From: Venkitachalam Gopalakrishnan Date: Thu, 24 Oct 2013 22:54:03 +0000 (-0700) Subject: Implement OFPT_QUEUE_GET_CONFIG_REQUEST and OFPT_QUEUE_GET_CONFIG_REPLY. X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=e8f9a7bbf1b4dd4cfd4f16a3a9c28ccf406b7d26 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 Co-authored-by: Ben Pfaff Signed-off-by: Ben Pfaff Acked-by: Joe Stringer --- diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h index 34d97c4c7..002c75d46 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 249e861f0..694cd5534 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 45d03ef03..93cc2c48e 100644 --- a/include/openflow/openflow-common.h +++ b/include/openflow/openflow-common.h @@ -204,19 +204,10 @@ 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. */ + OFPQT_EXPERIMENTER = 0xffff, /* Experimenter defined property. */ }; /* Common description for a queue. */ @@ -227,13 +218,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 aa19fe31f..4d40c1fa3 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 e4d0303ee..8bbb471d1 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1008,6 +1008,71 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) 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) { @@ -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 a0b729315..e881849e5 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 1f7780825..e16124cef 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -706,6 +706,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 91a39efe9..5aa6f87f0 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" @@ -5413,6 +5414,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. * @@ -5797,10 +5841,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: @@ -5829,6 +5871,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 d94e8d404..a0512528c 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 668246770..cdd824e48 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 1a1d4236c..da0a54b6c 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 },