OFPRAW_OFPST11_PORT_REPLY,
/* OFPST 1.0 (5): struct ofp10_queue_stats_request. */
- OFPRAW_OFPST_QUEUE_REQUEST,
+ OFPRAW_OFPST10_QUEUE_REQUEST,
+ /* OFPST 1.1+ (5): struct ofp11_queue_stats_request. */
+ OFPRAW_OFPST11_QUEUE_REQUEST,
/* OFPST 1.0 (5): struct ofp10_queue_stats[]. */
- OFPRAW_OFPST_QUEUE_REPLY,
+ OFPRAW_OFPST10_QUEUE_REPLY,
+ /* OFPST 1.1+ (5): struct ofp11_queue_stats[]. */
+ OFPRAW_OFPST11_QUEUE_REPLY,
/* OFPST 1.0+ (13): void. */
OFPRAW_OFPST_PORT_DESC_REQUEST,
* OFPRAW_OFPST11_PORT_REQUEST. */
OFPTYPE_PORT_STATS_REPLY, /* OFPRAW_OFPST10_PORT_REPLY.
* OFPRAW_OFPST11_PORT_REPLY. */
- OFPTYPE_QUEUE_STATS_REQUEST, /* OFPRAW_OFPST_QUEUE_REQUEST. */
- OFPTYPE_QUEUE_STATS_REPLY, /* OFPRAW_OFPST_QUEUE_REPLY. */
+ OFPTYPE_QUEUE_STATS_REQUEST, /* OFPRAW_OFPST10_QUEUE_REQUEST.
+ * OFPRAW_OFPST11_QUEUE_REQUEST. */
+ OFPTYPE_QUEUE_STATS_REPLY, /* OFPRAW_OFPST10_QUEUE_REPLY.
+ * OFPRAW_OFPST11_QUEUE_REPLY. */
OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
+
OFPTYPE_PORT_DESC_STATS_REPLY, /* OFPRAW_OFPST10_PORT_DESC_REPLY.
* OFPRAW_OFPST11_PORT_DESC_REPLY. */
static void
ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp10_queue_stats_request *qsr = ofpmsg_body(oh);
+ struct ofputil_queue_stats_request oqsr;
+ enum ofperr error;
+
+ error = ofputil_decode_queue_stats_request(oh, &oqsr);
+ if (error) {
+ ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
+ return;
+ }
ds_put_cstr(string, "port=");
- ofputil_format_port(ntohs(qsr->port_no), string);
+ ofputil_format_port(oqsr.port_no, string);
ds_put_cstr(string, " queue=");
- ofp_print_queue_name(string, ntohl(qsr->queue_id));
-}
-
-static void
-print_queue_stat(struct ds *string, const char *leader,
- const ovs_32aligned_be64 *statp, int more)
-{
- print_port_stat(string, leader, ntohll(get_32aligned_be64(statp)), more);
+ ofp_print_queue_name(string, oqsr.queue_id);
}
static void
ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
int verbosity)
{
- struct ofp10_queue_stats *qs;
struct ofpbuf b;
- size_t n;
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
- ofpraw_pull_assert(&b);
-
- n = b.size / sizeof *qs;
- ds_put_format(string, " %zu queues\n", n);
+ ds_put_format(string, " %zu queues\n", ofputil_count_queue_stats(oh));
if (verbosity < 1) {
return;
}
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
for (;;) {
- qs = ofpbuf_try_pull(&b, sizeof *qs);
- if (!qs) {
+ struct ofputil_queue_stats qs;
+ int retval;
+
+ retval = ofputil_decode_queue_stats(&qs, &b);
+ if (retval) {
+ if (retval != EOF) {
+ ds_put_cstr(string, " ***parse error***");
+ }
return;
}
ds_put_cstr(string, " port ");
- ofputil_format_port(ntohs(qs->port_no), string);
+ ofputil_format_port(qs.port_no, string);
ds_put_cstr(string, " queue ");
- ofp_print_queue_name(string, ntohl(qs->queue_id));
+ ofp_print_queue_name(string, qs.queue_id);
ds_put_cstr(string, ": ");
- print_queue_stat(string, "bytes=", &qs->tx_bytes, 1);
- print_queue_stat(string, "pkts=", &qs->tx_packets, 1);
- print_queue_stat(string, "errors=", &qs->tx_errors, 0);
+ print_port_stat(string, "bytes=", qs.stats.tx_bytes, 1);
+ print_port_stat(string, "pkts=", qs.stats.tx_packets, 1);
+ print_port_stat(string, "errors=", qs.stats.tx_errors, 0);
}
}
NOT_REACHED();
}
}
+
+/* Parse a queue status request message into 'oqsr'.
+ * Returns 0 if successful, otherwise an OFPERR_* number. */
+enum ofperr
+ofputil_decode_queue_stats_request(const struct ofp_header *request,
+ struct ofputil_queue_stats_request *oqsr)
+{
+ switch ((enum ofp_version)request->version) {
+ case OFP12_VERSION:
+ case OFP11_VERSION: {
+ const struct ofp11_queue_stats_request *qsr11 = ofpmsg_body(request);
+ oqsr->queue_id = ntohl(qsr11->queue_id);
+ return ofputil_port_from_ofp11(qsr11->port_no, &oqsr->port_no);
+ }
+
+ case OFP10_VERSION: {
+ const struct ofp10_queue_stats_request *qsr11 = ofpmsg_body(request);
+ oqsr->queue_id = ntohl(qsr11->queue_id);
+ oqsr->port_no = ntohs(qsr11->port_no);
+ return 0;
+ }
+
+ default:
+ NOT_REACHED();
+ }
+}
+
+/* Encode a queue statsrequest for 'oqsr', the encoded message
+ * will be fore Open Flow version 'ofp_version'. Returns message
+ * as a struct ofpbuf. Returns encoded message on success, NULL on error */
+struct ofpbuf *
+ofputil_encode_queue_stats_request(enum ofp_version ofp_version,
+ const struct ofputil_queue_stats_request *oqsr)
+{
+ struct ofpbuf *request;
+
+ switch (ofp_version) {
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
+ struct ofp11_queue_stats_request *req;
+ request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
+ req = ofpbuf_put_zeros(request, sizeof *req);
+ req->port_no = ofputil_port_to_ofp11(oqsr->port_no);
+ req->queue_id = htonl(oqsr->queue_id);
+ break;
+ }
+ case OFP10_VERSION: {
+ struct ofp10_queue_stats_request *req;
+ request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, ofp_version, 0);
+ req = ofpbuf_put_zeros(request, sizeof *req);
+ req->port_no = htons(oqsr->port_no);
+ req->queue_id = htonl(oqsr->queue_id);
+ break;
+ }
+ default:
+ NOT_REACHED();
+ }
+
+ return request;
+}
+
+/* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
+ * message 'oh'. */
+size_t
+ofputil_count_queue_stats(const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpraw_pull_assert(&b);
+
+ BUILD_ASSERT(sizeof(struct ofp10_queue_stats) ==
+ sizeof(struct ofp11_queue_stats));
+ return b.size / sizeof(struct ofp10_queue_stats);
+}
+
+static enum ofperr
+ofputil_queue_stats_from_ofp10(struct ofputil_queue_stats *oqs,
+ const struct ofp10_queue_stats *qs10)
+{
+ oqs->port_no = ntohs(qs10->port_no);
+ oqs->queue_id = ntohl(qs10->queue_id);
+ oqs->stats.tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
+ oqs->stats.tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
+ oqs->stats.tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
+
+ return 0;
+}
+
+static enum ofperr
+ofputil_queue_stats_from_ofp11(struct ofputil_queue_stats *oqs,
+ const struct ofp11_queue_stats *qs11)
+{
+ enum ofperr error;
+
+ error = ofputil_port_from_ofp11(qs11->port_no, &oqs->port_no);
+ if (error) {
+ return error;
+ }
+
+ oqs->queue_id = ntohl(qs11->queue_id);
+ oqs->stats.tx_bytes = ntohll(qs11->tx_bytes);
+ oqs->stats.tx_packets = ntohll(qs11->tx_packets);
+ oqs->stats.tx_errors = ntohll(qs11->tx_errors);
+
+ return 0;
+}
+
+/* Converts an OFPST_QUEUE_STATS reply in 'msg' into an abstract
+ * ofputil_queue_stats in 'qs'.
+ *
+ * Multiple OFPST_QUEUE_STATS replies can be packed into a single OpenFlow
+ * message. Calling this function multiple times for a single 'msg' iterates
+ * through the replies. The caller must initially leave 'msg''s layer pointers
+ * null and not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no replies were left in this 'msg',
+ * otherwise a positive errno value. */
+int
+ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
+{
+ enum ofperr error;
+ enum ofpraw raw;
+
+ error = (msg->l2
+ ? ofpraw_decode(&raw, msg->l2)
+ : ofpraw_pull(&raw, msg));
+ if (error) {
+ return error;
+ }
+
+ if (!msg->size) {
+ return EOF;
+ } else if (raw == OFPRAW_OFPST11_QUEUE_REPLY) {
+ const struct ofp11_queue_stats *qs11;
+
+ qs11 = ofpbuf_try_pull(msg, sizeof *qs11);
+ if (!qs11) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
+ "bytes at end", msg->size);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ return ofputil_queue_stats_from_ofp11(qs, qs11);
+ } else if (raw == OFPRAW_OFPST10_QUEUE_REPLY) {
+ const struct ofp10_queue_stats *qs10;
+
+ qs10 = ofpbuf_try_pull(msg, sizeof *qs10);
+ if (!qs10) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
+ "bytes at end", msg->size);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ return ofputil_queue_stats_from_ofp10(qs, qs10);
+ } else {
+ NOT_REACHED();
+ }
+}
+
+static void
+ofputil_queue_stats_to_ofp10(const struct ofputil_queue_stats *oqs,
+ struct ofp10_queue_stats *qs10)
+{
+ qs10->port_no = htons(oqs->port_no);
+ memset(qs10->pad, 0, sizeof qs10->pad);
+ qs10->queue_id = htonl(oqs->queue_id);
+ put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->stats.tx_bytes));
+ put_32aligned_be64(&qs10->tx_packets, htonll(oqs->stats.tx_packets));
+ put_32aligned_be64(&qs10->tx_errors, htonll(oqs->stats.tx_errors));
+}
+
+static void
+ofputil_queue_stats_to_ofp11(const struct ofputil_queue_stats *oqs,
+ struct ofp11_queue_stats *qs11)
+{
+ qs11->port_no = ofputil_port_to_ofp11(oqs->port_no);
+ qs11->queue_id = htonl(oqs->queue_id);
+ qs11->tx_bytes = htonll(oqs->stats.tx_bytes);
+ qs11->tx_packets = htonll(oqs->stats.tx_packets);
+ qs11->tx_errors = htonll(oqs->stats.tx_errors);
+}
+
+/* Encode a queue stat for 'oqs' and append it to 'replies'. */
+void
+ofputil_append_queue_stat(struct list *replies,
+ const struct ofputil_queue_stats *oqs)
+{
+ struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+ struct ofp_header *oh = msg->data;
+
+ switch ((enum ofp_version)oh->version) {
+ case OFP12_VERSION:
+ case OFP11_VERSION: {
+ struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
+ ofputil_queue_stats_to_ofp11(oqs, reply);
+ break;
+ }
+
+ case OFP10_VERSION: {
+ struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
+ ofputil_queue_stats_to_ofp10(oqs, reply);
+ break;
+ }
+
+ default:
+ NOT_REACHED();
+ }
+}
int ofputil_decode_port_stats(struct ofputil_port_stats *, struct ofpbuf *msg);
enum ofperr ofputil_decode_port_stats_request(const struct ofp_header *request,
uint16_t *ofp10_port);
+
+struct ofputil_queue_stats_request {
+ uint16_t port_no;
+ uint32_t queue_id;
+};
+
+enum ofperr
+ofputil_decode_queue_stats_request(const struct ofp_header *request,
+ struct ofputil_queue_stats_request *oqsr);
+struct ofpbuf *
+ofputil_encode_queue_stats_request(enum ofp_version ofp_version,
+ const struct ofputil_queue_stats_request *oqsr);
+
+struct ofputil_queue_stats {
+ uint16_t port_no;
+ uint32_t queue_id;
+ struct netdev_queue_stats stats;
+};
+
+size_t ofputil_count_queue_stats(const struct ofp_header *);
+int ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg);
+void ofputil_append_queue_stat(struct list *replies,
+ const struct ofputil_queue_stats *oqs);
+
#endif /* ofp-util.h */
put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
const struct netdev_queue_stats *stats)
{
- struct ofp10_queue_stats *reply;
- reply = ofpmp_append(&cbdata->replies, sizeof *reply);
- reply->port_no = htons(cbdata->ofport->pp.port_no);
- memset(reply->pad, 0, sizeof reply->pad);
- reply->queue_id = htonl(queue_id);
- put_32aligned_be64(&reply->tx_bytes, htonll(stats->tx_bytes));
- put_32aligned_be64(&reply->tx_packets, htonll(stats->tx_packets));
- put_32aligned_be64(&reply->tx_errors, htonll(stats->tx_errors));
+ struct ofputil_queue_stats oqs = {
+ .port_no = cbdata->ofport->pp.port_no,
+ .queue_id = queue_id,
+ .stats = *stats,
+ };
+ ofputil_append_queue_stat(&cbdata->replies, &oqs);
}
static void
const struct ofp_header *rq)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- const struct ofp10_queue_stats_request *qsr = ofpmsg_body(rq);
struct queue_stats_cbdata cbdata;
- unsigned int port_no;
struct ofport *port;
- uint32_t queue_id;
enum ofperr error;
+ struct ofputil_queue_stats_request oqsr;
COVERAGE_INC(ofproto_queue_req);
ofpmp_init(&cbdata.replies, rq);
- port_no = ntohs(qsr->port_no);
- queue_id = ntohl(qsr->queue_id);
- if (port_no == OFPP_ALL) {
+ error = ofputil_decode_queue_stats_request(rq, &oqsr);
+ if (error) {
+ return error;
+ }
+
+ if (oqsr.port_no == OFPP_ALL) {
error = OFPERR_OFPQOFC_BAD_QUEUE;
HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
- if (!handle_queue_stats_for_port(port, queue_id, &cbdata)) {
+ if (!handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)) {
error = 0;
}
}
} else {
- port = ofproto_get_port(ofproto, port_no);
+ port = ofproto_get_port(ofproto, oqsr.port_no);
error = (port
- ? handle_queue_stats_for_port(port, queue_id, &cbdata)
+ ? handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)
: OFPERR_OFPQOFC_BAD_PORT);
}
if (!error) {
])
AT_CLEANUP
-AT_SETUP([OFPST_QUEUE request])
+AT_SETUP([OFPST_QUEUE request - OF1.0])
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
AT_CHECK([ovs-ofctl ofp-print "\
01 10 00 14 00 00 00 01 00 05 00 00 ff fc 00 00 \
])
AT_CLEANUP
-AT_SETUP([OFPST_QUEUE reply])
+AT_SETUP([OFPST_QUEUE request - OF1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 12 00 18 00 00 00 02 00 05 00 00 00 00 00 00 \
+ff ff ff fc ff ff ff ff \
+"], [0], [dnl
+OFPST_QUEUE request (OF1.1) (xid=0x2):port=ALL queue=ALL
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE request - OF1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 12 00 18 00 00 00 02 00 05 00 00 00 00 00 00 \
+ff ff ff fc ff ff ff ff \
+"], [0], [dnl
+OFPST_QUEUE request (OF1.2) (xid=0x2):port=ALL queue=ALL
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE reply - OF1.0])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
AT_CHECK([ovs-ofctl ofp-print "\
01 11 00 cc 00 00 00 01 00 05 00 00 00 03 00 00 \
])
AT_CLEANUP
+AT_SETUP([OFPST_QUEUE reply - OF1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 13 00 d0 00 00 00 01 00 05 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 01 00 00 00 00 00 00 01 2e \
+00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 01 00 00 00 00 00 00 08 34 \
+00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_QUEUE reply (OF1.1) (xid=0x1): 6 queues
+ port 3 queue 1: bytes=302, pkts=1, errors=0
+ port 3 queue 2: bytes=0, pkts=0, errors=0
+ port 2 queue 1: bytes=2100, pkts=20, errors=0
+ port 2 queue 2: bytes=0, pkts=0, errors=0
+ port 1 queue 1: bytes=0, pkts=0, errors=0
+ port 1 queue 2: bytes=0, pkts=0, errors=0
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE reply - OF1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 13 00 d0 00 00 00 01 00 05 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 01 00 00 00 00 00 00 01 2e \
+00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 01 00 00 00 00 00 00 08 34 \
+00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_QUEUE reply (OF1.2) (xid=0x1): 6 queues
+ port 3 queue 1: bytes=302, pkts=1, errors=0
+ port 3 queue 2: bytes=0, pkts=0, errors=0
+ port 2 queue 1: bytes=2100, pkts=20, errors=0
+ port 2 queue 2: bytes=0, pkts=0, errors=0
+ port 1 queue 1: bytes=0, pkts=0, errors=0
+ port 1 queue 2: bytes=0, pkts=0, errors=0
+])
+AT_CLEANUP
+
AT_SETUP([OFPST_PORT_DESC reply - OF1.0])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
AT_CHECK([ovs-ofctl ofp-print "\
static void
ofctl_queue_stats(int argc, char *argv[])
{
- struct ofp10_queue_stats_request *req;
struct ofpbuf *request;
struct vconn *vconn;
+ struct ofputil_queue_stats_request oqs;
open_vconn(argv[1], &vconn);
- request = ofpraw_alloc(OFPRAW_OFPST_QUEUE_REQUEST,
- vconn_get_version(vconn), 0);
- req = ofpbuf_put_zeros(request, sizeof *req);
if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
- req->port_no = htons(str_to_port_no(argv[1], argv[2]));
+ oqs.port_no = str_to_port_no(argv[1], argv[2]);
} else {
- req->port_no = htons(OFPP_ALL);
+ oqs.port_no = OFPP_ALL;
}
if (argc > 3 && argv[3][0] && strcasecmp(argv[3], "all")) {
- req->queue_id = htonl(atoi(argv[3]));
+ oqs.queue_id = atoi(argv[3]);
} else {
- req->queue_id = htonl(OFPQ_ALL);
+ oqs.queue_id = OFPQ_ALL;
}
- memset(req->pad, 0, sizeof req->pad);
-
+ request = ofputil_encode_queue_stats_request(vconn_get_version(vconn), &oqs);
dump_stats_transaction(vconn, request);
vconn_close(vconn);
}