2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

Implement OFPT_QUEUE_GET_CONFIG_REQUEST and OFPT_QUEUE_GET_CONFIG_REPLY.

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@vmware.com>
Co-authored-by: Ben Pfaff <blp@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Joe Stringer <joestringer@nicira.com>
This commit is contained in:
Venkitachalam Gopalakrishnan
2013-10-24 15:54:03 -07:00
committed by Ben Pfaff
parent 54fec1f717
commit e8f9a7bbf1
11 changed files with 556 additions and 31 deletions

View File

@@ -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. */