]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-port.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ofp-port.c
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 {
40 namemap_init(&map->map);
41 }
42
43 void
44 ofputil_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
50 const char *
51 ofputil_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
61 ofp_port_t
62 ofputil_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
70 void
71 ofputil_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. */
82 enum ofperr
83 ofputil_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
96 static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1, 5);
97 VLOG_WARN_RL(&rll, "port %"PRIu32" is outside the supported "
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. */
110 ovs_be32
111 ofputil_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. */
148 bool
149 ofputil_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[OFP_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
227 const char *
228 ofputil_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". */
243 void
244 ofputil_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". */
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 {
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
289 /* ofputil_port_config */
290
291 static const char *
292 ofputil_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
309 void
310 ofputil_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
318 static const char *
319 ofputil_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
339 void
340 ofputil_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
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 {
387 uint32_t ofp10 = ntohl(ofp10_);
388 return (ofp10 & 0x7f) | ((ofp10 & 0xf80) << 4);
389 }
390
391 static ovs_be32
392 netdev_port_features_to_ofp10(enum netdev_features features)
393 {
394 return htonl((features & 0x7f) | ((features & 0xf800) >> 4));
395 }
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 {
417 return ntohl(ofp11) & 0xffff;
418 }
419
420 static ovs_be32
421 netdev_port_features_to_ofp11(enum netdev_features features)
422 {
423 return htonl(features & 0xffff);
424 }
425
426 static enum ofperr
427 ofputil_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
448 static enum ofperr
449 ofputil_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
475 static enum ofperr
476 parse_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
496 static enum ofperr
497 ofputil_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
529 static enum ofperr
530 ofputil_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
556 static void
557 ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp,
558 struct ofp10_phy_port *opp)
559 {
560 memset(opp, 0, sizeof *opp);
561
562 opp->port_no = htons(ofp_to_u16(pp->port_no));
563 opp->hw_addr = pp->hw_addr;
564 ovs_strlcpy_arrays(opp->name, pp->name);
565
566 opp->config = htonl(pp->config & OFPPC10_ALL);
567 opp->state = htonl(pp->state & OFPPS10_ALL);
568
569 opp->curr = netdev_port_features_to_ofp10(pp->curr);
570 opp->advertised = netdev_port_features_to_ofp10(pp->advertised);
571 opp->supported = netdev_port_features_to_ofp10(pp->supported);
572 opp->peer = netdev_port_features_to_ofp10(pp->peer);
573 }
574
575 static void
576 ofputil_encode_ofp11_port(const struct ofputil_phy_port *pp,
577 struct ofp11_port *op)
578 {
579 memset(op, 0, sizeof *op);
580
581 op->port_no = ofputil_port_to_ofp11(pp->port_no);
582 op->hw_addr = pp->hw_addr;
583 ovs_strlcpy_arrays(op->name, pp->name);
584
585 op->config = htonl(pp->config & OFPPC11_ALL);
586 op->state = htonl(pp->state & OFPPS11_ALL);
587
588 op->curr = netdev_port_features_to_ofp11(pp->curr);
589 op->advertised = netdev_port_features_to_ofp11(pp->advertised);
590 op->supported = netdev_port_features_to_ofp11(pp->supported);
591 op->peer = netdev_port_features_to_ofp11(pp->peer);
592
593 op->curr_speed = htonl(pp->curr_speed);
594 op->max_speed = htonl(pp->max_speed);
595 }
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 {
602 eth->curr = netdev_port_features_to_ofp11(pp->curr);
603 eth->advertised = netdev_port_features_to_ofp11(pp->advertised);
604 eth->supported = netdev_port_features_to_ofp11(pp->supported);
605 eth->peer = netdev_port_features_to_ofp11(pp->peer);
606 eth->curr_speed = htonl(pp->curr_speed);
607 eth->max_speed = htonl(pp->max_speed);
608 }
609
610 static void
611 ofputil_put_ofp14_port(const struct ofputil_phy_port *pp, struct ofpbuf *b)
612 {
613 struct ofp14_port *op;
614 struct ofp14_port_desc_prop_ethernet *eth;
615
616 ofpbuf_prealloc_tailroom(b, sizeof *op + sizeof *eth);
617
618 op = ofpbuf_put_zeros(b, sizeof *op);
619 op->port_no = ofputil_port_to_ofp11(pp->port_no);
620 op->length = htons(sizeof *op + sizeof *eth);
621 op->hw_addr = pp->hw_addr;
622 ovs_strlcpy_arrays(op->name, pp->name);
623 op->config = htonl(pp->config & OFPPC11_ALL);
624 op->state = htonl(pp->state & OFPPS11_ALL);
625
626 eth = ofpprop_put_zeros(b, OFPPDPT14_ETHERNET, sizeof *eth);
627 ofputil_encode_ofp14_port_ethernet_prop(pp, eth);
628 }
629
630 void
631 ofputil_put_phy_port(enum ofp_version ofp_version,
632 const struct ofputil_phy_port *pp, struct ofpbuf *b)
633 {
634 switch (ofp_version) {
635 case OFP10_VERSION: {
636 struct ofp10_phy_port *opp = ofpbuf_put_uninit(b, sizeof *opp);
637 ofputil_encode_ofp10_phy_port(pp, opp);
638 break;
639 }
640
641 case OFP11_VERSION:
642 case OFP12_VERSION:
643 case OFP13_VERSION: {
644 struct ofp11_port *op = ofpbuf_put_uninit(b, sizeof *op);
645 ofputil_encode_ofp11_port(pp, op);
646 break;
647 }
648
649 case OFP14_VERSION:
650 case OFP15_VERSION:
651 ofputil_put_ofp14_port(pp, b);
652 break;
653
654 default:
655 OVS_NOT_REACHED();
656 }
657 }
658
659 enum ofperr
660 ofputil_decode_port_desc_stats_request(const struct ofp_header *request,
661 ofp_port_t *port)
662 {
663 struct ofpbuf b = ofpbuf_const_initializer(request,
664 ntohs(request->length));
665 enum ofpraw raw = ofpraw_pull_assert(&b);
666 if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) {
667 *port = OFPP_ANY;
668 return 0;
669 } else if (raw == OFPRAW_OFPST15_PORT_DESC_REQUEST) {
670 ovs_be32 *ofp11_port;
671
672 ofp11_port = ofpbuf_pull(&b, sizeof *ofp11_port);
673 return ofputil_port_from_ofp11(*ofp11_port, port);
674 } else {
675 OVS_NOT_REACHED();
676 }
677 }
678
679 struct ofpbuf *
680 ofputil_encode_port_desc_stats_request(enum ofp_version ofp_version,
681 ofp_port_t port)
682 {
683 struct ofpbuf *request;
684
685 switch (ofp_version) {
686 case OFP10_VERSION:
687 case OFP11_VERSION:
688 case OFP12_VERSION:
689 case OFP13_VERSION:
690 case OFP14_VERSION:
691 request = ofpraw_alloc(OFPRAW_OFPST10_PORT_DESC_REQUEST,
692 ofp_version, 0);
693 break;
694 case OFP15_VERSION: {
695 struct ofp15_port_desc_request *req;
696 request = ofpraw_alloc(OFPRAW_OFPST15_PORT_DESC_REQUEST,
697 ofp_version, 0);
698 req = ofpbuf_put_zeros(request, sizeof *req);
699 req->port_no = ofputil_port_to_ofp11(port);
700 break;
701 }
702 default:
703 OVS_NOT_REACHED();
704 }
705
706 return request;
707 }
708
709 void
710 ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
711 struct ovs_list *replies)
712 {
713 struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
714 size_t start_ofs = reply->size;
715
716 ofputil_put_phy_port(ofpmp_version(replies), pp, reply);
717 ofpmp_postappend(replies, start_ofs);
718 }
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 {
729 memset(pp, 0, sizeof *pp);
730
731 switch (ofp_version) {
732 case OFP10_VERSION: {
733 const struct ofp10_phy_port *opp = ofpbuf_try_pull(b, sizeof *opp);
734 return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
735 }
736 case OFP11_VERSION:
737 case OFP12_VERSION:
738 case OFP13_VERSION: {
739 const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
740 return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
741 }
742 case OFP14_VERSION:
743 case OFP15_VERSION:
744 return b->size ? ofputil_pull_ofp14_port(pp, b) : EOF;
745 default:
746 OVS_NOT_REACHED();
747 }
748 }
749
750 void
751 ofputil_phy_port_format(struct ds *s, const struct ofputil_phy_port *port)
752 {
753 char name[sizeof port->name];
754 int j;
755
756 memcpy(name, port->name, sizeof name);
757 for (j = 0; j < sizeof name - 1; j++) {
758 if (!isprint((unsigned char) name[j])) {
759 break;
760 }
761 }
762 name[j] = '\0';
763
764 ds_put_char(s, ' ');
765 ofputil_format_port(port->port_no, NULL, s);
766 ds_put_format(s, "(%s): addr:"ETH_ADDR_FMT"\n",
767 name, ETH_ADDR_ARGS(port->hw_addr));
768
769 ds_put_cstr(s, " config: ");
770 ofputil_port_config_format(s, port->config);
771
772 ds_put_cstr(s, " state: ");
773 ofputil_port_state_format(s, port->state);
774
775 if (port->curr) {
776 ds_put_format(s, " current: ");
777 netdev_features_format(s, port->curr);
778 }
779 if (port->advertised) {
780 ds_put_format(s, " advertised: ");
781 netdev_features_format(s, port->advertised);
782 }
783 if (port->supported) {
784 ds_put_format(s, " supported: ");
785 netdev_features_format(s, port->supported);
786 }
787 if (port->peer) {
788 ds_put_format(s, " peer: ");
789 netdev_features_format(s, port->peer);
790 }
791 ds_put_format(s, " speed: %"PRIu32" Mbps now, "
792 "%"PRIu32" Mbps max\n",
793 port->curr_speed / UINT32_C(1000),
794 port->max_speed / UINT32_C(1000));
795 }
796
797 /* qsort comparison function. */
798 static int
799 compare_ports(const void *a_, const void *b_)
800 {
801 const struct ofputil_phy_port *a = a_;
802 const struct ofputil_phy_port *b = b_;
803 uint16_t ap = ofp_to_u16(a->port_no);
804 uint16_t bp = ofp_to_u16(b->port_no);
805
806 return ap < bp ? -1 : ap > bp;
807 }
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 {
815 struct ofputil_phy_port *ports;
816 size_t allocated_ports, n_ports;
817 int retval;
818 size_t i;
819
820 ports = NULL;
821 allocated_ports = 0;
822 for (n_ports = 0; ; n_ports++) {
823 if (n_ports >= allocated_ports) {
824 ports = x2nrealloc(ports, &allocated_ports, sizeof *ports);
825 }
826
827 retval = ofputil_pull_phy_port(ofp_version, b, &ports[n_ports]);
828 if (retval) {
829 break;
830 }
831 }
832
833 qsort(ports, n_ports, sizeof *ports, compare_ports);
834 for (i = 0; i < n_ports; i++) {
835 ofputil_phy_port_format(string, &ports[i]);
836 }
837 free(ports);
838
839 return retval != EOF ? retval : 0;
840 }
841 \f
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 {
850 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
851 ofpraw_pull_assert(&b);
852
853 const struct ofp_port_status *ops = ofpbuf_pull(&b, sizeof *ops);
854 if (ops->reason != OFPPR_ADD &&
855 ops->reason != OFPPR_DELETE &&
856 ops->reason != OFPPR_MODIFY) {
857 return OFPERR_NXBRC_BAD_REASON;
858 }
859 ps->reason = ops->reason;
860
861 int retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
862 ovs_assert(retval != EOF);
863 return retval;
864 }
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 {
873 struct ofp_port_status *ops;
874 struct ofpbuf *b;
875 enum ofp_version version;
876 enum ofpraw raw;
877
878 version = ofputil_protocol_to_ofp_version(protocol);
879 switch (version) {
880 case OFP10_VERSION:
881 raw = OFPRAW_OFPT10_PORT_STATUS;
882 break;
883
884 case OFP11_VERSION:
885 case OFP12_VERSION:
886 case OFP13_VERSION:
887 raw = OFPRAW_OFPT11_PORT_STATUS;
888 break;
889
890 case OFP14_VERSION:
891 case OFP15_VERSION:
892 raw = OFPRAW_OFPT14_PORT_STATUS;
893 break;
894
895 default:
896 OVS_NOT_REACHED();
897 }
898
899 b = ofpraw_alloc_xid(raw, version, htonl(0), 0);
900 ops = ofpbuf_put_zeros(b, sizeof *ops);
901 ops->reason = ps->reason;
902 ofputil_put_phy_port(version, &ps->desc, b);
903 ofpmsg_update_length(b);
904 return b;
905 }
906
907 void
908 ofputil_port_status_format(struct ds *s,
909 const struct ofputil_port_status *ps)
910 {
911 if (ps->reason == OFPPR_ADD) {
912 ds_put_format(s, " ADD:");
913 } else if (ps->reason == OFPPR_DELETE) {
914 ds_put_format(s, " DEL:");
915 } else if (ps->reason == OFPPR_MODIFY) {
916 ds_put_format(s, " MOD:");
917 }
918
919 ofputil_phy_port_format(s, &ps->desc);
920 }
921 \f
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 {
928 ovs_be32 advertise;
929 enum ofperr error;
930
931 error = ofpprop_parse_be32(property, &advertise);
932 if (!error) {
933 pm->advertise = netdev_port_features_from_ofp11(advertise);
934 }
935 return error;
936 }
937
938 static enum ofperr
939 ofputil_decode_ofp10_port_mod(const struct ofp10_port_mod *opm,
940 struct ofputil_port_mod *pm)
941 {
942 pm->port_no = u16_to_ofp(ntohs(opm->port_no));
943 pm->hw_addr = opm->hw_addr;
944 pm->config = ntohl(opm->config) & OFPPC10_ALL;
945 pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
946 pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
947 return 0;
948 }
949
950 static enum ofperr
951 ofputil_decode_ofp11_port_mod(const struct ofp11_port_mod *opm,
952 struct ofputil_port_mod *pm)
953 {
954 enum ofperr error;
955
956 error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
957 if (error) {
958 return error;
959 }
960
961 pm->hw_addr = opm->hw_addr;
962 pm->config = ntohl(opm->config) & OFPPC11_ALL;
963 pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
964 pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
965
966 return 0;
967 }
968
969 static enum ofperr
970 ofputil_decode_ofp14_port_mod_properties(struct ofpbuf *b, bool loose,
971 struct ofputil_port_mod *pm)
972 {
973 while (b->size > 0) {
974 struct ofpbuf property;
975 enum ofperr error;
976 uint64_t type;
977
978 error = ofpprop_pull(b, &property, &type);
979 if (error) {
980 return error;
981 }
982
983 switch (type) {
984 case OFPPMPT14_ETHERNET:
985 error = parse_port_mod_ethernet_property(&property, pm);
986 break;
987
988 default:
989 error = OFPPROP_UNKNOWN(loose, "port_mod", type);
990 break;
991 }
992
993 if (error) {
994 return error;
995 }
996 }
997 return 0;
998 }
999
1000 static enum ofperr
1001 ofputil_decode_ofp14_port_mod(struct ofpbuf *b, bool loose,
1002 struct ofputil_port_mod *pm)
1003 {
1004 const struct ofp14_port_mod *opm = ofpbuf_pull(b, sizeof *opm);
1005 enum ofperr error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
1006 if (error) {
1007 return error;
1008 }
1009
1010 pm->hw_addr = opm->hw_addr;
1011 pm->config = ntohl(opm->config) & OFPPC11_ALL;
1012 pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
1013
1014 return ofputil_decode_ofp14_port_mod_properties(b, loose, pm);
1015 }
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 {
1023 memset(pm, 0, sizeof *pm);
1024
1025 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1026 enum ofpraw raw = ofpraw_pull_assert(&b);
1027
1028 enum ofperr error;
1029 if (raw == OFPRAW_OFPT10_PORT_MOD) {
1030 error = ofputil_decode_ofp10_port_mod(b.data, pm);
1031 } else if (raw == OFPRAW_OFPT11_PORT_MOD) {
1032 error = ofputil_decode_ofp11_port_mod(b.data, pm);
1033 } else if (raw == OFPRAW_OFPT14_PORT_MOD) {
1034 error = ofputil_decode_ofp14_port_mod(&b, loose, pm);
1035 } else {
1036 error = OFPERR_OFPBRC_BAD_TYPE;
1037 }
1038
1039 pm->config &= pm->mask;
1040 return error;
1041 }
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 {
1050 enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
1051 struct ofpbuf *b;
1052
1053 switch (ofp_version) {
1054 case OFP10_VERSION: {
1055 struct ofp10_port_mod *opm;
1056
1057 b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
1058 opm = ofpbuf_put_zeros(b, sizeof *opm);
1059 opm->port_no = htons(ofp_to_u16(pm->port_no));
1060 opm->hw_addr = pm->hw_addr;
1061 opm->config = htonl(pm->config & OFPPC10_ALL);
1062 opm->mask = htonl(pm->mask & OFPPC10_ALL);
1063 opm->advertise = netdev_port_features_to_ofp10(pm->advertise);
1064 break;
1065 }
1066
1067 case OFP11_VERSION:
1068 case OFP12_VERSION:
1069 case OFP13_VERSION: {
1070 struct ofp11_port_mod *opm;
1071
1072 b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
1073 opm = ofpbuf_put_zeros(b, sizeof *opm);
1074 opm->port_no = ofputil_port_to_ofp11(pm->port_no);
1075 opm->hw_addr = pm->hw_addr;
1076 opm->config = htonl(pm->config & OFPPC11_ALL);
1077 opm->mask = htonl(pm->mask & OFPPC11_ALL);
1078 opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
1079 break;
1080 }
1081 case OFP14_VERSION:
1082 case OFP15_VERSION: {
1083 struct ofp14_port_mod *opm;
1084
1085 b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, 0);
1086 opm = ofpbuf_put_zeros(b, sizeof *opm);
1087 opm->port_no = ofputil_port_to_ofp11(pm->port_no);
1088 opm->hw_addr = pm->hw_addr;
1089 opm->config = htonl(pm->config & OFPPC11_ALL);
1090 opm->mask = htonl(pm->mask & OFPPC11_ALL);
1091
1092 if (pm->advertise) {
1093 ofpprop_put_be32(b, OFPPMPT14_ETHERNET,
1094 netdev_port_features_to_ofp11(pm->advertise));
1095 }
1096 break;
1097 }
1098 default:
1099 OVS_NOT_REACHED();
1100 }
1101
1102 return b;
1103 }
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 {
1109 ds_put_cstr(s, " port: ");
1110 ofputil_format_port(pm->port_no, port_map, s);
1111 ds_put_format(s, ": addr:"ETH_ADDR_FMT"\n",
1112 ETH_ADDR_ARGS(pm->hw_addr));
1113
1114 ds_put_cstr(s, " config: ");
1115 ofputil_port_config_format(s, pm->config);
1116
1117 ds_put_cstr(s, " mask: ");
1118 ofputil_port_config_format(s, pm->mask);
1119
1120 ds_put_cstr(s, " advertise: ");
1121 if (pm->advertise) {
1122 netdev_features_format(s, pm->advertise);
1123 } else {
1124 ds_put_cstr(s, "UNCHANGED\n");
1125 }
1126 }
1127 \f
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 {
1135 struct ofpbuf *request;
1136
1137 switch (ofp_version) {
1138 case OFP10_VERSION: {
1139 struct ofp10_port_stats_request *req;
1140 request = ofpraw_alloc(OFPRAW_OFPST10_PORT_REQUEST, ofp_version, 0);
1141 req = ofpbuf_put_zeros(request, sizeof *req);
1142 req->port_no = htons(ofp_to_u16(port));
1143 break;
1144 }
1145 case OFP11_VERSION:
1146 case OFP12_VERSION:
1147 case OFP13_VERSION:
1148 case OFP14_VERSION:
1149 case OFP15_VERSION: {
1150 struct ofp11_port_stats_request *req;
1151 request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
1152 req = ofpbuf_put_zeros(request, sizeof *req);
1153 req->port_no = ofputil_port_to_ofp11(port);
1154 break;
1155 }
1156 default:
1157 OVS_NOT_REACHED();
1158 }
1159
1160 return request;
1161 }
1162
1163 static void
1164 ofputil_port_stats_to_ofp10(const struct ofputil_port_stats *ops,
1165 struct ofp10_port_stats *ps10)
1166 {
1167 ps10->port_no = htons(ofp_to_u16(ops->port_no));
1168 memset(ps10->pad, 0, sizeof ps10->pad);
1169 put_32aligned_be64(&ps10->rx_packets, htonll(ops->stats.rx_packets));
1170 put_32aligned_be64(&ps10->tx_packets, htonll(ops->stats.tx_packets));
1171 put_32aligned_be64(&ps10->rx_bytes, htonll(ops->stats.rx_bytes));
1172 put_32aligned_be64(&ps10->tx_bytes, htonll(ops->stats.tx_bytes));
1173 put_32aligned_be64(&ps10->rx_dropped, htonll(ops->stats.rx_dropped));
1174 put_32aligned_be64(&ps10->tx_dropped, htonll(ops->stats.tx_dropped));
1175 put_32aligned_be64(&ps10->rx_errors, htonll(ops->stats.rx_errors));
1176 put_32aligned_be64(&ps10->tx_errors, htonll(ops->stats.tx_errors));
1177 put_32aligned_be64(&ps10->rx_frame_err,
1178 htonll(ops->stats.rx_frame_errors));
1179 put_32aligned_be64(&ps10->rx_over_err, htonll(ops->stats.rx_over_errors));
1180 put_32aligned_be64(&ps10->rx_crc_err, htonll(ops->stats.rx_crc_errors));
1181 put_32aligned_be64(&ps10->collisions, htonll(ops->stats.collisions));
1182 }
1183
1184 static void
1185 ofputil_port_stats_to_ofp11(const struct ofputil_port_stats *ops,
1186 struct ofp11_port_stats *ps11)
1187 {
1188 ps11->port_no = ofputil_port_to_ofp11(ops->port_no);
1189 memset(ps11->pad, 0, sizeof ps11->pad);
1190 ps11->rx_packets = htonll(ops->stats.rx_packets);
1191 ps11->tx_packets = htonll(ops->stats.tx_packets);
1192 ps11->rx_bytes = htonll(ops->stats.rx_bytes);
1193 ps11->tx_bytes = htonll(ops->stats.tx_bytes);
1194 ps11->rx_dropped = htonll(ops->stats.rx_dropped);
1195 ps11->tx_dropped = htonll(ops->stats.tx_dropped);
1196 ps11->rx_errors = htonll(ops->stats.rx_errors);
1197 ps11->tx_errors = htonll(ops->stats.tx_errors);
1198 ps11->rx_frame_err = htonll(ops->stats.rx_frame_errors);
1199 ps11->rx_over_err = htonll(ops->stats.rx_over_errors);
1200 ps11->rx_crc_err = htonll(ops->stats.rx_crc_errors);
1201 ps11->collisions = htonll(ops->stats.collisions);
1202 }
1203
1204 static void
1205 ofputil_port_stats_to_ofp13(const struct ofputil_port_stats *ops,
1206 struct ofp13_port_stats *ps13)
1207 {
1208 ofputil_port_stats_to_ofp11(ops, &ps13->ps);
1209 ps13->duration_sec = htonl(ops->duration_sec);
1210 ps13->duration_nsec = htonl(ops->duration_nsec);
1211 }
1212
1213 static void
1214 ofputil_append_ofp14_port_stats(const struct ofputil_port_stats *ops,
1215 struct ovs_list *replies)
1216 {
1217 struct ofp14_port_stats_prop_ethernet *eth;
1218 struct intel_port_stats_rfc2819 *stats_rfc2819;
1219 struct intel_port_custom_stats *stats_custom;
1220 struct ofp14_port_stats *ps14;
1221 struct ofpbuf *reply;
1222 uint16_t i;
1223 ovs_be64 counter_value;
1224 size_t custom_stats_start, start_ofs;
1225
1226 reply = ofpbuf_from_list(ovs_list_back(replies));
1227 start_ofs = reply->size;
1228
1229 ps14 = ofpbuf_put_uninit(reply, sizeof *ps14);
1230
1231 memset(ps14->pad, 0, sizeof ps14->pad);
1232 ps14->port_no = ofputil_port_to_ofp11(ops->port_no);
1233 ps14->duration_sec = htonl(ops->duration_sec);
1234 ps14->duration_nsec = htonl(ops->duration_nsec);
1235 ps14->rx_packets = htonll(ops->stats.rx_packets);
1236 ps14->tx_packets = htonll(ops->stats.tx_packets);
1237 ps14->rx_bytes = htonll(ops->stats.rx_bytes);
1238 ps14->tx_bytes = htonll(ops->stats.tx_bytes);
1239 ps14->rx_dropped = htonll(ops->stats.rx_dropped);
1240 ps14->tx_dropped = htonll(ops->stats.tx_dropped);
1241 ps14->rx_errors = htonll(ops->stats.rx_errors);
1242 ps14->tx_errors = htonll(ops->stats.tx_errors);
1243
1244 eth = ofpprop_put_zeros(reply, OFPPSPT14_ETHERNET, sizeof *eth);
1245 eth->rx_frame_err = htonll(ops->stats.rx_frame_errors);
1246 eth->rx_over_err = htonll(ops->stats.rx_over_errors);
1247 eth->rx_crc_err = htonll(ops->stats.rx_crc_errors);
1248 eth->collisions = htonll(ops->stats.collisions);
1249
1250 uint64_t prop_type_stats = OFPPROP_EXP(INTEL_VENDOR_ID,
1251 INTEL_PORT_STATS_RFC2819);
1252
1253 stats_rfc2819 = ofpprop_put_zeros(reply, prop_type_stats,
1254 sizeof *stats_rfc2819);
1255
1256 memset(stats_rfc2819->pad, 0, sizeof stats_rfc2819->pad);
1257 stats_rfc2819->rx_1_to_64_packets = htonll(ops->stats.rx_1_to_64_packets);
1258 stats_rfc2819->rx_65_to_127_packets =
1259 htonll(ops->stats.rx_65_to_127_packets);
1260 stats_rfc2819->rx_128_to_255_packets =
1261 htonll(ops->stats.rx_128_to_255_packets);
1262 stats_rfc2819->rx_256_to_511_packets =
1263 htonll(ops->stats.rx_256_to_511_packets);
1264 stats_rfc2819->rx_512_to_1023_packets =
1265 htonll(ops->stats.rx_512_to_1023_packets);
1266 stats_rfc2819->rx_1024_to_1522_packets =
1267 htonll(ops->stats.rx_1024_to_1522_packets);
1268 stats_rfc2819->rx_1523_to_max_packets =
1269 htonll(ops->stats.rx_1523_to_max_packets);
1270
1271 stats_rfc2819->tx_1_to_64_packets = htonll(ops->stats.tx_1_to_64_packets);
1272 stats_rfc2819->tx_65_to_127_packets =
1273 htonll(ops->stats.tx_65_to_127_packets);
1274 stats_rfc2819->tx_128_to_255_packets =
1275 htonll(ops->stats.tx_128_to_255_packets);
1276 stats_rfc2819->tx_256_to_511_packets =
1277 htonll(ops->stats.tx_256_to_511_packets);
1278 stats_rfc2819->tx_512_to_1023_packets =
1279 htonll(ops->stats.tx_512_to_1023_packets);
1280 stats_rfc2819->tx_1024_to_1522_packets =
1281 htonll(ops->stats.tx_1024_to_1522_packets);
1282 stats_rfc2819->tx_1523_to_max_packets =
1283 htonll(ops->stats.tx_1523_to_max_packets);
1284
1285 stats_rfc2819->tx_multicast_packets =
1286 htonll(ops->stats.tx_multicast_packets);
1287 stats_rfc2819->rx_broadcast_packets =
1288 htonll(ops->stats.rx_broadcast_packets);
1289 stats_rfc2819->tx_broadcast_packets =
1290 htonll(ops->stats.tx_broadcast_packets);
1291 stats_rfc2819->rx_undersized_errors =
1292 htonll(ops->stats.rx_undersized_errors);
1293 stats_rfc2819->rx_oversize_errors =
1294 htonll(ops->stats.rx_oversize_errors);
1295 stats_rfc2819->rx_fragmented_errors =
1296 htonll(ops->stats.rx_fragmented_errors);
1297 stats_rfc2819->rx_jabber_errors =
1298 htonll(ops->stats.rx_jabber_errors);
1299
1300 if (ops->custom_stats.counters && ops->custom_stats.size) {
1301 custom_stats_start = reply->size;
1302
1303 uint64_t prop_type_custom = OFPPROP_EXP(INTEL_VENDOR_ID,
1304 INTEL_PORT_STATS_CUSTOM);
1305
1306 stats_custom = ofpprop_put_zeros(reply, prop_type_custom,
1307 sizeof *stats_custom);
1308
1309 stats_custom->stats_array_size = htons(ops->custom_stats.size);
1310
1311 for (i = 0; i < ops->custom_stats.size; i++) {
1312 uint8_t counter_size = strlen(ops->custom_stats.counters[i].name);
1313 /* Counter name size */
1314 ofpbuf_put(reply, &counter_size, sizeof(counter_size));
1315 /* Counter name */
1316 ofpbuf_put(reply, ops->custom_stats.counters[i].name,
1317 counter_size);
1318 /* Counter value */
1319 counter_value = htonll(ops->custom_stats.counters[i].value);
1320 ofpbuf_put(reply, &counter_value,
1321 sizeof(ops->custom_stats.counters[i].value));
1322 }
1323
1324 ofpprop_end(reply, custom_stats_start);
1325 }
1326
1327 ps14 = ofpbuf_at_assert(reply, start_ofs, sizeof *ps14);
1328 ps14->length = htons(reply->size - start_ofs);
1329
1330 ofpmp_postappend(replies, start_ofs);
1331 }
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 {
1338 switch (ofpmp_version(replies)) {
1339 case OFP13_VERSION: {
1340 struct ofp13_port_stats *reply = ofpmp_append(replies, sizeof *reply);
1341 ofputil_port_stats_to_ofp13(ops, reply);
1342 break;
1343 }
1344 case OFP12_VERSION:
1345 case OFP11_VERSION: {
1346 struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
1347 ofputil_port_stats_to_ofp11(ops, reply);
1348 break;
1349 }
1350
1351 case OFP10_VERSION: {
1352 struct ofp10_port_stats *reply = ofpmp_append(replies, sizeof *reply);
1353 ofputil_port_stats_to_ofp10(ops, reply);
1354 break;
1355 }
1356
1357 case OFP14_VERSION:
1358 case OFP15_VERSION:
1359 ofputil_append_ofp14_port_stats(ops, replies);
1360 break;
1361
1362 default:
1363 OVS_NOT_REACHED();
1364 }
1365 }
1366
1367 static enum ofperr
1368 ofputil_port_stats_from_ofp10(struct ofputil_port_stats *ops,
1369 const struct ofp10_port_stats *ps10)
1370 {
1371
1372 ops->port_no = u16_to_ofp(ntohs(ps10->port_no));
1373 ops->stats.rx_packets = ntohll(get_32aligned_be64(&ps10->rx_packets));
1374 ops->stats.tx_packets = ntohll(get_32aligned_be64(&ps10->tx_packets));
1375 ops->stats.rx_bytes = ntohll(get_32aligned_be64(&ps10->rx_bytes));
1376 ops->stats.tx_bytes = ntohll(get_32aligned_be64(&ps10->tx_bytes));
1377 ops->stats.rx_dropped = ntohll(get_32aligned_be64(&ps10->rx_dropped));
1378 ops->stats.tx_dropped = ntohll(get_32aligned_be64(&ps10->tx_dropped));
1379 ops->stats.rx_errors = ntohll(get_32aligned_be64(&ps10->rx_errors));
1380 ops->stats.tx_errors = ntohll(get_32aligned_be64(&ps10->tx_errors));
1381 ops->stats.rx_frame_errors =
1382 ntohll(get_32aligned_be64(&ps10->rx_frame_err));
1383 ops->stats.rx_over_errors = ntohll(get_32aligned_be64(&ps10->rx_over_err));
1384 ops->stats.rx_crc_errors = ntohll(get_32aligned_be64(&ps10->rx_crc_err));
1385 ops->stats.collisions = ntohll(get_32aligned_be64(&ps10->collisions));
1386 ops->duration_sec = ops->duration_nsec = UINT32_MAX;
1387
1388 return 0;
1389 }
1390
1391 static enum ofperr
1392 ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
1393 const struct ofp11_port_stats *ps11)
1394 {
1395 enum ofperr error;
1396
1397 error = ofputil_port_from_ofp11(ps11->port_no, &ops->port_no);
1398 if (error) {
1399 return error;
1400 }
1401
1402 ops->stats.rx_packets = ntohll(ps11->rx_packets);
1403 ops->stats.tx_packets = ntohll(ps11->tx_packets);
1404 ops->stats.rx_bytes = ntohll(ps11->rx_bytes);
1405 ops->stats.tx_bytes = ntohll(ps11->tx_bytes);
1406 ops->stats.rx_dropped = ntohll(ps11->rx_dropped);
1407 ops->stats.tx_dropped = ntohll(ps11->tx_dropped);
1408 ops->stats.rx_errors = ntohll(ps11->rx_errors);
1409 ops->stats.tx_errors = ntohll(ps11->tx_errors);
1410 ops->stats.rx_frame_errors = ntohll(ps11->rx_frame_err);
1411 ops->stats.rx_over_errors = ntohll(ps11->rx_over_err);
1412 ops->stats.rx_crc_errors = ntohll(ps11->rx_crc_err);
1413 ops->stats.collisions = ntohll(ps11->collisions);
1414 ops->duration_sec = ops->duration_nsec = UINT32_MAX;
1415
1416 return 0;
1417 }
1418
1419 static enum ofperr
1420 ofputil_port_stats_from_ofp13(struct ofputil_port_stats *ops,
1421 const struct ofp13_port_stats *ps13)
1422 {
1423 enum ofperr error = ofputil_port_stats_from_ofp11(ops, &ps13->ps);
1424 if (!error) {
1425 ops->duration_sec = ntohl(ps13->duration_sec);
1426 ops->duration_nsec = ntohl(ps13->duration_nsec);
1427 }
1428 return error;
1429 }
1430
1431 static enum ofperr
1432 parse_ofp14_port_stats_ethernet_property(const struct ofpbuf *payload,
1433 struct ofputil_port_stats *ops)
1434 {
1435 const struct ofp14_port_stats_prop_ethernet *eth = payload->data;
1436
1437 if (payload->size != sizeof *eth) {
1438 return OFPERR_OFPBPC_BAD_LEN;
1439 }
1440
1441 ops->stats.rx_frame_errors = ntohll(eth->rx_frame_err);
1442 ops->stats.rx_over_errors = ntohll(eth->rx_over_err);
1443 ops->stats.rx_crc_errors = ntohll(eth->rx_crc_err);
1444 ops->stats.collisions = ntohll(eth->collisions);
1445
1446 return 0;
1447 }
1448
1449 static enum ofperr
1450 parse_intel_port_stats_rfc2819_property(const struct ofpbuf *payload,
1451 struct ofputil_port_stats *ops)
1452 {
1453 const struct intel_port_stats_rfc2819 *rfc2819 = payload->data;
1454
1455 if (payload->size != sizeof *rfc2819) {
1456 return OFPERR_OFPBPC_BAD_LEN;
1457 }
1458 ops->stats.rx_1_to_64_packets = ntohll(rfc2819->rx_1_to_64_packets);
1459 ops->stats.rx_65_to_127_packets = ntohll(rfc2819->rx_65_to_127_packets);
1460 ops->stats.rx_128_to_255_packets = ntohll(rfc2819->rx_128_to_255_packets);
1461 ops->stats.rx_256_to_511_packets = ntohll(rfc2819->rx_256_to_511_packets);
1462 ops->stats.rx_512_to_1023_packets =
1463 ntohll(rfc2819->rx_512_to_1023_packets);
1464 ops->stats.rx_1024_to_1522_packets =
1465 ntohll(rfc2819->rx_1024_to_1522_packets);
1466 ops->stats.rx_1523_to_max_packets =
1467 ntohll(rfc2819->rx_1523_to_max_packets);
1468
1469 ops->stats.tx_1_to_64_packets = ntohll(rfc2819->tx_1_to_64_packets);
1470 ops->stats.tx_65_to_127_packets = ntohll(rfc2819->tx_65_to_127_packets);
1471 ops->stats.tx_128_to_255_packets = ntohll(rfc2819->tx_128_to_255_packets);
1472 ops->stats.tx_256_to_511_packets = ntohll(rfc2819->tx_256_to_511_packets);
1473 ops->stats.tx_512_to_1023_packets =
1474 ntohll(rfc2819->tx_512_to_1023_packets);
1475 ops->stats.tx_1024_to_1522_packets =
1476 ntohll(rfc2819->tx_1024_to_1522_packets);
1477 ops->stats.tx_1523_to_max_packets =
1478 ntohll(rfc2819->tx_1523_to_max_packets);
1479
1480 ops->stats.tx_multicast_packets = ntohll(rfc2819->tx_multicast_packets);
1481 ops->stats.rx_broadcast_packets = ntohll(rfc2819->rx_broadcast_packets);
1482 ops->stats.tx_broadcast_packets = ntohll(rfc2819->tx_broadcast_packets);
1483 ops->stats.rx_undersized_errors = ntohll(rfc2819->rx_undersized_errors);
1484
1485 ops->stats.rx_oversize_errors = ntohll(rfc2819->rx_oversize_errors);
1486 ops->stats.rx_fragmented_errors = ntohll(rfc2819->rx_fragmented_errors);
1487 ops->stats.rx_jabber_errors = ntohll(rfc2819->rx_jabber_errors);
1488
1489 return 0;
1490 }
1491
1492 static enum ofperr
1493 parse_intel_port_custom_property(struct ofpbuf *payload,
1494 struct ofputil_port_stats *ops)
1495 {
1496 const struct intel_port_custom_stats *custom_stats
1497 = ofpbuf_try_pull(payload, sizeof *custom_stats);
1498 if (!custom_stats) {
1499 return OFPERR_OFPBPC_BAD_LEN;
1500 }
1501
1502 ops->custom_stats.size = ntohs(custom_stats->stats_array_size);
1503
1504 netdev_free_custom_stats_counters(&ops->custom_stats);
1505 ops->custom_stats.counters = xcalloc(ops->custom_stats.size,
1506 sizeof *ops->custom_stats.counters);
1507
1508 for (int i = 0; i < ops->custom_stats.size; i++) {
1509 struct netdev_custom_counter *c = &ops->custom_stats.counters[i];
1510
1511 /* Counter name. */
1512 uint8_t *name_len = ofpbuf_try_pull(payload, sizeof *name_len);
1513 char *name = name_len ? ofpbuf_try_pull(payload, *name_len) : NULL;
1514 if (!name_len || !name) {
1515 netdev_free_custom_stats_counters(&ops->custom_stats);
1516 return OFPERR_OFPBPC_BAD_LEN;
1517 }
1518
1519 size_t len = MIN(*name_len, sizeof c->name - 1);
1520 memcpy(c->name, name, len);
1521 c->name[len] = '\0';
1522
1523 /* Counter value. */
1524 ovs_be64 *value = ofpbuf_try_pull(payload, sizeof *value);
1525 if (!value) {
1526 netdev_free_custom_stats_counters(&ops->custom_stats);
1527 return OFPERR_OFPBPC_BAD_LEN;
1528 }
1529 c->value = ntohll(get_unaligned_be64(value));
1530 }
1531
1532 return 0;
1533 }
1534
1535 static enum ofperr
1536 ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops,
1537 struct ofpbuf *msg)
1538 {
1539 const struct ofp14_port_stats *ps14 = ofpbuf_try_pull(msg, sizeof *ps14);
1540 if (!ps14) {
1541 return OFPERR_OFPBRC_BAD_LEN;
1542 }
1543
1544 size_t len = ntohs(ps14->length);
1545 if (len < sizeof *ps14 || len - sizeof *ps14 > msg->size) {
1546 return OFPERR_OFPBRC_BAD_LEN;
1547 }
1548 len -= sizeof *ps14;
1549
1550 enum ofperr error = ofputil_port_from_ofp11(ps14->port_no, &ops->port_no);
1551 if (error) {
1552 return error;
1553 }
1554
1555 ops->duration_sec = ntohl(ps14->duration_sec);
1556 ops->duration_nsec = ntohl(ps14->duration_nsec);
1557 ops->stats.rx_packets = ntohll(ps14->rx_packets);
1558 ops->stats.tx_packets = ntohll(ps14->tx_packets);
1559 ops->stats.rx_bytes = ntohll(ps14->rx_bytes);
1560 ops->stats.tx_bytes = ntohll(ps14->tx_bytes);
1561 ops->stats.rx_dropped = ntohll(ps14->rx_dropped);
1562 ops->stats.tx_dropped = ntohll(ps14->tx_dropped);
1563 ops->stats.rx_errors = ntohll(ps14->rx_errors);
1564 ops->stats.tx_errors = ntohll(ps14->tx_errors);
1565
1566
1567 struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
1568 len);
1569 while (properties.size > 0) {
1570 struct ofpbuf payload;
1571 uint64_t type = 0;
1572
1573 error = ofpprop_pull(&properties, &payload, &type);
1574 if (error) {
1575 netdev_free_custom_stats_counters(&ops->custom_stats);
1576 return error;
1577 }
1578 switch (type) {
1579 case OFPPSPT14_ETHERNET:
1580 error = parse_ofp14_port_stats_ethernet_property(&payload, ops);
1581 break;
1582 case OFPPROP_EXP(INTEL_VENDOR_ID, INTEL_PORT_STATS_RFC2819):
1583 error = parse_intel_port_stats_rfc2819_property(&payload, ops);
1584 break;
1585 case OFPPROP_EXP(INTEL_VENDOR_ID, INTEL_PORT_STATS_CUSTOM):
1586 error = parse_intel_port_custom_property(&payload, ops);
1587 break;
1588 default:
1589 error = OFPPROP_UNKNOWN(true, "port stats", type);
1590 break;
1591 }
1592
1593 if (error) {
1594 netdev_free_custom_stats_counters(&ops->custom_stats);
1595 return error;
1596 }
1597 }
1598
1599 return 0;
1600 }
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 {
1607 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1608 ofpraw_pull_assert(&b);
1609
1610 for (size_t n = 0; ; n++) {
1611 struct ofputil_port_stats ps;
1612 if (ofputil_decode_port_stats(&ps, &b)) {
1613 return n;
1614 }
1615 netdev_free_custom_stats_counters(&ps.custom_stats);
1616 }
1617 }
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 {
1635 enum ofperr error;
1636 enum ofpraw raw;
1637
1638 memset(&(ps->stats), 0xFF, sizeof (ps->stats));
1639 memset(&(ps->custom_stats), 0, sizeof (ps->custom_stats));
1640
1641 error = (msg->header ? ofpraw_decode(&raw, msg->header)
1642 : ofpraw_pull(&raw, msg));
1643 if (error) {
1644 return error;
1645 }
1646
1647 if (!msg->size) {
1648 return EOF;
1649 } else if (raw == OFPRAW_OFPST14_PORT_REPLY) {
1650 return ofputil_pull_ofp14_port_stats(ps, msg);
1651 } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
1652 const struct ofp13_port_stats *ps13;
1653 ps13 = ofpbuf_try_pull(msg, sizeof *ps13);
1654 if (!ps13) {
1655 goto bad_len;
1656 }
1657 return ofputil_port_stats_from_ofp13(ps, ps13);
1658 } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
1659 const struct ofp11_port_stats *ps11;
1660
1661 ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
1662 if (!ps11) {
1663 goto bad_len;
1664 }
1665 return ofputil_port_stats_from_ofp11(ps, ps11);
1666 } else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
1667 const struct ofp10_port_stats *ps10;
1668
1669 ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
1670 if (!ps10) {
1671 goto bad_len;
1672 }
1673 return ofputil_port_stats_from_ofp10(ps, ps10);
1674 } else {
1675 OVS_NOT_REACHED();
1676 }
1677
1678 bad_len:
1679 VLOG_WARN_RL(&rl, "OFPST_PORT reply has %"PRIu32" leftover "
1680 "bytes at end", msg->size);
1681 return OFPERR_OFPBRC_BAD_LEN;
1682 }
1683
1684 static void
1685 print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
1686 {
1687 ds_put_cstr(string, leader);
1688 if (stat != UINT64_MAX) {
1689 ds_put_format(string, "%"PRIu64, stat);
1690 } else {
1691 ds_put_char(string, '?');
1692 }
1693 if (more) {
1694 ds_put_cstr(string, ", ");
1695 } else {
1696 ds_put_cstr(string, "\n");
1697 }
1698 }
1699
1700 static void
1701 print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
1702 {
1703 if (stat != UINT64_MAX) {
1704 ds_put_format(string, "%s%"PRIu64", ", leader, stat);
1705 }
1706 }
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 {
1713 ds_put_cstr(string, " port ");
1714 if (ofp_to_u16(ps->port_no) < 10) {
1715 ds_put_char(string, ' ');
1716 }
1717 ofputil_format_port(ps->port_no, port_map, string);
1718
1719 ds_put_cstr(string, ": rx ");
1720 print_port_stat(string, "pkts=", ps->stats.rx_packets, 1);
1721 print_port_stat(string, "bytes=", ps->stats.rx_bytes, 1);
1722 print_port_stat(string, "drop=", ps->stats.rx_dropped, 1);
1723 print_port_stat(string, "errs=", ps->stats.rx_errors, 1);
1724 print_port_stat(string, "frame=", ps->stats.rx_frame_errors, 1);
1725 print_port_stat(string, "over=", ps->stats.rx_over_errors, 1);
1726 print_port_stat(string, "crc=", ps->stats.rx_crc_errors, 0);
1727
1728 ds_put_cstr(string, " tx ");
1729 print_port_stat(string, "pkts=", ps->stats.tx_packets, 1);
1730 print_port_stat(string, "bytes=", ps->stats.tx_bytes, 1);
1731 print_port_stat(string, "drop=", ps->stats.tx_dropped, 1);
1732 print_port_stat(string, "errs=", ps->stats.tx_errors, 1);
1733 print_port_stat(string, "coll=", ps->stats.collisions, 0);
1734
1735 if (ps->duration_sec != UINT32_MAX) {
1736 ds_put_cstr(string, " duration=");
1737 ofp_print_duration(string, ps->duration_sec, ps->duration_nsec);
1738 ds_put_char(string, '\n');
1739 }
1740 struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
1741
1742 ds_init(&string_ext_stats);
1743
1744 print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1745 ps->stats.rx_1_to_64_packets);
1746 print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1747 ps->stats.rx_65_to_127_packets);
1748 print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1749 ps->stats.rx_128_to_255_packets);
1750 print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1751 ps->stats.rx_256_to_511_packets);
1752 print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1753 ps->stats.rx_512_to_1023_packets);
1754 print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1755 ps->stats.rx_1024_to_1522_packets);
1756 print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1757 ps->stats.rx_1523_to_max_packets);
1758 print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1759 ps->stats.rx_broadcast_packets);
1760 print_port_stat_cond(&string_ext_stats, "undersized_errors=",
1761 ps->stats.rx_undersized_errors);
1762 print_port_stat_cond(&string_ext_stats, "oversize_errors=",
1763 ps->stats.rx_oversize_errors);
1764 print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
1765 ps->stats.rx_fragmented_errors);
1766 print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
1767 ps->stats.rx_jabber_errors);
1768
1769 if (string_ext_stats.length != 0) {
1770 /* If at least one statistics counter is reported: */
1771 ds_put_cstr(string, " rx rfc2819 ");
1772 ds_put_buffer(string, string_ext_stats.string,
1773 string_ext_stats.length);
1774 ds_put_cstr(string, "\n");
1775 ds_destroy(&string_ext_stats);
1776 }
1777
1778 ds_init(&string_ext_stats);
1779
1780 print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1781 ps->stats.tx_1_to_64_packets);
1782 print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1783 ps->stats.tx_65_to_127_packets);
1784 print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1785 ps->stats.tx_128_to_255_packets);
1786 print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1787 ps->stats.tx_256_to_511_packets);
1788 print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1789 ps->stats.tx_512_to_1023_packets);
1790 print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1791 ps->stats.tx_1024_to_1522_packets);
1792 print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1793 ps->stats.tx_1523_to_max_packets);
1794 print_port_stat_cond(&string_ext_stats, "multicast_packets=",
1795 ps->stats.tx_multicast_packets);
1796 print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1797 ps->stats.tx_broadcast_packets);
1798
1799 if (string_ext_stats.length != 0) {
1800 /* If at least one statistics counter is reported: */
1801 ds_put_cstr(string, " tx rfc2819 ");
1802 ds_put_buffer(string, string_ext_stats.string,
1803 string_ext_stats.length);
1804 ds_put_cstr(string, "\n");
1805 ds_destroy(&string_ext_stats);
1806 }
1807
1808 if (ps->custom_stats.size) {
1809 ds_put_cstr(string, " CUSTOM Statistics");
1810 for (int i = 0; i < ps->custom_stats.size; i++) {
1811 /* 3 counters in the row */
1812 if (ps->custom_stats.counters[i].name[0]) {
1813 if (i % 3 == 0) {
1814 ds_put_cstr(string, "\n");
1815 ds_put_cstr(string, " ");
1816 } else {
1817 ds_put_char(string, ' ');
1818 }
1819 ds_put_format(string, "%s=%"PRIu64",",
1820 ps->custom_stats.counters[i].name,
1821 ps->custom_stats.counters[i].value);
1822 }
1823 }
1824 ds_put_cstr(string, "\n");
1825 }
1826 }
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 {
1836 switch ((enum ofp_version)request->version) {
1837 case OFP15_VERSION:
1838 case OFP14_VERSION:
1839 case OFP13_VERSION:
1840 case OFP12_VERSION:
1841 case OFP11_VERSION: {
1842 const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
1843 return ofputil_port_from_ofp11(psr11->port_no, ofp10_port);
1844 }
1845
1846 case OFP10_VERSION: {
1847 const struct ofp10_port_stats_request *psr10 = ofpmsg_body(request);
1848 *ofp10_port = u16_to_ofp(ntohs(psr10->port_no));
1849 return 0;
1850 }
1851
1852 default:
1853 OVS_NOT_REACHED();
1854 }
1855 }
1856