Coverage Report

Created: 2025-08-28 06:55

/src/openvswitch/lib/ofp-queue.c
Line
Count
Source (jump to first uncovered line)
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
20.0k
{
36
20.0k
    if (queue_id == OFPQ_ALL) {
37
8.34k
        ds_put_cstr(string, "ALL");
38
11.7k
    } else {
39
11.7k
        ds_put_format(string, "%"PRIu32, queue_id);
40
11.7k
    }
41
20.0k
}
42

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
0
{
55
0
    struct ofpbuf *request;
56
57
0
    if (version == OFP10_VERSION) {
58
0
        struct ofp10_queue_get_config_request *qgcr10;
59
60
0
        request = ofpraw_alloc(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST,
61
0
                               version, 0);
62
0
        qgcr10 = ofpbuf_put_zeros(request, sizeof *qgcr10);
63
0
        qgcr10->port = htons(ofp_to_u16(port));
64
0
    } else if (version < OFP14_VERSION) {
65
0
        struct ofp11_queue_get_config_request *qgcr11;
66
67
0
        request = ofpraw_alloc(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST,
68
0
                               version, 0);
69
0
        qgcr11 = ofpbuf_put_zeros(request, sizeof *qgcr11);
70
0
        qgcr11->port = ofputil_port_to_ofp11(port);
71
0
    } else {
72
0
        struct ofp14_queue_desc_request *qdr14;
73
74
0
        request = ofpraw_alloc(OFPRAW_OFPST14_QUEUE_DESC_REQUEST,
75
0
                               version, 0);
76
0
        qdr14 = ofpbuf_put_zeros(request, sizeof *qdr14);
77
0
        qdr14->port = ofputil_port_to_ofp11(port);
78
0
        qdr14->queue = htonl(queue);
79
0
    }
80
81
0
    return request;
82
0
}
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
5.11k
{
91
5.11k
    const struct ofp10_queue_get_config_request *qgcr10;
92
5.11k
    const struct ofp11_queue_get_config_request *qgcr11;
93
5.11k
    const struct ofp14_queue_desc_request *qdr14;
94
5.11k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
95
5.11k
    enum ofpraw raw = ofpraw_pull_assert(&b);
96
97
5.11k
    switch ((int) raw) {
98
3.45k
    case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
99
3.45k
        qgcr10 = b.data;
100
3.45k
        *port = u16_to_ofp(ntohs(qgcr10->port));
101
3.45k
        *queue = OFPQ_ALL;
102
3.45k
        break;
103
104
1.47k
    case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
105
1.47k
        qgcr11 = b.data;
106
1.47k
        *queue = OFPQ_ALL;
107
1.47k
        enum ofperr error = ofputil_port_from_ofp11(qgcr11->port, port);
108
1.47k
        if (error || *port == OFPP_ANY) {
109
801
            return error;
110
801
        }
111
673
        break;
112
113
673
    case OFPRAW_OFPST14_QUEUE_DESC_REQUEST:
114
188
        qdr14 = b.data;
115
188
        *queue = ntohl(qdr14->queue);
116
188
        return ofputil_port_from_ofp11(qdr14->port, port);
117
118
0
    default:
119
0
        OVS_NOT_REACHED();
120
5.11k
    }
121
122
4.12k
    return (ofp_to_u16(*port) < ofp_to_u16(OFPP_MAX)
123
4.12k
            ? 0
124
4.12k
            : OFPERR_OFPQOFC_BAD_PORT);
125
5.11k
}
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
5.11k
{
132
5.11k
    enum ofperr error;
133
5.11k
    ofp_port_t port;
134
5.11k
    uint32_t queue;
135
136
5.11k
    error = ofputil_decode_queue_get_config_request(oh, &port, &queue);
137
5.11k
    if (error) {
138
927
        return error;
139
927
    }
140
141
4.18k
    ds_put_cstr(string, " port=");
142
4.18k
    ofputil_format_port(port, port_map, string);
143
144
4.18k
    if (queue != OFPQ_ALL) {
145
129
        ds_put_cstr(string, " queue=");
146
129
        ofp_print_queue_name(string, queue);
147
129
    }
148
149
4.18k
    return 0;
150
5.11k
}
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
0
{
160
0
    struct ofpbuf *reply;
161
0
    ofp_port_t port;
162
0
    uint32_t queue;
163
164
0
    ovs_assert(!ofputil_decode_queue_get_config_request(request, &port,
165
0
                                                        &queue));
166
167
0
    enum ofpraw raw = ofpraw_decode_assert(request);
168
0
    switch ((int) raw) {
169
0
    case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
170
0
        reply = ofpraw_alloc_reply(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY,
171
0
                                   request, 0);
172
0
        struct ofp10_queue_get_config_reply *qgcr10
173
0
            = ofpbuf_put_zeros(reply, sizeof *qgcr10);
174
0
        qgcr10->port = htons(ofp_to_u16(port));
175
0
        break;
176
177
0
    case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
178
0
        reply = ofpraw_alloc_reply(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY,
179
0
                                   request, 0);
180
0
        struct ofp11_queue_get_config_reply *qgcr11
181
0
            = ofpbuf_put_zeros(reply, sizeof *qgcr11);
182
0
        qgcr11->port = ofputil_port_to_ofp11(port);
183
0
        break;
184
185
0
    case OFPRAW_OFPST14_QUEUE_DESC_REQUEST:
186
0
        reply = ofpraw_alloc_stats_reply(request, 0);
187
0
        break;
188
189
0
    default:
190
0
        OVS_NOT_REACHED();
191
0
    }
192
193
0
    ovs_list_init(replies);
194
0
    ovs_list_push_back(replies, &reply->list_node);
195
0
}
196
197
static void
198
put_ofp10_queue_rate(struct ofpbuf *reply,
199
                     enum ofp10_queue_properties property, uint16_t rate)
