[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