[ovs-dev] [PATCH v2 2/2] Implement OFPT_QUEUE_GET_CONFIG_REQUEST and OFPT_QUEUE_GET_CONFIG_REPLY.
Joe Stringer
joestringer at nicira.com
Fri Oct 25 22:02:00 UTC 2013
On Fri, Oct 25, 2013 at 1:12 PM, Ben Pfaff <blp at nicira.com> wrote:
> From: Venkitachalam Gopalakrishnan <gops at vmware.com>
>
> Open vSwitch has never implemented this request and reply, even though they
> have been in OpenFlow since version 1.0. This commit adds an
> implementation.
>
> Signed-off: Venkitachalam Gopalakrishnan <gops at vmware.com>
> Co-authored-by: Ben Pfaff <blp at nicira.com>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
> include/openflow/openflow-1.0.h | 11 +-
> include/openflow/openflow-1.2.h | 15 +-
> include/openflow/openflow-common.h | 23 +--
> lib/ofp-msgs.h | 12 +-
> lib/ofp-print.c | 75 +++++++++-
> lib/ofp-util.c | 277
> ++++++++++++++++++++++++++++++++++++
> lib/ofp-util.h | 29 ++++
> ofproto/ofproto.c | 49 ++++++-
> tests/ofp-print.at | 44 ++++++
> tests/ofproto.at | 30 ++++
> utilities/ovs-ofctl.c | 22 +++
> 11 files changed, 556 insertions(+), 31 deletions(-)
>
> diff --git a/include/openflow/openflow-1.0.h
> b/include/openflow/openflow-1.0.h
> index 34d97c4..002c75d 100644
> --- a/include/openflow/openflow-1.0.h
> +++ b/include/openflow/openflow-1.0.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -128,6 +128,15 @@ struct ofp10_port_mod {
> };
> OFP_ASSERT(sizeof(struct ofp10_port_mod) == 24);
>
> +struct ofp10_packet_queue {
> + ovs_be32 queue_id; /* id for the specific queue. */
> + ovs_be16 len; /* Length in bytes of this queue desc. */
> + uint8_t pad[2]; /* 64-bit alignment. */
> + /* Followed by any number of queue properties expressed using
> + * ofp_queue_prop_header, to fill out a total of 'len' bytes. */
> +};
> +OFP_ASSERT(sizeof(struct ofp10_packet_queue) == 8);
> +
> /* Query for port queue configuration. */
> struct ofp10_queue_get_config_request {
> ovs_be16 port; /* Port to be queried. Should refer
> diff --git a/include/openflow/openflow-1.2.h
> b/include/openflow/openflow-1.2.h
> index 249e861..694cd55 100644
> --- a/include/openflow/openflow-1.2.h
> +++ b/include/openflow/openflow-1.2.h
> @@ -251,13 +251,16 @@ enum ofp12_capabilities {
> OFPC12_PORT_BLOCKED = 1 << 8 /* Switch will block looping ports.
> */
> };
>
> -/* OpenFlow 1.2 specific properties
> - * (struct ofp_queue_prop_header member property). */
> -enum ofp12_queue_properties {
> - OFPQT12_MIN_RATE = 1, /* Minimum datarate guaranteed. */
> - OFPQT12_MAX_RATE = 2, /* Maximum datarate. */
> - OFPQT12_EXPERIMENTER = 0xffff /* Experimenter defined property. */
> +/* Full description for a queue. */
> +struct ofp12_packet_queue {
> + ovs_be32 queue_id; /* id for the specific queue. */
> + ovs_be32 port; /* Port this queue is attached to. */
> + ovs_be16 len; /* Length in bytes of this queue desc. */
> + uint8_t pad[6]; /* 64-bit alignment. */
> + /* Followed by any number of queue properties expressed using
> + * ofp_queue_prop_header, to fill out a total of 'len' bytes. */
> };
> +OFP_ASSERT(sizeof(struct ofp12_packet_queue) == 16);
>
> /* Body of reply to OFPST_TABLE request. */
> struct ofp12_table_stats {
> diff --git a/include/openflow/openflow-common.h
> b/include/openflow/openflow-common.h
> index 45d03ef..930848e 100644
> --- a/include/openflow/openflow-common.h
> +++ b/include/openflow/openflow-common.h
> @@ -204,19 +204,9 @@ enum ofp_port_features {
> OFPPF_10GB_FD = 1 << 6, /* 10 Gb full-duplex rate support. */
> };
>
> -struct ofp_packet_queue {
> - ovs_be32 queue_id; /* id for the specific queue. */
> - ovs_be16 len; /* Length in bytes of this queue desc. */
> - uint8_t pad[2]; /* 64-bit alignment. */
> - /* struct ofp_queue_prop_header properties[0]; List of properties. */
> -};
> -OFP_ASSERT(sizeof(struct ofp_packet_queue) == 8);
> -
> enum ofp_queue_properties {
> - OFPQT_NONE = 0, /* No property defined for queue (default). */
> - OFPQT_MIN_RATE, /* Minimum datarate guaranteed. */
> - /* Other types should be added here
> - * (i.e. max rate, precedence, etc). */
> + OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */
> + OFPQT_MAX_RATE = 2, /* Maximum guaranteed rate. */
> };
Is there a particular reason why OFPQT_NONE and OFPQT_EXPERIMENTER are
dropped?
>
> /* Common description for a queue. */
> @@ -227,13 +217,14 @@ struct ofp_queue_prop_header {
> };
> OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8);
>
> -/* Min-Rate queue property description. */
> -struct ofp_queue_prop_min_rate {
> - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MIN, len:
> 16. */
> +/* Min-Rate and Max-Rate queue property description (OFPQT_MIN and
> + * OFPQT_MAX). */
> +struct ofp_queue_prop_rate {
> + struct ofp_queue_prop_header prop_header;
> ovs_be16 rate; /* In 1/10 of a percent; >1000 -> disabled. */
> uint8_t pad[6]; /* 64-bit alignment */
> };
> -OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16);
> +OFP_ASSERT(sizeof(struct ofp_queue_prop_rate) == 16);
>
> /* Switch features. */
> struct ofp_switch_features {
> diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
> index aa19fe3..4d40c1f 100644
> --- a/lib/ofp-msgs.h
> +++ b/lib/ofp-msgs.h
> @@ -198,10 +198,14 @@ enum ofpraw {
> /* OFPT 1.1+ (21): void. */
> OFPRAW_OFPT11_BARRIER_REPLY,
>
> + /* OFPT 1.0 (22): struct ofp10_queue_get_config_request. */
> + OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST,
> /* OFPT 1.1+ (22): struct ofp11_queue_get_config_request. */
> OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST,
>
> - /* OFPT 1.1+ (23): struct ofp11_queue_get_config_reply, struct
> ofp_packet_queue[]. */
> + /* OFPT 1.0 (23): struct ofp10_queue_get_config_reply, uint8_t[8][].
> */
> + OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY,
> + /* OFPT 1.1+ (23): struct ofp11_queue_get_config_reply, uint8_t[8][].
> */
> OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY,
>
> /* OFPT 1.2+ (24): struct ofp12_role_request. */
> @@ -478,8 +482,10 @@ enum ofptype {
> * OFPRAW_OFPT11_BARRIER_REPLY. */
>
> /* Queue Configuration messages. */
> - OFPTYPE_QUEUE_GET_CONFIG_REQUEST, /*
> OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST. */
> - OFPTYPE_QUEUE_GET_CONFIG_REPLY, /*
> OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY. */
> + OFPTYPE_QUEUE_GET_CONFIG_REQUEST, /*
> OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST.
> + *
> OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST. */
> + OFPTYPE_QUEUE_GET_CONFIG_REPLY, /*
> OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY.
> + *
> OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY. */
>
> /* Controller role change request messages. */
> OFPTYPE_ROLE_REQUEST, /* OFPRAW_OFPT12_ROLE_REQUEST.
> diff --git a/lib/ofp-print.c b/lib/ofp-print.c
> index e4d0303..8bbb471 100644
> --- a/lib/ofp-print.c
> +++ b/lib/ofp-print.c
> @@ -1009,6 +1009,71 @@ ofp_print_table_mod(struct ds *string, const struct
> ofp_header *oh)
> }
>
> static void
> +ofp_print_queue_get_config_request(struct ds *string,
> + const struct ofp_header *oh)
> +{
> + enum ofperr error;
> + ofp_port_t port;
> +
> + error = ofputil_decode_queue_get_config_request(oh, &port);
> + if (error) {
> + ofp_print_error(string, error);
> + return;
> + }
> +
> + ds_put_cstr(string, " port=");
> + ofputil_format_port(port, string);
> +}
> +
> +static void
> +print_queue_rate(struct ds *string, const char *name, unsigned int rate)
> +{
> + if (rate <= 1000) {
> + ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
> + } else if (rate < UINT16_MAX) {
> + ds_put_format(string, " %s:(disabled)", name);
> + }
> +}
> +
> +static void
> +ofp_print_queue_get_config_reply(struct ds *string,
> + const struct ofp_header *oh)
> +{
> + enum ofperr error;
> + struct ofpbuf b;
> + ofp_port_t port;
> +
> + ofpbuf_use_const(&b, oh, ntohs(oh->length));
> + error = ofputil_decode_queue_get_config_reply(&b, &port);
> + if (error) {
> + ofp_print_error(string, error);
> + return;
> + }
> +
> + ds_put_cstr(string, " port=");
> + ofputil_format_port(port, string);
> + ds_put_char(string, '\n');
> +
> + for (;;) {
> + struct ofputil_queue_config queue;
> + int retval;
> +
> + retval = ofputil_pull_queue_get_config_reply(&b, &queue);
> + if (retval) {
> + if (retval != EOF) {
> + ofp_print_error(string, retval);
> + }
> + break;
> + }
> +
> + ds_put_format(string, "queue %"PRIu32":", queue.queue_id);
> + print_queue_rate(string, "min_rate", queue.min_rate);
> + print_queue_rate(string, "max_rate", queue.max_rate);
> + ds_put_char(string, '\n');
> + }
> +}
> +
> +static void
> ofp_print_meter_flags(struct ds *s, uint16_t flags)
> {
> if (flags & OFPMF13_KBPS) {
> @@ -2419,8 +2484,6 @@ ofp_to_string__(const struct ofp_header *oh, enum
> ofpraw raw,
> ofp_print_group_mod(string, oh);
> break;
>
> - case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
> - case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
> case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
> case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
> ofp_print_not_implemented(string);
> @@ -2490,6 +2553,14 @@ ofp_to_string__(const struct ofp_header *oh, enum
> ofpraw raw,
> case OFPTYPE_BARRIER_REPLY:
> break;
>
> + case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
> + ofp_print_queue_get_config_request(string, oh);
> + break;
> +
> + case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
> + ofp_print_queue_get_config_reply(string, oh);
> + break;
> +
> case OFPTYPE_ROLE_REQUEST:
> case OFPTYPE_ROLE_REPLY:
> ofp_print_role_message(string, oh);
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index 8c200ce..9550c2b 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -2186,6 +2186,283 @@ ofputil_decode_nxst_flow_request(struct
> ofputil_flow_stats_request *fsr,
> return 0;
> }
>
> +/* Constructs and returns an OFPT_QUEUE_GET_CONFIG request for the
> specified
> + * 'port', suitable for OpenFlow version 'version'. */
> +struct ofpbuf *
> +ofputil_encode_queue_get_config_request(enum ofp_version version,
> + ofp_port_t port)
> +{
> + struct ofpbuf *request;
> +
> + if (version == OFP10_VERSION) {
> + struct ofp10_queue_get_config_request *qgcr10;
> +
> + request = ofpraw_alloc(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST,
> + version, 0);
> + qgcr10 = ofpbuf_put_zeros(request, sizeof *qgcr10);
> + qgcr10->port = htons(ofp_to_u16(port));
> + } else {
> + struct ofp11_queue_get_config_request *qgcr11;
> +
> + request = ofpraw_alloc(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST,
> + version, 0);
> + qgcr11 = ofpbuf_put_zeros(request, sizeof *qgcr11);
> + qgcr11->port = ofputil_port_to_ofp11(port);
> + }
> +
> + return request;
> +}
> +
> +/* Parses OFPT_QUEUE_GET_CONFIG request 'oh', storing the port specified
> by the
> + * request into '*port'. Returns 0 if successful, otherwise an OpenFlow
> error
> + * code. */
> +enum ofperr
> +ofputil_decode_queue_get_config_request(const struct ofp_header *oh,
> + ofp_port_t *port)
> +{
> + const struct ofp10_queue_get_config_request *qgcr10;
> + const struct ofp11_queue_get_config_request *qgcr11;
> + enum ofpraw raw;
> + struct ofpbuf b;
> +
> + ofpbuf_use_const(&b, oh, ntohs(oh->length));
> + raw = ofpraw_pull_assert(&b);
> +
> + switch ((int) raw) {
> + case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
> + qgcr10 = b.data;
> + *port = u16_to_ofp(ntohs(qgcr10->port));
> + return 0;
> +
> + case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
> + qgcr11 = b.data;
> + return ofputil_port_from_ofp11(qgcr11->port, port);
> + }
> +
> + NOT_REACHED();
> +}
> +
> +/* Constructs and returns the beginning of a reply to
> + * OFPT_QUEUE_GET_CONFIG_REQUEST 'oh'. The caller may append information
> about
> + * individual queues with ofputil_append_queue_get_config_reply(). */
> +struct ofpbuf *
> +ofputil_encode_queue_get_config_reply(const struct ofp_header *oh)
> +{
> + struct ofp10_queue_get_config_reply *qgcr10;
> + struct ofp11_queue_get_config_reply *qgcr11;
> + struct ofpbuf *reply;
> + enum ofperr error;
> + struct ofpbuf b;
> + enum ofpraw raw;
> + ofp_port_t port;
> +
> + error = ofputil_decode_queue_get_config_request(oh, &port);
> + ovs_assert(!error);
> +
> + ofpbuf_use_const(&b, oh, ntohs(oh->length));
> + raw = ofpraw_pull_assert(&b);
> +
> + switch ((int) raw) {
> + case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
> + reply = ofpraw_alloc_reply(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY,
> + oh, 0);
> + qgcr10 = ofpbuf_put_zeros(reply, sizeof *qgcr10);
> + qgcr10->port = htons(ofp_to_u16(port));
> + break;
> +
> + case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
> + reply = ofpraw_alloc_reply(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY,
> + oh, 0);
> + qgcr11 = ofpbuf_put_zeros(reply, sizeof *qgcr11);
> + qgcr11->port = ofputil_port_to_ofp11(port);
> + break;
> +
> + default:
> + NOT_REACHED();
> + }
> +
> + return reply;
> +}
> +
> +static void
> +put_queue_rate(struct ofpbuf *reply, enum ofp_queue_properties property,
> + uint16_t rate)
> +{
> + if (rate != UINT16_MAX) {
> + struct ofp_queue_prop_rate *oqpr;
> +
> + oqpr = ofpbuf_put_zeros(reply, sizeof *oqpr);
> + oqpr->prop_header.property = htons(property);
> + oqpr->prop_header.len = htons(sizeof *oqpr);
> + oqpr->rate = htons(rate);
> + }
> +}
> +
> +/* Appends a queue description for 'queue_id' to the
> + * OFPT_QUEUE_GET_CONFIG_REPLY already in 'oh'. */
> +void
> +ofputil_append_queue_get_config_reply(struct ofpbuf *reply,
> + const struct ofputil_queue_config
> *oqc)
> +{
> + const struct ofp_header *oh = reply->data;
> + size_t start_ofs, len_ofs;
> + ovs_be16 *len;
> +
> + start_ofs = reply->size;
> + if (oh->version < OFP12_VERSION) {
> + struct ofp10_packet_queue *opq10;
> +
> + opq10 = ofpbuf_put_zeros(reply, sizeof *opq10);
> + opq10->queue_id = htonl(oqc->queue_id);
> + len_ofs = (char *) &opq10->len - (char *) reply->data;
> + } else {
> + struct ofp11_queue_get_config_reply *qgcr11;
> + struct ofp12_packet_queue *opq12;
> + ovs_be32 port;
> +
> + qgcr11 = reply->l3;
> + port = qgcr11->port;
> +
> + opq12 = ofpbuf_put_zeros(reply, sizeof *opq12);
> + opq12->port = port;
> + opq12->queue_id = htonl(oqc->queue_id);
> + len_ofs = (char *) &opq12->len - (char *) reply->data;
> + }
> +
> + put_queue_rate(reply, OFPQT_MIN_RATE, oqc->min_rate);
> + put_queue_rate(reply, OFPQT_MAX_RATE, oqc->max_rate);
> +
> + len = ofpbuf_at(reply, len_ofs, sizeof *len);
> + *len = htons(reply->size - start_ofs);
> +}
> +
> +/* Decodes the initial part of an OFPT_QUEUE_GET_CONFIG_REPLY from
> 'reply' and
> + * stores in '*port' the port that the reply is about. The caller may
> call
> + * ofputil_pull_queue_get_config_reply() to obtain information about
> individual
> + * queues included in the reply. Returns 0 if successful, otherwise an
> + * ofperr.*/
> +enum ofperr
> +ofputil_decode_queue_get_config_reply(struct ofpbuf *reply, ofp_port_t
> *port)
> +{
> + const struct ofp10_queue_get_config_reply *qgcr10;
> + const struct ofp11_queue_get_config_reply *qgcr11;
> + enum ofpraw raw;
> +
> + raw = ofpraw_pull_assert(reply);
> + switch ((int) raw) {
> + case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY:
> + qgcr10 = ofpbuf_pull(reply, sizeof *qgcr10);
> + *port = u16_to_ofp(ntohs(qgcr10->port));
> + return 0;
> +
> + case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY:
> + qgcr11 = ofpbuf_pull(reply, sizeof *qgcr11);
> + return ofputil_port_from_ofp11(qgcr11->port, port);
> + }
> +
> + NOT_REACHED();
> +}
> +
> +static enum ofperr
> +parse_queue_rate(const struct ofp_queue_prop_header *hdr, uint16_t *rate)
> +{
> + const struct ofp_queue_prop_rate *oqpr;
> +
> + if (hdr->len == htons(sizeof *oqpr)) {
> + oqpr = (const struct ofp_queue_prop_rate *) hdr;
> + *rate = ntohs(oqpr->rate);
> + return 0;
> + } else {
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> +}
> +
> +/* Decodes information about a queue from the OFPT_QUEUE_GET_CONFIG_REPLY
> in
> + * 'reply' and stores it in '*queue'.
> ofputil_decode_queue_get_config_reply()
> + * must already have pulled off the main header.
> + *
> + * This function returns EOF if the last queue has already been decoded,
> 0 if a
> + * queue was successfully decoded into '*queue', or an ofperr if there
> was a
> + * problem decoding 'reply'. */
> +int
> +ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
> + struct ofputil_queue_config *queue)
> +{
> + const struct ofp_header *oh;
> + unsigned int opq_len;
> + unsigned int len;
> +
> + if (!reply->size) {
> + return EOF;
> + }
> +
> + queue->min_rate = UINT16_MAX;
> + queue->max_rate = UINT16_MAX;
> +
> + oh = reply->l2;
> + if (oh->version < OFP12_VERSION) {
> + const struct ofp10_packet_queue *opq10;
> +
> + opq10 = ofpbuf_try_pull(reply, sizeof *opq10);
> + if (!opq10) {
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> + queue->queue_id = ntohl(opq10->queue_id);
> + len = ntohs(opq10->len);
> + opq_len = sizeof *opq10;
> + } else {
> + const struct ofp12_packet_queue *opq12;
> +
> + opq12 = ofpbuf_try_pull(reply, sizeof *opq12);
> + if (!opq12) {
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> + queue->queue_id = ntohl(opq12->queue_id);
> + len = ntohs(opq12->len);
> + opq_len = sizeof *opq12;
> + }
> +
> + if (len < opq_len || len > reply->size + opq_len || len % 8) {
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> + len -= opq_len;
> +
> + while (len > 0) {
> + const struct ofp_queue_prop_header *hdr;
> + unsigned int property;
> + unsigned int prop_len;
> + enum ofperr error = 0;
> +
> + hdr = ofpbuf_at_assert(reply, 0, sizeof *hdr);
> + prop_len = ntohs(hdr->len);
> + if (prop_len < sizeof *hdr || prop_len > reply->size || prop_len
> % 8) {
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> +
> + property = ntohs(hdr->property);
> + switch (property) {
> + case OFPQT_MIN_RATE:
> + error = parse_queue_rate(hdr, &queue->min_rate);
> + break;
> +
> + case OFPQT_MAX_RATE:
> + error = parse_queue_rate(hdr, &queue->max_rate);
> + break;
> +
> + default:
> + VLOG_INFO_RL(&bad_ofmsg_rl, "unknown queue property %u",
> property);
> + break;
> + }
> + if (error) {
> + return error;
> + }
> +
> + ofpbuf_pull(reply, prop_len);
> + len -= prop_len;
> + }
> + return 0;
> +}
> +
> /* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE
> * request 'oh', into an abstract flow_stats_request in 'fsr'. Returns 0
> if
> * successful, otherwise an OpenFlow error code. */
> diff --git a/lib/ofp-util.h b/lib/ofp-util.h
> index 1f77808..a98ae93 100644
> --- a/lib/ofp-util.h
> +++ b/lib/ofp-util.h
> @@ -26,6 +26,7 @@
> #include "match.h"
> #include "netdev.h"
> #include "openflow/nicira-ext.h"
> +#include "openflow/openflow-1.1.h"
>
Is this needed?
> #include "openvswitch/types.h"
> #include "type-props.h"
>
> @@ -706,6 +707,34 @@ struct ofpbuf *ofputil_encode_table_stats_reply(
> const struct ofp12_table_stats[], int n,
> const struct ofp_header *request);
>
> +/* Queue configuration request. */
> +struct ofpbuf *ofputil_encode_queue_get_config_request(enum ofp_version,
> + ofp_port_t port);
> +enum ofperr ofputil_decode_queue_get_config_request(const struct
> ofp_header *,
> + ofp_port_t *port);
> +
> +/* Queue configuration reply. */
> +struct ofputil_queue_config {
> + uint32_t queue_id;
> +
> + /* Each of these optional values is expressed in tenths of a percent.
> + * Values greater than 1000 indicate that the feature is disabled.
> + * UINT16_MAX indicates that the value is omitted. */
> + uint16_t min_rate;
> + uint16_t max_rate;
> +};
> +
> +struct ofpbuf *ofputil_encode_queue_get_config_reply(
> + const struct ofp_header *request);
> +void ofputil_append_queue_get_config_reply(
> + struct ofpbuf *reply, const struct ofputil_queue_config *);
> +
> +enum ofperr ofputil_decode_queue_get_config_reply(struct ofpbuf *reply,
> + ofp_port_t *);
> +int ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
> + struct ofputil_queue_config *);
> +
> +
> /* Abstract nx_flow_monitor_request. */
> struct ofputil_flow_monitor_request {
> uint32_t id;
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index 8fa5e84..992b324 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -49,6 +49,7 @@
> #include "random.h"
> #include "shash.h"
> #include "simap.h"
> +#include "smap.h"
> #include "sset.h"
> #include "timeval.h"
> #include "unaligned.h"
> @@ -5410,6 +5411,49 @@ handle_group_features_stats_request(struct ofconn
> *ofconn,
> return 0;
> }
>
> +static enum ofperr
> +handle_queue_get_config_request(struct ofconn *ofconn,
> + const struct ofp_header *oh)
> +{
> + struct ofproto *p = ofconn_get_ofproto(ofconn);
> + struct netdev_queue_dump queue_dump;
> + struct ofport *ofport;
> + unsigned int queue_id;
> + struct ofpbuf *reply;
> + struct smap details;
> + ofp_port_t request;
> + enum ofperr error;
> +
> + error = ofputil_decode_queue_get_config_request(oh, &request);
> + if (error) {
> + return error;
> + }
> +
> + ofport = ofproto_get_port(p, request);
> + if (!ofport) {
> + return OFPERR_OFPQOFC_BAD_PORT;
> + }
> +
> + reply = ofputil_encode_queue_get_config_reply(oh);
> +
> + smap_init(&details);
> + NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &queue_dump,
> ofport->netdev) {
> + struct ofputil_queue_config queue;
> +
> + /* None of the existing queues have compatible properties, so we
> + * hard-code omitting min_rate and max_rate. */
> + queue.queue_id = queue_id;
> + queue.min_rate = UINT16_MAX;
> + queue.max_rate = UINT16_MAX;
> + ofputil_append_queue_get_config_reply(reply, &queue);
> + }
> + smap_destroy(&details);
> +
> + ofconn_send_reply(ofconn, reply);
> +
> + return 0;
> +}
> +
> /* Implements OFPGC11_ADD
> * in which no matching flow already exists in the flow table.
> *
> @@ -5794,10 +5838,8 @@ handle_openflow__(struct ofconn *ofconn, const
> struct ofpbuf *msg)
> case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
> return handle_group_features_stats_request(ofconn, oh);
>
> - /* FIXME: Change the following once they are implemented: */
> case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
> - case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
> - /* fallthrough */
> + return handle_queue_get_config_request(ofconn, oh);
>
> case OFPTYPE_HELLO:
> case OFPTYPE_ERROR:
> @@ -5826,6 +5868,7 @@ handle_openflow__(struct ofconn *ofconn, const
> struct ofpbuf *msg)
> case OFPTYPE_METER_STATS_REPLY:
> case OFPTYPE_METER_CONFIG_STATS_REPLY:
> case OFPTYPE_METER_FEATURES_STATS_REPLY:
> + case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
> case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
> default:
> if (ofpmsg_is_stat_request(oh)) {
> diff --git a/tests/ofp-print.at b/tests/ofp-print.at
> index 87d5da8..f932f00 100644
> --- a/tests/ofp-print.at
> +++ b/tests/ofp-print.at
> @@ -1978,6 +1978,50 @@ OFPT_BARRIER_REPLY (OF1.3) (xid=0x1):
> ])
> AT_CLEANUP
>
> +AT_SETUP([OFPT_QUEUE_GET_CONFIG_REQUEST - OF1.0])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print "01 16 00 0c 00 00 00 01 00 01 00 00"],
> [0], [dnl
> +OFPT_QUEUE_GET_CONFIG_REQUEST (xid=0x1): port=1
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_QUEUE_GET_CONFIG_REQUEST - OF1.2])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print "\
> +03 16 00 10 00 00 00 01 00 00 00 01 00 00 00 00"], [0], [dnl
> +OFPT_QUEUE_GET_CONFIG_REQUEST (OF1.2) (xid=0x1): port=1
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_QUEUE_GET_CONFIG_REPLY - OF1.0])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print "01 17 00 40 00 00 00 01 \
> +00 01 00 00 00 00 00 00 \
> +00 00 55 55 00 28 00 00 \
> +00 01 00 10 00 00 00 00 01 f4 00 00 00 00 00 00 \
> +00 02 00 10 00 00 00 00 02 ee 00 00 00 00 00 00 \
> +00 00 44 44 00 08 00 00 \
> +"], [0], [dnl
> +OFPT_QUEUE_GET_CONFIG_REPLY (xid=0x1): port=1
> +queue 21845: min_rate:50.0% max_rate:75.0%
> +queue 17476:
> +])
> +AT_CLEANUP
> +
> +AT_SETUP([OFPT_QUEUE_GET_CONFIG_REPLY - OF1.2])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print "03 17 00 50 00 00 00 01 \
> +00 00 00 01 00 00 00 00 \
> +00 00 55 55 00 00 00 01 00 30 00 00 00 00 00 00 \
> +00 01 00 10 00 00 00 00 01 f4 00 00 00 00 00 00 \
> +00 02 00 10 00 00 00 00 02 ee 00 00 00 00 00 00 \
> +00 00 44 44 00 08 00 01 00 10 00 00 00 00 00 00 \
> +"], [0], [dnl
> +OFPT_QUEUE_GET_CONFIG_REPLY (OF1.2) (xid=0x1): port=1
> +queue 21845: min_rate:50.0% max_rate:75.0%
> +queue 17476:
> +])
> +AT_CLEANUP
>
> AT_SETUP([OFPT_SET_ASYNC - OF1.3])
> AT_KEYWORDS([ofp-print])
> diff --git a/tests/ofproto.at b/tests/ofproto.at
> index 0e1d41b..759b6dd 100644
> --- a/tests/ofproto.at
> +++ b/tests/ofproto.at
> @@ -144,6 +144,36 @@ OFPST_QUEUE request (OF1.2) (xid=0x2):port=10
> queue=ALL
> OVS_VSWITCHD_STOP
> AT_CLEANUP
>
> +dnl This is really bare-bones.
> +dnl It at least checks request and reply serialization and
> deserialization.
> +AT_SETUP([ofproto - queue configuration - (OpenFlow 1.0)])
> +OVS_VSWITCHD_START
> +ADD_OF_PORTS([br0], [1], [2])
> +AT_CHECK([ovs-ofctl queue-get-config br0 1], [0], [stdout])
> +AT_CHECK([STRIP_XIDS stdout], [0], [dnl
> +OFPT_QUEUE_GET_CONFIG_REPLY: port=1
> +])
> +AT_CHECK([ovs-ofctl queue-get-config br0 10], [0],
> + [OFPT_ERROR (xid=0x2): OFPQOFC_BAD_PORT
> +OFPT_QUEUE_GET_CONFIG_REQUEST (xid=0x2): port=10
> +])
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto - queue configuration - (OpenFlow 1.2)])
> +OVS_VSWITCHD_START
> +ADD_OF_PORTS([br0], [1], [2])
> +AT_CHECK([ovs-ofctl -O OpenFlow12 queue-get-config br0 1], [0], [stdout])
> +AT_CHECK([STRIP_XIDS stdout], [0], [dnl
> +OFPT_QUEUE_GET_CONFIG_REPLY (OF1.2): port=1
> +])
> +AT_CHECK([ovs-ofctl -O OpenFlow12 queue-get-config br0 10], [0],
> + [OFPT_ERROR (OF1.2) (xid=0x2): OFPQOFC_BAD_PORT
> +OFPT_QUEUE_GET_CONFIG_REQUEST (OF1.2) (xid=0x2): port=10
> +])
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> AT_SETUP([ofproto - mod-port (OpenFlow 1.0)])
> OVS_VSWITCHD_START
> for command_config_state in \
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index 1a1d423..da0a54b 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -310,6 +310,7 @@ usage(void)
> " dump-group-features SWITCH print group features\n"
> " dump-groups SWITCH print group description\n"
> " dump-group-stats SWITCH [GROUP] print group statistics\n"
> + " queue-get-config SWITCH PORT print queue information for
> port\n"
> " add-meter SWITCH METER add meter described by METER\n"
> " mod-meter SWITCH METER modify specific METER\n"
> " del-meter SWITCH METER delete METER\n"
> @@ -1048,6 +1049,26 @@ ofctl_queue_stats(int argc, char *argv[])
> vconn_close(vconn);
> }
>
> +static void
> +ofctl_queue_get_config(int argc OVS_UNUSED, char *argv[])
> +{
> + const char *vconn_name = argv[1];
> + const char *port_name = argv[2];
> + enum ofputil_protocol protocol;
> + enum ofp_version version;
> + struct ofpbuf *request;
> + struct vconn *vconn;
> + ofp_port_t port;
> +
> + port = str_to_port_no(vconn_name, port_name);
> +
> + protocol = open_vconn(vconn_name, &vconn);
> + version = ofputil_protocol_to_ofp_version(protocol);
> + request = ofputil_encode_queue_get_config_request(version, port);
> + dump_transaction(vconn, request);
> + vconn_close(vconn);
> +}
> +
> static enum ofputil_protocol
> open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp,
> enum ofputil_protocol usable_protocols)
> @@ -3326,6 +3347,7 @@ static const struct command all_commands[] = {
> { "dump-flows", 1, 2, ofctl_dump_flows },
> { "dump-aggregate", 1, 2, ofctl_dump_aggregate },
> { "queue-stats", 1, 3, ofctl_queue_stats },
> + { "queue-get-config", 2, 2, ofctl_queue_get_config },
> { "add-flow", 2, 2, ofctl_add_flow },
> { "add-flows", 2, 2, ofctl_add_flows },
> { "mod-flows", 2, 2, ofctl_mod_flows },
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
Acked-by: Joe Stringer <joestringer at nicira.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openvswitch.org/pipermail/ovs-dev/attachments/20131025/26bef948/attachment-0003.html>
More information about the dev
mailing list