200
0
{
201
0
    if (rate != UINT16_MAX) {
202
0
        struct ofp10_queue_prop_rate *oqpr;
203
204
0
        oqpr = ofpbuf_put_zeros(reply, sizeof *oqpr);
205
0
        oqpr->prop_header.property = htons(property);
206
0
        oqpr->prop_header.len = htons(sizeof *oqpr);
207
0
        oqpr->rate = htons(rate);
208
0
    }
209
0
}
210
211
static void
212
put_ofp14_queue_rate(struct ofpbuf *reply,
213
                     enum ofp14_queue_desc_prop_type type, uint16_t rate)
214
0
{
215
0
    if (rate != UINT16_MAX) {
216
0
        ofpprop_put_u16(reply, type, rate);
217
0
    }
218
0
}
219
220
void
221
ofputil_append_queue_get_config_reply(const struct ofputil_queue_config *qc,
222
                                      struct ovs_list *replies)
223
0
{
224
0
    enum ofp_version ofp_version = ofpmp_version(replies);
225
0
    struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
226
0
    size_t start_ofs = reply->size;
227
0
    size_t len_ofs;
228
0
    ovs_be16 *len;
229
230
0
    if (ofp_version < OFP14_VERSION) {
231
0
        if (ofp_version < OFP12_VERSION) {
232
0
            struct ofp10_packet_queue *opq10;
233
234
0
            opq10 = ofpbuf_put_zeros(reply, sizeof *opq10);
235
0
            opq10->queue_id = htonl(qc->queue);
236
0
            len_ofs = (char *) &opq10->len - (char *) reply->data;
237
0
        } else {
238
0
            struct ofp12_packet_queue *opq12;
239
240
0
            opq12 = ofpbuf_put_zeros(reply, sizeof *opq12);
241
0
            opq12->port = ofputil_port_to_ofp11(qc->port);
242
0
            opq12->queue_id = htonl(qc->queue);
243
0
            len_ofs = (char *) &opq12->len - (char *) reply->data;
244
0
        }
245
246
0
        put_ofp10_queue_rate(reply, OFPQT10_MIN_RATE, qc->min_rate);
247
0
        put_ofp10_queue_rate(reply, OFPQT11_MAX_RATE, qc->max_rate);
248
0
    } else {
249
0
        struct ofp14_queue_desc *oqd = ofpbuf_put_zeros(reply, sizeof *oqd);
250
0
        oqd->port_no = ofputil_port_to_ofp11(qc->port);
251
0
        oqd->queue_id = htonl(qc->queue);
252
0
        len_ofs = (char *) &oqd->len - (char *) reply->data;
253
0
        put_ofp14_queue_rate(reply, OFPQDPT14_MIN_RATE, qc->min_rate);
254
0
        put_ofp14_queue_rate(reply, OFPQDPT14_MAX_RATE, qc->max_rate);
255
0
    }
256
257
0
    len = ofpbuf_at(reply, len_ofs, sizeof *len);
258
0
    *len = htons(reply->size - start_ofs);
259
260
0
    if (ofp_version >= OFP14_VERSION) {
261
0
        ofpmp_postappend(replies, start_ofs);
262
0
    }
263
0
}
264
265
static enum ofperr
266
parse_ofp10_queue_rate(const struct ofp10_queue_prop_header *hdr,
267
                       uint16_t *rate)
268
337
{
269
337
    const struct ofp10_queue_prop_rate *oqpr;
270
271
337
    if (hdr->len == htons(sizeof *oqpr)) {
272
232
        oqpr = (const struct ofp10_queue_prop_rate *) hdr;
273
232
        *rate = ntohs(oqpr->rate);
274
232
        return 0;
275
232
    } else {
276
105
        return OFPERR_OFPBRC_BAD_LEN;
277
105
    }
278
337
}
279
280
static int
281
ofputil_pull_queue_get_config_reply10(struct ofpbuf *msg,
282
                                      struct ofputil_queue_config *queue)
283
16.5k
{
284
16.5k
    const struct ofp_header *oh = msg->header;
285
16.5k
    unsigned int opq_len;       /* Length of protocol-specific queue header. */
286
16.5k
    unsigned int len;           /* Total length of queue + properties. */
287
288
    /* Obtain the port number from the message header. */
289
16.5k
    if (oh->version == OFP10_VERSION) {
290
4.22k
        const struct ofp10_queue_get_config_reply *oqgcr10 = msg->msg;
291
4.22k
        queue->port = u16_to_ofp(ntohs(oqgcr10->port));
292
12.3k
    } else {
293
12.3k
        const struct ofp11_queue_get_config_reply *oqgcr11 = msg->msg;
294
12.3k
        enum ofperr error = ofputil_port_from_ofp11(oqgcr11->port,
295
12.3k
                                                    &queue->port);
296
12.3k
        if (error) {
297
216
            return error;
298
216
        }
299
12.3k
    }
300
301
    /* Pull off the queue header and get the queue number and length. */
302
16.3k
    if (oh->version < OFP12_VERSION) {
303
16.0k
        const struct ofp10_packet_queue *opq10;
304
16.0k
        opq10 = ofpbuf_try_pull(msg, sizeof *opq10);
305
16.0k
        if (!opq10) {
306
0
            return OFPERR_OFPBRC_BAD_LEN;
307
0
        }
308
16.0k
        queue->queue = ntohl(opq10->queue_id);
309
16.0k
        len = ntohs(opq10->len);
310
16.0k
        opq_len = sizeof *opq10;
311
16.0k
    } else {
312
298
        const struct ofp12_packet_queue *opq12;
313
298
        opq12 = ofpbuf_try_pull(msg, sizeof *opq12);
314
298
        if (!opq12) {
315
205
            return OFPERR_OFPBRC_BAD_LEN;
316
205
        }
317
93
        queue->queue = ntohl(opq12->queue_id);
318
93
        len = ntohs(opq12->len);
319
93
        opq_len = sizeof *opq12;
320
93
    }
321
322
    /* Length check. */
323
16.1k
    if (len < opq_len || len > msg->size + opq_len || len % 8) {
324
3.05k
        return OFPERR_OFPBRC_BAD_LEN;
325
3.05k
    }
326
13.0k
    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
14.9k
    while (len > 0) {
331
3.61k
        const struct ofp10_queue_prop_header *hdr;
332
3.61k
        unsigned int property;
333
3.61k
        unsigned int prop_len;
334
3.61k
        enum ofperr error = 0;
335
336
3.61k
        hdr = ofpbuf_at_assert(msg, 0, sizeof *hdr);
337
3.61k
        prop_len = ntohs(hdr->len);
338
3.61k
        if (prop_len < sizeof *hdr || prop_len > len || prop_len % 8) {
339
1.64k
            return OFPERR_OFPBRC_BAD_LEN;
340
1.64k
        }
341
342
1.97k
        property = ntohs(hdr->property);
343
1.97k
        switch (property) {
344
273
        case OFPQT10_MIN_RATE:
345
273
            error = parse_ofp10_queue_rate(hdr, &queue->min_rate);
346
273
            break;
347
348
64
        case OFPQT11_MAX_RATE:
349
64
            error = parse_ofp10_queue_rate(hdr, &queue->max_rate);
350
64
            break;
351
352
1.63k
        default:
353
1.63k
            VLOG_INFO_RL(&rl, "unknown queue property %u", property);
354
1.63k
            break;
355
1.97k
        }
356
1.97k
        if (error) {
357
105
            return error;
358
105
        }
359
360
1.86k
        ofpbuf_pull(msg, prop_len);
361
1.86k
        len -= prop_len;
362
1.86k
    }
363
11.3k
    return 0;
364
13.0k
}
365
366
static int
367
ofputil_pull_queue_get_config_reply14(struct ofpbuf *msg,
368
                                      struct ofputil_queue_config *queue)
369
4.89k
{
370
4.89k
    struct ofp14_queue_desc *oqd14 = ofpbuf_try_pull(msg, sizeof *oqd14);
371
4.89k
    if (!oqd14) {
372
604
        return OFPERR_OFPBRC_BAD_LEN;
373
604
    }
374
4.29k
    enum ofperr error = ofputil_port_from_ofp11(oqd14->port_no, &queue->port);
375
4.29k
    if (error) {
376
439
        return error;
377
439
    }
378
3.85k
    queue->queue = ntohl(oqd14->queue_id);
379
380
    /* Length check. */
381
3.85k
    unsigned int len = ntohs(oqd14->len);
382
3.85k
    if (len < sizeof *oqd14 || len > msg->size + sizeof *oqd14 || len % 8) {
383
1.66k
        return OFPERR_OFPBRC_BAD_LEN;
384
1.66k
    }
385
2.18k
    len -= sizeof *oqd14;
386
387
2.18k
    struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
388
2.18k
                                                        len);
389
3.26k
    while (properties.size > 0) {
390
2.50k
        struct ofpbuf payload;
391
2.50k
        uint64_t type;
392
393
2.50k
        error = ofpprop_pull(&properties, &payload, &type);
394
2.50k
        if (error) {
395
739
            return error;
396
739
        }
397
398
1.76k
        switch (type) {
399
857
        case OFPQDPT14_MIN_RATE:
400
857
            error = ofpprop_parse_u16(&payload, &queue->min_rate);
401
857
            break;
402
403
391
        case OFPQDPT14_MAX_RATE:
404
391
            error = ofpprop_parse_u16(&payload, &queue->max_rate);
405
391
            break;
406
407
516
        default:
408
516
            error = OFPPROP_UNKNOWN(true, "queue desc", type);
409
516
            break;
410
1.76k
        }
411
412
1.76k
        if (error) {
413
692
            return error;
414
692
        }
415
1.76k
    }
416
417
758
    return 0;
418
2.18k
}
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
22.3k
{
431
22.3k
    enum ofpraw raw;
432
22.3k
    if (!msg->header) {
433
        /* Pull OpenFlow header. */
434
10.2k
        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
10.2k
        if (raw == OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY) {
439
1.67k
            ofpbuf_pull(msg, sizeof(struct ofp10_queue_get_config_reply));
440
8.61k
        } else if (raw == OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY) {
441
4.32k
            ofpbuf_pull(msg, sizeof(struct ofp11_queue_get_config_reply));
442
4.32k
        } else {
443
4.29k
            ovs_assert(raw == OFPRAW_OFPST14_QUEUE_DESC_REPLY);
444
4.29k
        }
445
12.0k
    } else {
446
12.0k
        raw = ofpraw_decode_assert(msg->header);
447
12.0k
    }
448
449
22.3k
    queue->min_rate = UINT16_MAX;
450
22.3k
    queue->max_rate = UINT16_MAX;
451
452
22.3k
    if (!msg->size) {
453
925
        return EOF;
454
21.4k
    } else if (raw == OFPRAW_OFPST14_QUEUE_DESC_REPLY) {
455
4.89k
        return ofputil_pull_queue_get_config_reply14(msg, queue);
456
16.5k
    } else {
457
16.5k
        return ofputil_pull_queue_get_config_reply10(msg, queue);
458
16.5k
    }
459
22.3k
}
460
461
static void
462
print_queue_rate(struct ds *string, const char *name, unsigned int rate)
463
24.1k
{
464
24.1k
    if (rate <= 1000) {
465
461
        ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
466
23.6k
    } else if (rate < UINT16_MAX) {
467
257
        ds_put_format(string, " %s:(disabled)", name);
468
257
    }
469
24.1k
}
470
471
/* qsort comparison function. */
472
static int
473
compare_queues(const void *a_, const void *b_)
474
11.7k
{
475
11.7k
    const struct ofputil_queue_config *a = a_;
476
11.7k
    const struct ofputil_queue_config *b = b_;
477
478
11.7k
    uint16_t ap = ofp_to_u16(a->port);
479
11.7k
    uint16_t bp = ofp_to_u16(b->port);
480
11.7k
    if (ap != bp) {
481
344
        return ap < bp ? -1 : 1;
482
344
    }
483
484
11.3k
    uint32_t aq = a->queue;
485
11.3k
    uint32_t bq = b->queue;
486
11.3k
    return aq < bq ? -1 : aq > bq;
487
11.7k
}
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
10.2k
{
494
10.2k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
495
496
10.2k
    struct ofputil_queue_config *queues = NULL;
497
10.2k
    size_t allocated_queues = 0;
498
10.2k
    size_t n = 0;
499
500
10.2k
    int retval = 0;
501
22.3k
    for (;;) {
502
22.3k
        if (n >= allocated_queues) {
503
19.3k
            queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
504
19.3k
        }
505
22.3k
        retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
506
22.3k
        if (retval) {
507
10.2k
            break;
508
10.2k
        }
509
12.0k
        n++;
510
12.0k
    }
511
512
10.2k
    qsort(queues, n, sizeof *queues, compare_queues);
513
514
10.2k
    ds_put_char(string, ' ');
515
516
10.2k
    ofp_port_t port = 0;
517
22.3k
    for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
518
12.0k
        if (q->port != port) {
519
2.97k
            port = q->port;
520
521
2.97k
            ds_put_cstr(string, "port=");
522
2.97k
            ofputil_format_port(port, port_map, string);
523
2.97k
            ds_put_char(string, '\n');
524
2.97k
        }
525
526
12.0k
        ds_put_format(string, "queue %"PRIu32":", q->queue);
527
12.0k
        print_queue_rate(string, "min_rate", q->min_rate);
528
12.0k
        print_queue_rate(string, "max_rate", q->max_rate);
529
12.0k
        ds_put_char(string, '\n');
530
12.0k
    }
531
532
10.2k
    ds_chomp(string, ' ');
533
10.2k
    free(queues);
534
535
10.2k
    return retval != EOF ? retval : 0;
536
10.2k
}
537

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
1.76k
{
544
1.76k
    switch ((enum ofp_version)request->version) {
545
341
    case OFP15_VERSION:
546
547
    case OFP14_VERSION:
547
615
    case OFP13_VERSION:
548
682
    case OFP12_VERSION:
549
778
    case OFP11_VERSION: {
550
778
        const struct ofp11_queue_stats_request *qsr11 = ofpmsg_body(request);
551
778
        oqsr->queue_id = ntohl(qsr11->queue_id);
552
778
        return ofputil_port_from_ofp11(qsr11->port_no, &oqsr->port_no);
553
682
    }
554
555
991
    case OFP10_VERSION: {
556
991
        const struct ofp10_queue_stats_request *qsr10 = ofpmsg_body(request);
557
991
        oqsr->queue_id = ntohl(qsr10->queue_id);
558
991
        oqsr->port_no = u16_to_ofp(ntohs(qsr10->port_no));
559
        /* OF 1.0 uses OFPP_ALL for OFPP_ANY */
560
991
        if (oqsr->port_no == OFPP_ALL) {
561
380
            oqsr->port_no = OFPP_ANY;
562
380
        }
563
991
        return 0;
564
682
    }
565
566
0
    default:
567
0
        OVS_NOT_REACHED();
568
1.76k
    }
569
1.76k
}
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
0
{
579
0
    struct ofpbuf *request;
580
581
0
    switch (ofp_version) {
582
0
    case OFP11_VERSION:
583
0
    case OFP12_VERSION:
584
0
    case OFP13_VERSION:
585
0
    case OFP14_VERSION:
586
0
    case OFP15_VERSION: {
587
0
        struct ofp11_queue_stats_request *req;
588
0
        request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
589
0
        req = ofpbuf_put_zeros(request, sizeof *req);
590
0
        req->port_no = ofputil_port_to_ofp11(oqsr->port_no);
591
0
        req->queue_id = htonl(oqsr->queue_id);
592
0
        break;
593
0
    }
594
0
    case OFP10_VERSION: {
595
0
        struct ofp10_queue_stats_request *req;
596
0
        request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, ofp_version, 0);
597
0
        req = ofpbuf_put_zeros(request, sizeof *req);
598
        /* OpenFlow 1.0 needs OFPP_ALL instead of OFPP_ANY */
599
0
        req->port_no = htons(ofp_to_u16(oqsr->port_no == OFPP_ANY
600
0
                                        ? OFPP_ALL : oqsr->port_no));
601
0
        req->queue_id = htonl(oqsr->queue_id);
602
0
        break;
603
0
    }
604
0
    default:
605
0
        OVS_NOT_REACHED();
606
0
    }
