This allows for encoding and decoding Open Flow 1.1 and 1.2 Queue Stats Request and Reply messages.
Signed-off-by: Simon Horman <ho...@verge.net.au> --- v14 * No change v13 * Merged the following patches - ofp-msgs: Split OFPRAW_OFPST_QUEUE_{REQUEST,REPLY} - ofp-print: Enable display of Open Flow 1.1 & 1.2 Queue Status Reply Messages - ofp-util: Allow encoding of Open Flow 1.1 & 1.2 Queue Stats Reply Messages - ofp-util: Allow decoding of Open Flow 1.1 & 1.2 Queue Stats Request Messages - ovs-print: Enable display of Open Flow 1.1 & 1.2 Queue Stats Request * Move ofp_print_ofpst_queue_reply() decode code into a helper function * Move put_queue_stats() encode code into helper functions * Move ofp_print_ofpst_queue_request parse code to helper functions * Merged revision history of above patches follows v12 * No change v11 * No change v10 * Manual rebase * Make use of enum ofp_version * Change subject name from "ovs-print: Enable display of Open Flow 1.1 & 1.2 Queue Stats Response" to "ovs-print: Enable display of Open Flow 1.1 & 1.2 Queue Stats Request" * Add ofp-print test * Use ofputil_port_from_ofp11 to decode port number v9 * Omitted v8 * Omitted v7 * Omitted v6 * No change v5 * Initial Post --- lib/ofp-msgs.h | 14 +++-- lib/ofp-print.c | 41 +++++++++----- lib/ofp-util.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/ofp-util.h | 11 ++++ ofproto/ofproto.c | 36 +++++++++---- tests/ofp-print.at | 78 ++++++++++++++++++++++++++- utilities/ovs-ofctl.c | 2 +- 7 files changed, 294 insertions(+), 32 deletions(-) diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h index 6420c5d..ceb3fc3 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -226,10 +226,14 @@ enum ofpraw { 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, @@ -390,8 +394,10 @@ enum ofptype { * 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_OFPST_PORT_DESC_REPLY. */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 25aa9b9..8166ab1 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1077,12 +1077,6 @@ static void ofp_print_port_stat(struct ds *string, const char *leader, } } -static void print_port_stat(struct ds *string, const char *leader, - const ovs_32aligned_be64 *statp, int more) -{ - ofp_print_port_stat(string, leader, get_32aligned_be64(statp), more); -} - static void ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh) { @@ -1325,10 +1319,18 @@ ofp_print_queue_name(struct ds *string, uint32_t queue_id) 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); + uint16_t port_no; + const struct ofp11_queue_stats_request *qsr; + struct ofp11_queue_stats_request qsr_storage; + + qsr = ofptutil_decode_queue_stat_request(oh, &qsr_storage); + if (ofputil_port_from_ofp11(qsr->port_no, &port_no)) { + ds_put_cstr(string, "*** parse error: invalid port ***\n"); + return; + } ds_put_cstr(string, "port="); - ofputil_format_port(ntohs(qsr->port_no), string); + ofputil_format_port(port_no, string); ds_put_cstr(string, " queue="); ofp_print_queue_name(string, ntohl(qsr->queue_id)); @@ -1338,13 +1340,16 @@ static void ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh, int verbosity) { - struct ofp10_queue_stats *qs; + const struct ofp11_queue_stats *qs; struct ofpbuf b; size_t n; ofpbuf_use_const(&b, oh, ntohs(oh->length)); ofpraw_pull_assert(&b); + /* This calculation is correct because + * struct ofp10_queue_stats and struct ofp11_queue_stats + * are the same size. */ n = b.size / sizeof *qs; ds_put_format(string, " %zu queues\n", n); if (verbosity < 1) { @@ -1352,20 +1357,28 @@ ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh, } for (;;) { - qs = ofpbuf_try_pull(&b, sizeof *qs); + struct ofp11_queue_stats qs_storage; + uint16_t port_no; + enum ofperr error; + + qs = ofptutil_decode_queue_stat(oh->version, &b, &qs_storage); if (!qs) { return; } + error = ofputil_port_from_ofp11(qs->port_no, &port_no); + if (error) { + return; + } ds_put_cstr(string, " port "); - ofputil_format_port(ntohs(qs->port_no), string); + ofputil_format_port(port_no, string); ds_put_cstr(string, " queue "); ofp_print_queue_name(string, ntohl(qs->queue_id)); ds_put_cstr(string, ": "); - print_port_stat(string, "bytes=", &qs->tx_bytes, 1); - print_port_stat(string, "pkts=", &qs->tx_packets, 1); - print_port_stat(string, "errors=", &qs->tx_errors, 0); + ofp_print_port_stat(string, "bytes=", qs->tx_bytes, 1); + ofp_print_port_stat(string, "pkts=", qs->tx_packets, 1); + ofp_print_port_stat(string, "errors=", qs->tx_errors, 0); } } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index e3c4d42..18f749a 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -4147,3 +4147,147 @@ ofptutil_decode_port_stats_request(const struct ofp_header *request) NOT_REACHED(); } } + +/* Convert a struct ofp10_queue_stats to a struct ofp11_queue_stats. + * The latter may be used as a neutral format as is able to + * encode both ofp*_queue_stats variants. */ +static void +oqs10_to_oqs11(const struct ofp10_queue_stats *in, + struct ofp11_queue_stats *out) +{ + out->port_no = ofputil_port_to_ofp11(ntohs(in->port_no)); + out->queue_id = in->queue_id; + out->tx_bytes = get_32aligned_be64(&in->tx_bytes); + out->tx_packets = get_32aligned_be64(&in->tx_packets); + out->tx_errors = get_32aligned_be64(&in->tx_errors); +} + +/* Convert a struct ofp11_queue_stats to a struct ofp10_queue_stats. + * The former may be used as a neutral format as is able to + * encode both ofp*_queue_stats variants. + * Returns 0 success, an enum ofperr on error */ +static enum ofperr +oqs11_to_oqs10(const struct ofp11_queue_stats *in, + struct ofp10_queue_stats *out) +{ + enum ofperr error; + uint16_t ofp10_port; + + error = ofputil_port_from_ofp11(in->port_no, &ofp10_port); + if (error) { + return error; + } + out->port_no = htons(ofp10_port); + memset(out->pad, 0, sizeof out->pad); + out->queue_id = in->queue_id; + put_32aligned_be64(&out->tx_bytes, in->tx_bytes); + put_32aligned_be64(&out->tx_packets, in->tx_packets); + put_32aligned_be64(&out->tx_errors, in->tx_errors); + return 0; +} + +/* Parse a struct one element of a port status reply message into a struct + * ofp11_queue_stats. struct ofp11_queue_stats is used as a neutral format + * as is able to encode both ofp*_queue_stats variants. qs_storage shuold + * point to memory for a struct ofp11_queue_stats. Returns pointer to + * struct ofp11_queue_stats on success, NULL otherwise. */ +const struct ofp11_queue_stats * +ofptutil_decode_queue_stat(enum ofp_version ofp_version, + struct ofpbuf *openflow, + struct ofp11_queue_stats *qs_storage) +{ + switch (ofp_version) { + case OFP12_VERSION: + case OFP11_VERSION: + return ofpbuf_try_pull(openflow, sizeof *qs_storage); + + case OFP10_VERSION: { + struct ofp10_queue_stats *qs10; + + qs10 = ofpbuf_try_pull(openflow, sizeof *qs10); + if (!qs10) { + return NULL; + } + oqs10_to_oqs11(qs10, qs_storage); + return qs_storage; + } + + default: + NOT_REACHED(); + } +} + +/* Encode a queue status 'oqs' and append to to 'replies' + * The encoded message will be fore Open Flow version 'ofp_version'. + * Returns 0 success, an enum ofperr on error */ +enum ofperr +ofputil_append_queue_stat(struct list *replies, + struct ofp11_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; + + reply = ofpmp_append(replies, sizeof *reply); + memcpy(reply, &oqs, sizeof reply); + break; + } + + case OFP10_VERSION: { + struct ofp10_queue_stats *reply; + + reply = ofpmp_append(replies, sizeof *reply); + return oqs11_to_oqs10(oqs, reply); + } + + default: + NOT_REACHED(); + } + + return 0; +} + +/* Convert a struct ofp10_queue_stats_request to a struct + * ofp11_queue_stats_request. + * The latter may be used as a neutral format as is able to + * encode both ofp*_queue_stats_request variants. */ +static void +oqsr10_to_oqsr11(const struct ofp10_queue_stats_request *in, + struct ofp11_queue_stats_request *out) +{ + out->port_no = ofputil_port_to_ofp11(ntohs(in->port_no)); + out->queue_id = in->queue_id; +} + +/* Parse a struct one element of a port status request message into a + * struct ofp11_queue_stats_request. struct ofp11_queue_stats_request is + * used as a neutral format as is able to encode both + * ofp*_queue_stats_request variants. qsr_storage shuold point to memory + * for a struct ofp11_queue_stats_request. Returns pointer to struct + * ofp11_queue_stats_request on success, NULL otherwise. */ +const struct ofp11_queue_stats_request * +ofptutil_decode_queue_stat_request(const struct ofp_header *oh, + struct ofp11_queue_stats_request + *qsr_storage) +{ + switch ((enum ofp_version)oh->version) { + case OFP12_VERSION: + case OFP11_VERSION: + return ofpmsg_body(oh); + + case OFP10_VERSION: { + const struct ofp10_queue_stats_request *qsr10; + + qsr10 = ofpmsg_body(oh);; + oqsr10_to_oqsr11(qsr10, qsr_storage); + return qsr_storage; + } + + default: + NOT_REACHED(); + } +} diff --git a/lib/ofp-util.h b/lib/ofp-util.h index f28d0a3..f91bccf 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -633,4 +633,15 @@ ofptutil_decode_one_port_reply(enum ofp_version ofp_version, struct ofpbuf *openflow, struct ofp11_port_stats *ps_storage); ovs_be32 ofptutil_decode_port_stats_request(const struct ofp_header *request); + +const struct ofp11_queue_stats * +ofptutil_decode_queue_stat(enum ofp_version ofp_version, + struct ofpbuf *openflow, + struct ofp11_queue_stats *qs_storage); +enum ofperr ofputil_append_queue_stat(struct list *replies, + struct ofp11_queue_stats *ofqs11); +const struct ofp11_queue_stats_request * +ofptutil_decode_queue_stat_request(const struct ofp_header *oh, + struct ofp11_queue_stats_request + *qsr_storage); #endif /* ofp-util.h */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index cf7be02..d328818 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2790,6 +2790,18 @@ handle_aggregate_stats_request(struct ofconn *ofconn, return 0; } +static void +collate_queue_stat(uint16_t port_no, uint32_t queue_id, + const struct netdev_queue_stats *stats, + struct ofp11_queue_stats *reply) +{ + reply->port_no = htonl(port_no); + reply->queue_id = htonl(queue_id); + reply->tx_bytes = htonll(stats->tx_bytes); + reply->tx_packets = htonll(stats->tx_packets); + reply->tx_errors = htonll(stats->tx_errors); +} + struct queue_stats_cbdata { struct ofport *ofport; struct list replies; @@ -2799,15 +2811,11 @@ static void 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 ofp11_queue_stats ofqs11; + + collate_queue_stat(cbdata->ofport->pp.port_no, queue_id, stats, &ofqs11); + assert(!ofputil_append_queue_stat(&cbdata->replies, &ofqs11)); } static void @@ -2845,19 +2853,25 @@ handle_queue_stats_request(struct ofconn *ofconn, 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; + uint16_t port_no; struct ofport *port; uint32_t queue_id; enum ofperr error; + const struct ofp11_queue_stats_request *qsr; + struct ofp11_queue_stats_request qsr_storage; COVERAGE_INC(ofproto_queue_req); ofpmp_init(&cbdata.replies, rq); - port_no = ntohs(qsr->port_no); + qsr = ofptutil_decode_queue_stat_request(rq, &qsr_storage); + error = ofputil_port_from_ofp11(qsr->port_no, &port_no); + if (error) { + return error; + } queue_id = ntohl(qsr->queue_id); + if (port_no == OFPP_ALL) { error = OFPERR_OFPQOFC_BAD_QUEUE; HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { diff --git a/tests/ofp-print.at b/tests/ofp-print.at index f214aa8..7c4604d 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -993,7 +993,7 @@ OFPST_PORT reply (OF1.2) (xid=0x2): 3 ports ]) 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 \ @@ -1003,7 +1003,27 @@ OFPST_QUEUE request (xid=0x1):port=ALL queue=ALL ]) 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 \ @@ -1037,6 +1057,60 @@ OFPST_PORT_DESC request (xid=0x1): ]) 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 "\ diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 0bfdd02..b11ef38 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -953,7 +953,7 @@ ofctl_queue_stats(int argc, char *argv[]) struct vconn *vconn; open_vconn(argv[1], &vconn); - request = ofpraw_alloc(OFPRAW_OFPST_QUEUE_REQUEST, + request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, vconn_get_version(vconn), 0); req = ofpbuf_put_zeros(request, sizeof *req); -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev