/*
- * 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.
};
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
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 {
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. */
+ OFPQT_EXPERIMENTER = 0xffff, /* Experimenter defined property. */
};
/* Common description for a queue. */
};
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 {
/* 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. */
* 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.
ofp_print_table_miss_config(string, pm.config);
}
+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)
{
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);
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);
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. */
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;
#include "random.h"
#include "shash.h"
#include "simap.h"
+#include "smap.h"
#include "sset.h"
#include "timeval.h"
#include "unaligned.h"
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.
*
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:
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)) {
])
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])
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 \
" 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"
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)
{ "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 },