607
608
0
    return request;
609
0
}
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
1.76k
{
616
1.76k
    struct ofputil_queue_stats_request oqsr;
617
1.76k
    enum ofperr error;
618
619
1.76k
    error = ofputil_decode_queue_stats_request(oh, &oqsr);
620
1.76k
    if (error) {
621
475
        return error;
622
475
    }
623
624
1.29k
    ds_put_cstr(string, " port=");
625
1.29k
    ofputil_format_port(oqsr.port_no, port_map, string);
626
627
1.29k
    ds_put_cstr(string, " queue=");
628
1.29k
    ofp_print_queue_name(string, oqsr.queue_id);
629
630
1.29k
    return 0;
631
1.76k
}
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
15.3k
{
638
15.3k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
639
15.3k
    ofpraw_pull_assert(&b);
640
641
33.9k
    for (size_t n = 0; ; n++) {
642
33.9k
        struct ofputil_queue_stats qs;
643
33.9k
        if (ofputil_decode_queue_stats(&qs, &b)) {
644
15.3k
            return n;
645
15.3k
        }
646
33.9k
    }
647
15.3k
}
648
649
static enum ofperr
650
ofputil_queue_stats_from_ofp10(struct ofputil_queue_stats *oqs,
651
                               const struct ofp10_queue_stats *qs10)
652
3.26k
{
653
3.26k
    oqs->port_no = u16_to_ofp(ntohs(qs10->port_no));
654
3.26k
    oqs->queue_id = ntohl(qs10->queue_id);
655
3.26k
    oqs->tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
656
3.26k
    oqs->tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
657
3.26k
    oqs->tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
658
3.26k
    oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
659
660
3.26k
    return 0;
661
3.26k
}
662
663
static enum ofperr
664
ofputil_queue_stats_from_ofp11(struct ofputil_queue_stats *oqs,
665
                               const struct ofp11_queue_stats *qs11)
666
53.6k
{
667
53.6k
    enum ofperr error;
668
669
53.6k
    error = ofputil_port_from_ofp11(qs11->port_no, &oqs->port_no);
670
53.6k
    if (error) {
671
19.5k
        return error;
672
19.5k
    }
673
674
34.0k
    oqs->queue_id = ntohl(qs11->queue_id);
675
34.0k
    oqs->tx_bytes = ntohll(qs11->tx_bytes);
676
34.0k
    oqs->tx_packets = ntohll(qs11->tx_packets);
677
34.0k
    oqs->tx_errors = ntohll(qs11->tx_errors);
678
34.0k
    oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
679
680
34.0k
    return 0;
681
53.6k
}
682
683
static enum ofperr
684
ofputil_queue_stats_from_ofp13(struct ofputil_queue_stats *oqs,
685
                               const struct ofp13_queue_stats *qs13)
686
16.5k
{
687
16.5k
    enum ofperr error = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
688
16.5k
    if (!error) {
689
5.11k
        oqs->duration_sec = ntohl(qs13->duration_sec);
690
5.11k
        oqs->duration_nsec = ntohl(qs13->duration_nsec);
691
5.11k
    }
692
693
16.5k
    return error;
694
16.5k
}
695
696
static enum ofperr
697
ofputil_pull_ofp14_queue_stats(struct ofputil_queue_stats *oqs,
698
                               struct ofpbuf *msg)
