]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-queue.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ofp-queue.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-queue.h"
19 #include "byte-order.h"
20 #include "flow.h"
21 #include "openvswitch/ofp-msgs.h"
22 #include "openvswitch/ofp-print.h"
23 #include "openvswitch/ofp-port.h"
24 #include "openvswitch/ofp-prop.h"
25 #include "openvswitch/ofpbuf.h"
26 #include "openvswitch/vlog.h"
27 #include "util.h"
28
29 VLOG_DEFINE_THIS_MODULE(ofp_queue);
30
31 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
32
33 static void
34 ofp_print_queue_name(struct ds *string, uint32_t queue_id)
35 {
36 if (queue_id == OFPQ_ALL) {
37 ds_put_cstr(string, "ALL");
38 } else {
39 ds_put_format(string, "%"PRIu32, queue_id);
40 }
41 }
42 \f
43 /* OFPT_QUEUE_GET_CONFIG request and reply. */
44
45 /* Constructs and returns an OFPT_QUEUE_GET_CONFIG request for the specified
46 * 'port' and 'queue', suitable for OpenFlow version 'version'.
47 *
48 * 'queue' is honored only for OpenFlow 1.4 and later; older versions always
49 * request all queues. */
50 struct ofpbuf *
51 ofputil_encode_queue_get_config_request(enum ofp_version version,
52 ofp_port_t port,
53 uint32_t queue)
54 {
55 struct ofpbuf *request;
56
57 if (version == OFP10_VERSION) {
58 struct ofp10_queue_get_config_request *qgcr10;
59
60 request = ofpraw_alloc(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST,
61 version, 0);
62 qgcr10 = ofpbuf_put_zeros(request, sizeof *qgcr10);
63 qgcr10->port = htons(ofp_to_u16(port));
64 } else if (version < OFP14_VERSION) {
65 struct ofp11_queue_get_config_request *qgcr11;
66
67 request = ofpraw_alloc(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST,
68 version, 0);
69 qgcr11 = ofpbuf_put_zeros(request, sizeof *qgcr11);
70 qgcr11->port = ofputil_port_to_ofp11(port);
71 } else {
72 struct ofp14_queue_desc_request *qdr14;
73
74 request = ofpraw_alloc(OFPRAW_OFPST14_QUEUE_DESC_REQUEST,
75 version, 0);
76 qdr14 = ofpbuf_put_zeros(request, sizeof *qdr14);
77 qdr14->port = ofputil_port_to_ofp11(port);
78 qdr14->queue = htonl(queue);
79 }
80
81 return request;
82 }
83
84 /* Parses OFPT_QUEUE_GET_CONFIG request 'oh', storing the port specified by the
85 * request into '*port'. Returns 0 if successful, otherwise an OpenFlow error
86 * code. */
87 enum ofperr
88 ofputil_decode_queue_get_config_request(const struct ofp_header *oh,
89 ofp_port_t *port, uint32_t *queue)
90 {
91 const struct ofp10_queue_get_config_request *qgcr10;
92 const struct ofp11_queue_get_config_request *qgcr11;
93 const struct ofp14_queue_desc_request *qdr14;
94 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
95 enum ofpraw raw = ofpraw_pull_assert(&b);
96
97 switch ((int) raw) {
98 case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
99 qgcr10 = b.data;
100 *port = u16_to_ofp(ntohs(qgcr10->port));
101 *queue = OFPQ_ALL;
102 break;
103
104 case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
105 qgcr11 = b.data;
106 *queue = OFPQ_ALL;
107 enum ofperr error = ofputil_port_from_ofp11(qgcr11->port, port);
108 if (error || *port == OFPP_ANY) {
109 return error;
110 }
111 break;
112
113 case OFPRAW_OFPST14_QUEUE_DESC_REQUEST:
114 qdr14 = b.data;
115 *queue = ntohl(qdr14->queue);
116 return ofputil_port_from_ofp11(qdr14->port, port);
117
118 default:
119 OVS_NOT_REACHED();
120 }
121
122 return (ofp_to_u16(*port) < ofp_to_u16(OFPP_MAX)
123 ? 0
124 : OFPERR_OFPQOFC_BAD_PORT);
125 }
126
127 enum ofperr
128 ofputil_queue_get_config_request_format(
129 struct ds *string, const struct ofp_header *oh,
130 const struct ofputil_port_map *port_map)
131 {
132 enum ofperr error;
133 ofp_port_t port;
134 uint32_t queue;
135
136 error = ofputil_decode_queue_get_config_request(oh, &port, &queue);
137 if (error) {
138 return error;
139 }
140
141 ds_put_cstr(string, " port=");
142 ofputil_format_port(port, port_map, string);
143
144 if (queue != OFPQ_ALL) {
145 ds_put_cstr(string, " queue=");
146 ofp_print_queue_name(string, queue);
147 }
148
149 return 0;
150 }
151
152 /* Constructs and returns the beginning of a reply to
153 * OFPT_QUEUE_GET_CONFIG_REQUEST or OFPMP_QUEUE_DESC request 'oh'. The caller
154 * may append information about individual queues with
155 * ofputil_append_queue_get_config_reply(). */
156 void
157 ofputil_start_queue_get_config_reply(const struct ofp_header *request,
158 struct ovs_list *replies)
159 {
160 struct ofpbuf *reply;
161 ofp_port_t port;
162 uint32_t queue;
163
164 ovs_assert(!ofputil_decode_queue_get_config_request(request, &port,
165 &queue));
166
167 enum ofpraw raw = ofpraw_decode_assert(request);
168 switch ((int) raw) {
169 case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
170 reply = ofpraw_alloc_reply(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY,
171 request, 0);
172 struct ofp10_queue_get_config_reply *qgcr10
173 = ofpbuf_put_zeros(reply, sizeof *qgcr10);
174 qgcr10->port = htons(ofp_to_u16(port));
175 break;
176
177 case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
178 reply = ofpraw_alloc_reply(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY,
179 request, 0);
180 struct ofp11_queue_get_config_reply *qgcr11
181 = ofpbuf_put_zeros(reply, sizeof *qgcr11);
182 qgcr11->port = ofputil_port_to_ofp11(port);
183 break;
184
185 case OFPRAW_OFPST14_QUEUE_DESC_REQUEST:
186 reply = ofpraw_alloc_stats_reply(request, 0);
187 break;
188
189 default:
190 OVS_NOT_REACHED();
191 }
192
193 ovs_list_init(replies);
194 ovs_list_push_back(replies, &reply->list_node);
195 }
196
197 static void
198 put_ofp10_queue_rate(struct ofpbuf *reply,
199 enum ofp10_queue_properties property, uint16_t rate)
200 {
201 if (rate != UINT16_MAX) {
202 struct ofp10_queue_prop_rate *oqpr;
203
204 oqpr = ofpbuf_put_zeros(reply, sizeof *oqpr);
205 oqpr->prop_header.property = htons(property);
206 oqpr->prop_header.len = htons(sizeof *oqpr);
207 oqpr->rate = htons(rate);
208 }
209 }
210
211 static void
212 put_ofp14_queue_rate(struct ofpbuf *reply,
213 enum ofp14_queue_desc_prop_type type, uint16_t rate)
214 {
215 if (rate != UINT16_MAX) {
216 ofpprop_put_u16(reply, type, rate);
217 }
218 }
219
220 void
221 ofputil_append_queue_get_config_reply(const struct ofputil_queue_config *qc,
222 struct ovs_list *replies)
223 {
224 enum ofp_version ofp_version = ofpmp_version(replies);
225 struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
226 size_t start_ofs = reply->size;
227 size_t len_ofs;
228 ovs_be16 *len;
229
230 if (ofp_version < OFP14_VERSION) {
231 if (ofp_version < OFP12_VERSION) {
232 struct ofp10_packet_queue *opq10;
233
234 opq10 = ofpbuf_put_zeros(reply, sizeof *opq10);
235 opq10->queue_id = htonl(qc->queue);
236 len_ofs = (char *) &opq10->len - (char *) reply->data;
237 } else {
238 struct ofp12_packet_queue *opq12;
239
240 opq12 = ofpbuf_put_zeros(reply, sizeof *opq12);
241 opq12->port = ofputil_port_to_ofp11(qc->port);
242 opq12->queue_id = htonl(qc->queue);
243 len_ofs = (char *) &opq12->len - (char *) reply->data;
244 }
245
246 put_ofp10_queue_rate(reply, OFPQT10_MIN_RATE, qc->min_rate);
247 put_ofp10_queue_rate(reply, OFPQT11_MAX_RATE, qc->max_rate);
248 } else {
249 struct ofp14_queue_desc *oqd = ofpbuf_put_zeros(reply, sizeof *oqd);
250 oqd->port_no = ofputil_port_to_ofp11(qc->port);
251 oqd->queue_id = htonl(qc->queue);
252 len_ofs = (char *) &oqd->len - (char *) reply->data;
253 put_ofp14_queue_rate(reply, OFPQDPT14_MIN_RATE, qc->min_rate);
254 put_ofp14_queue_rate(reply, OFPQDPT14_MAX_RATE, qc->max_rate);
255 }
256
257 len = ofpbuf_at(reply, len_ofs, sizeof *len);
258 *len = htons(reply->size - start_ofs);
259
260 if (ofp_version >= OFP14_VERSION) {
261 ofpmp_postappend(replies, start_ofs);
262 }
263 }
264
265 static enum ofperr
266 parse_ofp10_queue_rate(const struct ofp10_queue_prop_header *hdr,
267 uint16_t *rate)
268 {
269 const struct ofp10_queue_prop_rate *oqpr;
270
271 if (hdr->len == htons(sizeof *oqpr)) {
272 oqpr = (const struct ofp10_queue_prop_rate *) hdr;
273 *rate = ntohs(oqpr->rate);
274 return 0;
275 } else {
276 return OFPERR_OFPBRC_BAD_LEN;
277 }
278 }
279
280 static int
281 ofputil_pull_queue_get_config_reply10(struct ofpbuf *msg,
282 struct ofputil_queue_config *queue)
283 {
284 const struct ofp_header *oh = msg->header;
285 unsigned int opq_len; /* Length of protocol-specific queue header. */
286 unsigned int len; /* Total length of queue + properties. */
287
288 /* Obtain the port number from the message header. */
289 if (oh->version == OFP10_VERSION) {
290 const struct ofp10_queue_get_config_reply *oqgcr10 = msg->msg;
291 queue->port = u16_to_ofp(ntohs(oqgcr10->port));
292 } else {
293 const struct ofp11_queue_get_config_reply *oqgcr11 = msg->msg;
294 enum ofperr error = ofputil_port_from_ofp11(oqgcr11->port,
295 &queue->port);
296 if (error) {
297 return error;
298 }
299 }
300
301 /* Pull off the queue header and get the queue number and length. */
302 if (oh->version < OFP12_VERSION) {
303 const struct ofp10_packet_queue *opq10;
304 opq10 = ofpbuf_try_pull(msg, sizeof *opq10);
305 if (!opq10) {
306 return OFPERR_OFPBRC_BAD_LEN;
307 }
308 queue->queue = ntohl(opq10->queue_id);
309 len = ntohs(opq10->len);
310 opq_len = sizeof *opq10;
311 } else {
312 const struct ofp12_packet_queue *opq12;
313 opq12 = ofpbuf_try_pull(msg, sizeof *opq12);
314 if (!opq12) {
315 return OFPERR_OFPBRC_BAD_LEN;
316 }
317 queue->queue = ntohl(opq12->queue_id);
318 len = ntohs(opq12->len);
319 opq_len = sizeof *opq12;
320 }
321
322 /* Length check. */
323 if (len < opq_len || len > msg->size + opq_len || len % 8) {
324 return OFPERR_OFPBRC_BAD_LEN;
325 }
326 len -= opq_len;
327
328 /* Pull properties. The format of these properties differs from used in
329 * OF1.4+ so we can't use the common property functions. */
330 while (len > 0) {
331 const struct ofp10_queue_prop_header *hdr;
332 unsigned int property;
333 unsigned int prop_len;
334 enum ofperr error = 0;
335
336 hdr = ofpbuf_at_assert(msg, 0, sizeof *hdr);
337 prop_len = ntohs(hdr->len);
338 if (prop_len < sizeof *hdr || prop_len > len || prop_len % 8) {
339 return OFPERR_OFPBRC_BAD_LEN;
340 }
341
342 property = ntohs(hdr->property);
343 switch (property) {
344 case OFPQT10_MIN_RATE:
345 error = parse_ofp10_queue_rate(hdr, &queue->min_rate);
346 break;
347
348 case OFPQT11_MAX_RATE:
349 error = parse_ofp10_queue_rate(hdr, &queue->max_rate);
350 break;
351
352 default:
353 VLOG_INFO_RL(&rl, "unknown queue property %u", property);
354 break;
355 }
356 if (error) {
357 return error;
358 }
359
360 ofpbuf_pull(msg, prop_len);
361 len -= prop_len;
362 }
363 return 0;
364 }
365
366 static int
367 ofputil_pull_queue_get_config_reply14(struct ofpbuf *msg,
368 struct ofputil_queue_config *queue)
369 {
370 struct ofp14_queue_desc *oqd14 = ofpbuf_try_pull(msg, sizeof *oqd14);
371 if (!oqd14) {
372 return OFPERR_OFPBRC_BAD_LEN;
373 }
374 enum ofperr error = ofputil_port_from_ofp11(oqd14->port_no, &queue->port);
375 if (error) {
376 return error;
377 }
378 queue->queue = ntohl(oqd14->queue_id);
379
380 /* Length check. */
381 unsigned int len = ntohs(oqd14->len);
382 if (len < sizeof *oqd14 || len > msg->size + sizeof *oqd14 || len % 8) {
383 return OFPERR_OFPBRC_BAD_LEN;
384 }
385 len -= sizeof *oqd14;
386
387 struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
388 len);
389 while (properties.size > 0) {
390 struct ofpbuf payload;
391 uint64_t type;
392
393 error = ofpprop_pull(&properties, &payload, &type);
394 if (error) {
395 return error;
396 }
397
398 switch (type) {
399 case OFPQDPT14_MIN_RATE:
400 error = ofpprop_parse_u16(&payload, &queue->min_rate);
401 break;
402
403 case OFPQDPT14_MAX_RATE:
404 error = ofpprop_parse_u16(&payload, &queue->max_rate);
405 break;
406
407 default:
408 error = OFPPROP_UNKNOWN(true, "queue desc", type);
409 break;
410 }
411
412 if (error) {
413 return error;
414 }
415 }
416
417 return 0;
418 }
419
420 /* Decodes information about a queue from the OFPT_QUEUE_GET_CONFIG_REPLY in
421 * 'reply' and stores it in '*queue'. ofputil_decode_queue_get_config_reply()
422 * must already have pulled off the main header.
423 *
424 * This function returns EOF if the last queue has already been decoded, 0 if a
425 * queue was successfully decoded into '*queue', or an ofperr if there was a
426 * problem decoding 'reply'. */
427 int
428 ofputil_pull_queue_get_config_reply(struct ofpbuf *msg,
429 struct ofputil_queue_config *queue)
430 {
431 enum ofpraw raw;
432 if (!msg->header) {
433 /* Pull OpenFlow header. */
434 raw = ofpraw_pull_assert(msg);
435
436 /* Pull protocol-specific ofp_queue_get_config_reply header (OF1.4
437 * doesn't have one at all). */
438 if (raw == OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY) {
439 ofpbuf_pull(msg, sizeof(struct ofp10_queue_get_config_reply));
440 } else if (raw == OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY) {
441 ofpbuf_pull(msg, sizeof(struct ofp11_queue_get_config_reply));
442 } else {
443 ovs_assert(raw == OFPRAW_OFPST14_QUEUE_DESC_REPLY);
444 }
445 } else {
446 raw = ofpraw_decode_assert(msg->header);
447 }
448
449 queue->min_rate = UINT16_MAX;
450 queue->max_rate = UINT16_MAX;
451
452 if (!msg->size) {
453 return EOF;
454 } else if (raw == OFPRAW_OFPST14_QUEUE_DESC_REPLY) {
455 return ofputil_pull_queue_get_config_reply14(msg, queue);
456 } else {
457 return ofputil_pull_queue_get_config_reply10(msg, queue);
458 }
459 }
460
461 static void
462 print_queue_rate(struct ds *string, const char *name, unsigned int rate)
463 {
464 if (rate <= 1000) {
465 ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
466 } else if (rate < UINT16_MAX) {
467 ds_put_format(string, " %s:(disabled)", name);
468 }
469 }
470
471 /* qsort comparison function. */
472 static int
473 compare_queues(const void *a_, const void *b_)
474 {
475 const struct ofputil_queue_config *a = a_;
476 const struct ofputil_queue_config *b = b_;
477
478 uint16_t ap = ofp_to_u16(a->port);
479 uint16_t bp = ofp_to_u16(b->port);
480 if (ap != bp) {
481 return ap < bp ? -1 : 1;
482 }
483
484 uint32_t aq = a->queue;
485 uint32_t bq = b->queue;
486 return aq < bq ? -1 : aq > bq;
487 }
488
489 enum ofperr
490 ofputil_queue_get_config_reply_format(struct ds *string,
491 const struct ofp_header *oh,
492 const struct ofputil_port_map *port_map)
493 {
494 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
495
496 struct ofputil_queue_config *queues = NULL;
497 size_t allocated_queues = 0;
498 size_t n = 0;
499
500 int retval = 0;
501 for (;;) {
502 if (n >= allocated_queues) {
503 queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
504 }
505 retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
506 if (retval) {
507 break;
508 }
509 n++;
510 }
511
512 qsort(queues, n, sizeof *queues, compare_queues);
513
514 ds_put_char(string, ' ');
515
516 ofp_port_t port = 0;
517 for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
518 if (q->port != port) {
519 port = q->port;
520
521 ds_put_cstr(string, "port=");
522 ofputil_format_port(port, port_map, string);
523 ds_put_char(string, '\n');
524 }
525
526 ds_put_format(string, "queue %"PRIu32":", q->queue);
527 print_queue_rate(string, "min_rate", q->min_rate);
528 print_queue_rate(string, "max_rate", q->max_rate);
529 ds_put_char(string, '\n');
530 }
531
532 ds_chomp(string, ' ');
533 free(queues);
534
535 return retval != EOF ? retval : 0;
536 }
537 \f
538 /* Parse a queue status request message into 'oqsr'.
539 * Returns 0 if successful, otherwise an OFPERR_* number. */
540 enum ofperr
541 ofputil_decode_queue_stats_request(const struct ofp_header *request,
542 struct ofputil_queue_stats_request *oqsr)
543 {
544 switch ((enum ofp_version)request->version) {
545 case OFP15_VERSION:
546 case OFP14_VERSION:
547 case OFP13_VERSION:
548 case OFP12_VERSION:
549 case OFP11_VERSION: {
550 const struct ofp11_queue_stats_request *qsr11 = ofpmsg_body(request);
551 oqsr->queue_id = ntohl(qsr11->queue_id);
552 return ofputil_port_from_ofp11(qsr11->port_no, &oqsr->port_no);
553 }
554
555 case OFP10_VERSION: {
556 const struct ofp10_queue_stats_request *qsr10 = ofpmsg_body(request);
557 oqsr->queue_id = ntohl(qsr10->queue_id);
558 oqsr->port_no = u16_to_ofp(ntohs(qsr10->port_no));
559 /* OF 1.0 uses OFPP_ALL for OFPP_ANY */
560 if (oqsr->port_no == OFPP_ALL) {
561 oqsr->port_no = OFPP_ANY;
562 }
563 return 0;
564 }
565
566 default:
567 OVS_NOT_REACHED();
568 }
569 }
570
571 /* Encode a queue stats request for 'oqsr', the encoded message
572 * will be for OpenFlow version 'ofp_version'. Returns message
573 * as a struct ofpbuf. Returns encoded message on success, NULL on error. */
574 struct ofpbuf *
575 ofputil_encode_queue_stats_request(
576 enum ofp_version ofp_version,
577 const struct ofputil_queue_stats_request *oqsr)
578 {
579 struct ofpbuf *request;
580
581 switch (ofp_version) {
582 case OFP11_VERSION:
583 case OFP12_VERSION:
584 case OFP13_VERSION:
585 case OFP14_VERSION:
586 case OFP15_VERSION: {
587 struct ofp11_queue_stats_request *req;
588 request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
589 req = ofpbuf_put_zeros(request, sizeof *req);
590 req->port_no = ofputil_port_to_ofp11(oqsr->port_no);
591 req->queue_id = htonl(oqsr->queue_id);
592 break;
593 }
594 case OFP10_VERSION: {
595 struct ofp10_queue_stats_request *req;
596 request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, ofp_version, 0);
597 req = ofpbuf_put_zeros(request, sizeof *req);
598 /* OpenFlow 1.0 needs OFPP_ALL instead of OFPP_ANY */
599 req->port_no = htons(ofp_to_u16(oqsr->port_no == OFPP_ANY
600 ? OFPP_ALL : oqsr->port_no));
601 req->queue_id = htonl(oqsr->queue_id);
602 break;
603 }
604 default:
605 OVS_NOT_REACHED();
606 }
607
608 return request;
609 }
610
611 enum ofperr
612 ofputil_queue_stats_request_format(struct ds *string,
613 const struct ofp_header *oh,
614 const struct ofputil_port_map *port_map)
615 {
616 struct ofputil_queue_stats_request oqsr;
617 enum ofperr error;
618
619 error = ofputil_decode_queue_stats_request(oh, &oqsr);
620 if (error) {
621 return error;
622 }
623
624 ds_put_cstr(string, " port=");
625 ofputil_format_port(oqsr.port_no, port_map, string);
626
627 ds_put_cstr(string, " queue=");
628 ofp_print_queue_name(string, oqsr.queue_id);
629
630 return 0;
631 }
632
633 /* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
634 * message 'oh'. */
635 size_t
636 ofputil_count_queue_stats(const struct ofp_header *oh)
637 {
638 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
639 ofpraw_pull_assert(&b);
640
641 for (size_t n = 0; ; n++) {
642 struct ofputil_queue_stats qs;
643 if (ofputil_decode_queue_stats(&qs, &b)) {
644 return n;
645 }
646 }
647 }
648
649 static enum ofperr
650 ofputil_queue_stats_from_ofp10(struct ofputil_queue_stats *oqs,
651 const struct ofp10_queue_stats *qs10)
652 {
653 oqs->port_no = u16_to_ofp(ntohs(qs10->port_no));
654 oqs->queue_id = ntohl(qs10->queue_id);
655 oqs->tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
656 oqs->tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
657 oqs->tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
658 oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
659
660 return 0;
661 }
662
663 static enum ofperr
664 ofputil_queue_stats_from_ofp11(struct ofputil_queue_stats *oqs,
665 const struct ofp11_queue_stats *qs11)
666 {
667 enum ofperr error;
668
669 error = ofputil_port_from_ofp11(qs11->port_no, &oqs->port_no);
670 if (error) {
671 return error;
672 }
673
674 oqs->queue_id = ntohl(qs11->queue_id);
675 oqs->tx_bytes = ntohll(qs11->tx_bytes);
676 oqs->tx_packets = ntohll(qs11->tx_packets);
677 oqs->tx_errors = ntohll(qs11->tx_errors);
678 oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
679
680 return 0;
681 }
682
683 static enum ofperr
684 ofputil_queue_stats_from_ofp13(struct ofputil_queue_stats *oqs,
685 const struct ofp13_queue_stats *qs13)
686 {
687 enum ofperr error = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
688 if (!error) {
689 oqs->duration_sec = ntohl(qs13->duration_sec);
690 oqs->duration_nsec = ntohl(qs13->duration_nsec);
691 }
692
693 return error;
694 }
695
696 static enum ofperr
697 ofputil_pull_ofp14_queue_stats(struct ofputil_queue_stats *oqs,
698 struct ofpbuf *msg)
699 {
700 const struct ofp14_queue_stats *qs14;
701 size_t len;
702
703 qs14 = ofpbuf_try_pull(msg, sizeof *qs14);
704 if (!qs14) {
705 return OFPERR_OFPBRC_BAD_LEN;
706 }
707
708 len = ntohs(qs14->length);
709 if (len < sizeof *qs14 || len - sizeof *qs14 > msg->size) {
710 return OFPERR_OFPBRC_BAD_LEN;
711 }
712 ofpbuf_pull(msg, len - sizeof *qs14);
713
714 /* No properties yet defined, so ignore them for now. */
715
716 return ofputil_queue_stats_from_ofp13(oqs, &qs14->qs);
717 }
718
719 /* Converts an OFPST_QUEUE_STATS reply in 'msg' into an abstract
720 * ofputil_queue_stats in 'qs'.
721 *
722 * Multiple OFPST_QUEUE_STATS replies can be packed into a single OpenFlow
723 * message. Calling this function multiple times for a single 'msg' iterates
724 * through the replies. The caller must initially leave 'msg''s layer pointers
725 * null and not modify them between calls.
726 *
727 * Returns 0 if successful, EOF if no replies were left in this 'msg',
728 * otherwise a positive errno value. */
729 int
730 ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
731 {
732 enum ofperr error;
733 enum ofpraw raw;
734
735 error = (msg->header ? ofpraw_decode(&raw, msg->header)
736 : ofpraw_pull(&raw, msg));
737 if (error) {
738 return error;
739 }
740
741 if (!msg->size) {
742 return EOF;
743 } else if (raw == OFPRAW_OFPST14_QUEUE_REPLY) {
744 return ofputil_pull_ofp14_queue_stats(qs, msg);
745 } else if (raw == OFPRAW_OFPST13_QUEUE_REPLY) {
746 const struct ofp13_queue_stats *qs13;
747
748 qs13 = ofpbuf_try_pull(msg, sizeof *qs13);
749 if (!qs13) {
750 goto bad_len;
751 }
752 return ofputil_queue_stats_from_ofp13(qs, qs13);
753 } else if (raw == OFPRAW_OFPST11_QUEUE_REPLY) {
754 const struct ofp11_queue_stats *qs11;
755
756 qs11 = ofpbuf_try_pull(msg, sizeof *qs11);
757 if (!qs11) {
758 goto bad_len;
759 }
760 return ofputil_queue_stats_from_ofp11(qs, qs11);
761 } else if (raw == OFPRAW_OFPST10_QUEUE_REPLY) {
762 const struct ofp10_queue_stats *qs10;
763
764 qs10 = ofpbuf_try_pull(msg, sizeof *qs10);
765 if (!qs10) {
766 goto bad_len;
767 }
768 return ofputil_queue_stats_from_ofp10(qs, qs10);
769 } else {
770 OVS_NOT_REACHED();
771 }
772
773 bad_len:
774 VLOG_WARN_RL(&rl, "OFPST_QUEUE reply has %"PRIu32" leftover "
775 "bytes at end", msg->size);
776 return OFPERR_OFPBRC_BAD_LEN;
777 }
778
779 static void
780 ofputil_queue_stats_to_ofp10(const struct ofputil_queue_stats *oqs,
781 struct ofp10_queue_stats *qs10)
782 {
783 qs10->port_no = htons(ofp_to_u16(oqs->port_no));
784 memset(qs10->pad, 0, sizeof qs10->pad);
785 qs10->queue_id = htonl(oqs->queue_id);
786 put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->tx_bytes));
787 put_32aligned_be64(&qs10->tx_packets, htonll(oqs->tx_packets));
788 put_32aligned_be64(&qs10->tx_errors, htonll(oqs->tx_errors));
789 }
790
791 static void
792 ofputil_queue_stats_to_ofp11(const struct ofputil_queue_stats *oqs,
793 struct ofp11_queue_stats *qs11)
794 {
795 qs11->port_no = ofputil_port_to_ofp11(oqs->port_no);
796 qs11->queue_id = htonl(oqs->queue_id);
797 qs11->tx_bytes = htonll(oqs->tx_bytes);
798 qs11->tx_packets = htonll(oqs->tx_packets);
799 qs11->tx_errors = htonll(oqs->tx_errors);
800 }
801
802 static void
803 ofputil_queue_stats_to_ofp13(const struct ofputil_queue_stats *oqs,
804 struct ofp13_queue_stats *qs13)
805 {
806 ofputil_queue_stats_to_ofp11(oqs, &qs13->qs);
807 if (oqs->duration_sec != UINT32_MAX) {
808 qs13->duration_sec = htonl(oqs->duration_sec);
809 qs13->duration_nsec = htonl(oqs->duration_nsec);
810 } else {
811 qs13->duration_sec = OVS_BE32_MAX;
812 qs13->duration_nsec = OVS_BE32_MAX;
813 }
814 }
815
816 static void
817 ofputil_queue_stats_to_ofp14(const struct ofputil_queue_stats *oqs,
818 struct ofp14_queue_stats *qs14)
819 {
820 qs14->length = htons(sizeof *qs14);
821 memset(qs14->pad, 0, sizeof qs14->pad);
822 ofputil_queue_stats_to_ofp13(oqs, &qs14->qs);
823 }
824
825
826 /* Encode a queue stat for 'oqs' and append it to 'replies'. */
827 void
828 ofputil_append_queue_stat(struct ovs_list *replies,
829 const struct ofputil_queue_stats *oqs)
830 {
831 switch (ofpmp_version(replies)) {
832 case OFP13_VERSION: {
833 struct ofp13_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
834 ofputil_queue_stats_to_ofp13(oqs, reply);
835 break;
836 }
837
838 case OFP12_VERSION:
839 case OFP11_VERSION: {
840 struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
841 ofputil_queue_stats_to_ofp11(oqs, reply);
842 break;
843 }
844
845 case OFP10_VERSION: {
846 struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
847 ofputil_queue_stats_to_ofp10(oqs, reply);
848 break;
849 }
850
851 case OFP14_VERSION:
852 case OFP15_VERSION: {
853 struct ofp14_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
854 ofputil_queue_stats_to_ofp14(oqs, reply);
855 break;
856 }
857
858 default:
859 OVS_NOT_REACHED();
860 }
861 }
862
863 static void
864 print_queue_stat(struct ds *string, const char *leader, uint64_t stat,
865 int more)
866 {
867 ds_put_cstr(string, leader);
868 if (stat != UINT64_MAX) {
869 ds_put_format(string, "%"PRIu64, stat);
870 } else {
871 ds_put_char(string, '?');
872 }
873 if (more) {
874 ds_put_cstr(string, ", ");
875 } else {
876 ds_put_cstr(string, "\n");
877 }
878 }
879
880 enum ofperr
881 ofputil_queue_stats_reply_format(struct ds *string,
882 const struct ofp_header *oh,
883 const struct ofputil_port_map *port_map,
884 int verbosity)
885 {
886 ds_put_format(string, " %"PRIuSIZE" queues\n",
887 ofputil_count_queue_stats(oh));
888 if (verbosity < 1) {
889 return 0;
890 }
891
892 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
893 for (;;) {
894 struct ofputil_queue_stats qs;
895 int retval;
896
897 retval = ofputil_decode_queue_stats(&qs, &b);
898 if (retval) {
899 return retval != EOF ? retval : 0;
900 }
901
902 ds_put_cstr(string, " port ");
903 ofputil_format_port(qs.port_no, port_map, string);
904 ds_put_cstr(string, " queue ");
905 ofp_print_queue_name(string, qs.queue_id);
906 ds_put_cstr(string, ": ");
907
908 print_queue_stat(string, "bytes=", qs.tx_bytes, 1);
909 print_queue_stat(string, "pkts=", qs.tx_packets, 1);
910 print_queue_stat(string, "errors=", qs.tx_errors, 1);
911
912 ds_put_cstr(string, "duration=");
913 if (qs.duration_sec != UINT32_MAX) {
914 ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
915 } else {
916 ds_put_char(string, '?');
917 }
918 ds_put_char(string, '\n');
919 }
920 }
921