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