699
21.8k
{
700
21.8k
    const struct ofp14_queue_stats *qs14;
701
21.8k
    size_t len;
702
703
21.8k
    qs14 = ofpbuf_try_pull(msg, sizeof *qs14);
704
21.8k
    if (!qs14) {
705
574
        return OFPERR_OFPBRC_BAD_LEN;
706
574
    }
707
708
21.2k
    len = ntohs(qs14->length);
709
21.2k
    if (len < sizeof *qs14 || len - sizeof *qs14 > msg->size) {
710
6.28k
        return OFPERR_OFPBRC_BAD_LEN;
711
6.28k
    }
712
14.9k
    ofpbuf_pull(msg, len - sizeof *qs14);
713
714
    /* No properties yet defined, so ignore them for now. */
715
716
14.9k
    return ofputil_queue_stats_from_ofp13(oqs, &qs14->qs);
717
21.2k
}
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
67.9k
{
732
67.9k
    enum ofperr error;
733
67.9k
    enum ofpraw raw;
734
735
67.9k
    error = (msg->header ? ofpraw_decode(&raw, msg->header)
736
67.9k
             : ofpraw_pull(&raw, msg));
737
67.9k
    if (error) {
738
0
        return error;
739
0
    }
740
741
67.9k
    if (!msg->size) {
742
4.17k
        return EOF;
743
63.8k
    } else if (raw == OFPRAW_OFPST14_QUEUE_REPLY) {
744
21.8k
        return ofputil_pull_ofp14_queue_stats(qs, msg);
745
41.9k
    } else if (raw == OFPRAW_OFPST13_QUEUE_REPLY) {
746
1.63k
        const struct ofp13_queue_stats *qs13;
747
748
1.63k
        qs13 = ofpbuf_try_pull(msg, sizeof *qs13);
749
1.63k
        if (!qs13) {
750
0
            goto bad_len;
751
0
        }
752
1.63k
        return ofputil_queue_stats_from_ofp13(qs, qs13);
753
40.3k
    } else if (raw == OFPRAW_OFPST11_QUEUE_REPLY) {
754
37.1k
        const struct ofp11_queue_stats *qs11;
755
756
37.1k
        qs11 = ofpbuf_try_pull(msg, sizeof *qs11);
757
37.1k
        if (!qs11) {
758
0
            goto bad_len;
759
0
        }
760
37.1k
        return ofputil_queue_stats_from_ofp11(qs, qs11);
761
37.1k
    } else if (raw == OFPRAW_OFPST10_QUEUE_REPLY) {
762
3.26k
        const struct ofp10_queue_stats *qs10;
763
764
3.26k
        qs10 = ofpbuf_try_pull(msg, sizeof *qs10);
765
3.26k
        if (!qs10) {
766
0
            goto bad_len;
767
0
        }
768
3.26k
        return ofputil_queue_stats_from_ofp10(qs, qs10);
769
3.26k
    } else {
770
0
        OVS_NOT_REACHED();
771
0
    }
772
773
0
 bad_len:
774
0
    VLOG_WARN_RL(&rl, "OFPST_QUEUE reply has %"PRIu32" leftover "
775
0
                 "bytes at end", msg->size);
776
0
    return OFPERR_OFPBRC_BAD_LEN;
777
67.9k
}
778
779
static void
780
ofputil_queue_stats_to_ofp10(const struct ofputil_queue_stats *oqs,
781
                             struct ofp10_queue_stats *qs10)
782
0
{
783
0
    qs10->port_no = htons(ofp_to_u16(oqs->port_no));
784
0
    memset(qs10->pad, 0, sizeof qs10->pad);
785
0
    qs10->queue_id = htonl(oqs->queue_id);
786
0
    put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->tx_bytes));
787
0
    put_32aligned_be64(&qs10->tx_packets, htonll(oqs->tx_packets));
788
0
    put_32aligned_be64(&qs10->tx_errors, htonll(oqs->tx_errors));
789
0
}
790
791
static void
792
ofputil_queue_stats_to_ofp11(const struct ofputil_queue_stats *oqs,
793
                             struct ofp11_queue_stats *qs11)
794
0
{
795
0
    qs11->port_no = ofputil_port_to_ofp11(oqs->port_no);
796
0
    qs11->queue_id = htonl(oqs->queue_id);
797
0
    qs11->tx_bytes = htonll(oqs->tx_bytes);
798
0
    qs11->tx_packets = htonll(oqs->tx_packets);
799
0
    qs11->tx_errors = htonll(oqs->tx_errors);
800
0
}
801
802
static void
803
ofputil_queue_stats_to_ofp13(const struct ofputil_queue_stats *oqs,
804
                             struct ofp13_queue_stats *qs13)
805
0
{
806
0
    ofputil_queue_stats_to_ofp11(oqs, &qs13->qs);
807
0
    if (oqs->duration_sec != UINT32_MAX) {
808
0
        qs13->duration_sec = htonl(oqs->duration_sec);
809
0
        qs13->duration_nsec = htonl(oqs->duration_nsec);
810
0
    } else {
811
0
        qs13->duration_sec = OVS_BE32_MAX;
812
0
        qs13->duration_nsec = OVS_BE32_MAX;
813
0
    }
814
0
}
815
816
static void
817
ofputil_queue_stats_to_ofp14(const struct ofputil_queue_stats *oqs,
818
                             struct ofp14_queue_stats *qs14)
819
0
{
820
0
    qs14->length = htons(sizeof *qs14);
821
0
    memset(qs14->pad, 0, sizeof qs14->pad);
822
0
    ofputil_queue_stats_to_ofp13(oqs, &qs14->qs);
823
0
}
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
0
{
831
0
    switch (ofpmp_version(replies)) {
832
0
    case OFP13_VERSION: {
833
0
        struct ofp13_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
834
0
        ofputil_queue_stats_to_ofp13(oqs, reply);
835
0
        break;
836
0
    }
837
838
0
    case OFP12_VERSION:
839
0
    case OFP11_VERSION: {
840
0
        struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
841
0
        ofputil_queue_stats_to_ofp11(oqs, reply);
842
0
        break;
843
0
    }
844
845
0
    case OFP10_VERSION: {
846
0
        struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
847
0
        ofputil_queue_stats_to_ofp10(oqs, reply);
848
0
        break;
849
0
    }
850
851
0
    case OFP14_VERSION:
852
0
    case OFP15_VERSION: {
853
0
        struct ofp14_queue_stats *reply = ofpmp_append(replies, sizeof *reply);
854
0
        ofputil_queue_stats_to_ofp14(oqs, reply);
855
0
        break;
856
0
    }
857
858
0
    default:
859
0
        OVS_NOT_REACHED();
860
0
    }
861
0
}
862
863
static void
864
print_queue_stat(struct ds *string, const char *leader, uint64_t stat,
865
                 int more)
866
56.0k
{
867
56.0k
    ds_put_cstr(string, leader);
868
56.0k
    if (stat != UINT64_MAX) {
869
36.9k
        ds_put_format(string, "%"PRIu64, stat);
870
36.9k
    } else {
871
19.0k
        ds_put_char(string, '?');
872
19.0k
    }
873
56.0k
    if (more) {
874
56.0k
        ds_put_cstr(string, ", ");
875
56.0k
    } else {
876
0
        ds_put_cstr(string, "\n");
877
0
    }
878
56.0k
}
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
15.3k
{
886
15.3k
    ds_put_format(string, " %"PRIuSIZE" queues\n",
887
15.3k
                  ofputil_count_queue_stats(oh));
888
15.3k
    if (verbosity < 1) {
889
0
        return 0;
890
0
    }
891
892
15.3k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
893
33.9k
    for (;;) {
894
33.9k
        struct ofputil_queue_stats qs;
895
33.9k
        int retval;
896
897
33.9k
        retval = ofputil_decode_queue_stats(&qs, &b);
898
33.9k
        if (retval) {
899
15.3k
            return retval != EOF ? retval : 0;
900
15.3k
        }
901
902
18.6k
        ds_put_cstr(string, "  port ");
903
18.6k
        ofputil_format_port(qs.port_no, port_map, string);
904
18.6k
        ds_put_cstr(string, " queue ");
905
18.6k
        ofp_print_queue_name(string, qs.queue_id);
906
18.6k
        ds_put_cstr(string, ": ");
907
908
18.6k
        print_queue_stat(string, "bytes=", qs.tx_bytes, 1);
909
18.6k
        print_queue_stat(string, "pkts=", qs.tx_packets, 1);
910
18.6k
        print_queue_stat(string, "errors=", qs.tx_errors, 1);
911
912
18.6k
        ds_put_cstr(string, "duration=");
913
18.6k
        if (qs.duration_sec != UINT32_MAX) {
914
2.51k
            ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
915
16.1k
        } else {
916
16.1k
            ds_put_char(string, '?');
917
16.1k
        }
918
18.6k
        ds_put_char(string, '\n');
919
18.6k
    }
920
15.3k
}
921