From: Ben Pfaff Date: Tue, 31 May 2011 23:49:06 +0000 (-0700) Subject: openflow: Make stats replies more like other OpenFlow messages. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63f2140a553;p=openvswitch openflow: Make stats replies more like other OpenFlow messages. --- diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 7ee2c44b..e0bd4167 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -154,10 +154,7 @@ enum nicira_type { /* Header for Nicira vendor stats request and reply messages. */ struct nicira_stats_msg { - struct ofp_header header; /* OFPT_STATS_REQUEST or OFPT_STATS_REPLY. */ - ovs_be16 type; /* OFPST_VENDOR. */ - ovs_be16 flags; /* OFPSF_{REQ,REPLY}_*. */ - ovs_be32 vendor; /* NX_VENDOR_ID. */ + struct ofp_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */ ovs_be32 subtype; /* One of NXST_* below. */ uint8_t pad[4]; /* Align to 64-bits. */ }; diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index b7c7085d..0dad50d1 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -696,39 +696,37 @@ OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); enum ofp_stats_types { /* Description of this OpenFlow switch. - * The request body is empty. - * The reply body is struct ofp_desc_stats. */ + * The request is struct ofp_stats_msg. + * The reply is struct ofp_desc_stats. */ OFPST_DESC, /* Individual flow statistics. - * The request body is struct ofp_flow_stats_request. + * The request is struct ofp_flow_stats_request. * The reply body is an array of struct ofp_flow_stats. */ OFPST_FLOW, /* Aggregate flow statistics. - * The request body is struct ofp_flow_stats_request. - * The reply body is struct ofp_aggregate_stats_reply. */ + * The request is struct ofp_flow_stats_request. + * The reply is struct ofp_aggregate_stats_reply. */ OFPST_AGGREGATE, /* Flow table statistics. - * The request body is empty. + * The request is struct ofp_stats_msg. * The reply body is an array of struct ofp_table_stats. */ OFPST_TABLE, /* Physical port statistics. - * The request body is struct ofp_port_stats_request. + * The request is struct ofp_port_stats_request. * The reply body is an array of struct ofp_port_stats. */ OFPST_PORT, - /* Queue statistics for a port + /* Queue statistics for a port. * The request body is struct ofp_queue_stats_request. * The reply body is an array of struct ofp_queue_stats. */ OFPST_QUEUE, /* Vendor extension. - * The request and reply bodies begin with a 32-bit vendor ID, which takes - * the same form as in "struct ofp_vendor_header". The request and reply - * bodies are otherwise vendor-defined. */ + * The request and reply begin with "struct ofp_vendor_stats". */ OFPST_VENDOR = 0xffff }; @@ -747,9 +745,10 @@ enum ofp_stats_reply_flags { #define DESC_STR_LEN 256 #define SERIAL_NUM_LEN 32 -/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated - * ASCII string. */ +/* Reply to OFPST_DESC request. Each entry is a NULL-terminated ASCII + * string. */ struct ofp_desc_stats { + struct ofp_stats_msg osm; char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */ char hw_desc[DESC_STR_LEN]; /* Hardware description. */ char sw_desc[DESC_STR_LEN]; /* Software description. */ @@ -757,10 +756,11 @@ struct ofp_desc_stats { char dp_desc[DESC_STR_LEN]; /* Human readable description of the datapath. */ }; -OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056); +OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1068); -/* Body for stats request of type OFPST_FLOW or OFPST_AGGREGATE. */ +/* Stats request of type OFPST_AGGREGATE or OFPST_FLOW. */ struct ofp_flow_stats_request { + struct ofp_stats_msg osm; struct ofp_match match; /* Fields to match. */ uint8_t table_id; /* ID of table to read (from ofp_table_stats) or 0xff for all tables. */ @@ -769,7 +769,7 @@ struct ofp_flow_stats_request { as an output port. A value of OFPP_NONE indicates no restriction. */ }; -OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44); +OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 56); /* Body of reply to OFPST_FLOW request. */ struct ofp_flow_stats { @@ -792,14 +792,15 @@ struct ofp_flow_stats { }; OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88); -/* Body of reply to OFPST_AGGREGATE request. */ +/* Reply to OFPST_AGGREGATE request. */ struct ofp_aggregate_stats_reply { + struct ofp_stats_msg osm; ovs_32aligned_be64 packet_count; /* Number of packets in flows. */ ovs_32aligned_be64 byte_count; /* Number of bytes in flows. */ ovs_be32 flow_count; /* Number of flows. */ uint8_t pad[4]; /* Align to 64 bits. */ }; -OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24); +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 36); /* Body of reply to OFPST_TABLE request. */ struct ofp_table_stats { @@ -816,14 +817,15 @@ struct ofp_table_stats { }; OFP_ASSERT(sizeof(struct ofp_table_stats) == 64); -/* Body for stats request of type OFPST_PORT. */ +/* Stats request of type OFPST_PORT. */ struct ofp_port_stats_request { + struct ofp_stats_msg osm; ovs_be16 port_no; /* OFPST_PORT message may request statistics for a single port (specified with port_no) or for all ports (port_no == OFPP_NONE). */ uint8_t pad[6]; }; -OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 20); /* Body of reply to OFPST_PORT request. If a counter is unsupported, set * the field to all ones. */ @@ -854,11 +856,12 @@ OFP_ASSERT(sizeof(struct ofp_port_stats) == 104); /* Body for stats request of type OFPST_QUEUE. */ struct ofp_queue_stats_request { + struct ofp_stats_msg osm; ovs_be16 port_no; /* All ports if OFPP_ALL. */ uint8_t pad[2]; /* Align to 32-bits. */ ovs_be32 queue_id; /* All queues if OFPQ_ALL. */ }; -OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 20); /* Body for stats reply of type OFPST_QUEUE consists of an array of this * structure type. */ @@ -872,6 +875,17 @@ struct ofp_queue_stats { }; OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32); +/* Vendor extension stats message. */ +struct ofp_vendor_stats_msg { + struct ofp_stats_msg osm; /* Type OFPST_VENDOR. */ + ovs_be32 vendor; /* Vendor ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by OpenFlow + * consortium. */ + /* Followed by vendor-defined arbitrary additional data. */ +}; +OFP_ASSERT(sizeof(struct ofp_vendor_stats_msg) == 16); + /* Vendor extension. */ struct ofp_vendor_header { struct ofp_header header; /* Type OFPT_VENDOR. */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 30da724e..828740ac 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1043,10 +1043,8 @@ ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops) } static void -ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh) +ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods) { - const struct ofp_desc_stats *ods = ofputil_stats_body(oh); - ds_put_char(string, '\n'); ds_put_format(string, "Manufacturer: %.*s\n", (int) sizeof ods->mfr_desc, ods->mfr_desc); @@ -1131,8 +1129,8 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh) } static void -ofp_print_ofp_aggregate_stats_reply ( - struct ds *string, const struct ofp_aggregate_stats_reply *asr) +ofp_print_ofpst_aggregate_reply(struct ds *string, + const struct ofp_aggregate_stats_reply *asr) { ds_put_format(string, " packet_count=%"PRIu64, ntohll(get_32aligned_be64(&asr->packet_count))); @@ -1141,12 +1139,6 @@ ofp_print_ofp_aggregate_stats_reply ( ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count)); } -static void -ofp_print_ofpst_aggregate_reply(struct ds *string, const struct ofp_header *oh) -{ - ofp_print_ofp_aggregate_stats_reply(string, ofputil_stats_body(oh)); -} - static void ofp_print_nxst_aggregate_reply(struct ds *string, const struct nx_aggregate_stats_reply *nasr) @@ -1175,9 +1167,9 @@ static void print_port_stat(struct ds *string, const char *leader, } static void -ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh) +ofp_print_ofpst_port_request(struct ds *string, + const struct ofp_port_stats_request *psr) { - const struct ofp_port_stats_request *psr = ofputil_stats_body(oh); ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no)); } @@ -1251,10 +1243,9 @@ ofp_print_queue_name(struct ds *string, uint32_t queue_id) } static void -ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh) +ofp_print_ofpst_queue_request(struct ds *string, + const struct ofp_queue_stats_request *qsr) { - const struct ofp_queue_stats_request *qsr = ofputil_stats_body(oh); - ds_put_cstr(string, "port="); ofp_print_port_name(string, ntohs(qsr->port_no)); @@ -1465,17 +1456,17 @@ ofp_to_string__(const struct ofp_header *oh, case OFPUTIL_OFPST_PORT_REQUEST: ofp_print_stats_request(string, oh); - ofp_print_ofpst_port_request(string, oh); + ofp_print_ofpst_port_request(string, msg); break; case OFPUTIL_OFPST_QUEUE_REQUEST: ofp_print_stats_request(string, oh); - ofp_print_ofpst_queue_request(string, oh); + ofp_print_ofpst_queue_request(string, msg); break; case OFPUTIL_OFPST_DESC_REPLY: ofp_print_stats_reply(string, oh); - ofp_print_ofpst_desc_reply(string, oh); + ofp_print_ofpst_desc_reply(string, msg); break; case OFPUTIL_OFPST_FLOW_REPLY: @@ -1501,7 +1492,7 @@ ofp_to_string__(const struct ofp_header *oh, case OFPUTIL_OFPST_AGGREGATE_REPLY: ofp_print_stats_reply(string, oh); - ofp_print_ofpst_aggregate_reply(string, oh); + ofp_print_ofpst_aggregate_reply(string, msg); break; case OFPUTIL_NXT_ROLE_REQUEST: diff --git a/lib/ofp-util.c b/lib/ofp-util.c index df084b0e..c3d9187f 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -500,35 +500,34 @@ static int ofputil_decode_ofpst_request(const struct ofp_header *oh, const struct ofputil_msg_type **typep) { - enum { OSM_SIZE = sizeof(struct ofp_stats_msg) }; static const struct ofputil_msg_type ofpst_requests[] = { { OFPUTIL_OFPST_DESC_REQUEST, OFPST_DESC, "OFPST_DESC request", - OSM_SIZE, 0 }, + sizeof(struct ofp_stats_msg), 0 }, { OFPUTIL_OFPST_FLOW_REQUEST, OFPST_FLOW, "OFPST_FLOW request", - OSM_SIZE + sizeof(struct ofp_flow_stats_request), 0 }, + sizeof(struct ofp_flow_stats_request), 0 }, { OFPUTIL_OFPST_AGGREGATE_REQUEST, OFPST_AGGREGATE, "OFPST_AGGREGATE request", - OSM_SIZE + sizeof(struct ofp_flow_stats_request), 0 }, + sizeof(struct ofp_flow_stats_request), 0 }, { OFPUTIL_OFPST_TABLE_REQUEST, OFPST_TABLE, "OFPST_TABLE request", - OSM_SIZE, 0 }, + sizeof(struct ofp_stats_msg), 0 }, { OFPUTIL_OFPST_PORT_REQUEST, OFPST_PORT, "OFPST_PORT request", - OSM_SIZE + sizeof(struct ofp_port_stats_request), 0 }, + sizeof(struct ofp_port_stats_request), 0 }, { OFPUTIL_OFPST_QUEUE_REQUEST, OFPST_QUEUE, "OFPST_QUEUE request", - OSM_SIZE + sizeof(struct ofp_queue_stats_request), 0 }, + sizeof(struct ofp_queue_stats_request), 0 }, { 0, OFPST_VENDOR, "OFPST_VENDOR request", - OSM_SIZE + sizeof(uint32_t), 1 }, + sizeof(struct ofp_vendor_stats_msg), 1 }, }; static const struct ofputil_msg_category ofpst_request_category = { @@ -553,35 +552,34 @@ static int ofputil_decode_ofpst_reply(const struct ofp_header *oh, const struct ofputil_msg_type **typep) { - enum { OSM_SIZE = sizeof(struct ofp_stats_msg) }; static const struct ofputil_msg_type ofpst_replies[] = { { OFPUTIL_OFPST_DESC_REPLY, OFPST_DESC, "OFPST_DESC reply", - OSM_SIZE + sizeof(struct ofp_desc_stats), 0 }, + sizeof(struct ofp_desc_stats), 0 }, { OFPUTIL_OFPST_FLOW_REPLY, OFPST_FLOW, "OFPST_FLOW reply", - OSM_SIZE, 1 }, + sizeof(struct ofp_stats_msg), 1 }, { OFPUTIL_OFPST_AGGREGATE_REPLY, OFPST_AGGREGATE, "OFPST_AGGREGATE reply", - OSM_SIZE + sizeof(struct ofp_aggregate_stats_reply), 0 }, + sizeof(struct ofp_aggregate_stats_reply), 0 }, { OFPUTIL_OFPST_TABLE_REPLY, OFPST_TABLE, "OFPST_TABLE reply", - OSM_SIZE, sizeof(struct ofp_table_stats) }, + sizeof(struct ofp_stats_msg), sizeof(struct ofp_table_stats) }, { OFPUTIL_OFPST_PORT_REPLY, OFPST_PORT, "OFPST_PORT reply", - OSM_SIZE, sizeof(struct ofp_port_stats) }, + sizeof(struct ofp_stats_msg), sizeof(struct ofp_port_stats) }, { OFPUTIL_OFPST_QUEUE_REPLY, OFPST_QUEUE, "OFPST_QUEUE reply", - OSM_SIZE, sizeof(struct ofp_queue_stats) }, + sizeof(struct ofp_stats_msg), sizeof(struct ofp_queue_stats) }, { 0, OFPST_VENDOR, "OFPST_VENDOR reply", - OSM_SIZE + sizeof(uint32_t), 1 }, + sizeof(struct ofp_vendor_stats_msg), 1 }, }; static const struct ofputil_msg_category ofpst_reply_category = { @@ -1015,7 +1013,8 @@ ofputil_decode_ofpst_flow_request(struct flow_stats_request *fsr, const struct ofp_header *oh, bool aggregate) { - const struct ofp_flow_stats_request *ofsr = ofputil_stats_body(oh); + const struct ofp_flow_stats_request *ofsr = + (const struct ofp_flow_stats_request *) oh; fsr->aggregate = aggregate; ofputil_cls_rule_from_match(&ofsr->match, 0, &fsr->match); @@ -1100,7 +1099,7 @@ ofputil_encode_flow_stats_request(const struct flow_stats_request *fsr, int type; type = fsr->aggregate ? OFPST_AGGREGATE : OFPST_FLOW; - ofsr = ofputil_make_stats_request(sizeof *ofsr, type, &msg); + ofsr = ofputil_make_stats_request(sizeof *ofsr, type, 0, &msg); ofputil_cls_rule_to_match(&fsr->match, &ofsr->match); ofsr->table_id = fsr->table_id; ofsr->out_port = htons(fsr->out_port); @@ -1110,7 +1109,7 @@ ofputil_encode_flow_stats_request(const struct flow_stats_request *fsr, int subtype; subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW; - ofputil_make_nxstats_request(sizeof *nfsr, subtype, &msg); + ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg); match_len = nx_put_match(msg, &fsr->match); nfsr = msg->data; @@ -1520,34 +1519,130 @@ update_openflow_length(struct ofpbuf *buffer) oh->length = htons(buffer->size); } -/* Creates an ofp_stats_msg with the given 'type' and 'body_len' bytes of space - * allocated following the ofp_stats_msg header. */ +static void +put_stats__(ovs_be32 xid, uint8_t ofp_type, + ovs_be16 ofpst_type, ovs_be32 nxst_subtype, + struct ofpbuf *msg) +{ + if (ofpst_type == htons(OFPST_VENDOR)) { + struct nicira_stats_msg *nsm; + + nsm = put_openflow_xid(sizeof *nsm, ofp_type, xid, msg); + nsm->vsm.osm.type = ofpst_type; + nsm->vsm.vendor = htonl(NX_VENDOR_ID); + nsm->subtype = nxst_subtype; + } else { + struct ofp_stats_msg *osm; + + osm = put_openflow_xid(sizeof *osm, ofp_type, xid, msg); + osm->type = ofpst_type; + } +} + +/* Creates a statistics request message with total length 'openflow_len' + * (including all headers) and the given 'ofpst_type', and stores the buffer + * containing the new message in '*bufferp'. If 'ofpst_type' is OFPST_VENDOR + * then 'nxst_subtype' is used as the Nicira vendor extension statistics + * subtype (otherwise 'nxst_subtype' is ignored). + * + * Initializes bytes following the headers to all-bits-zero. + * + * Returns the first byte of the new message. */ void * -ofputil_make_stats_request(size_t body_len, uint16_t type, - struct ofpbuf **bufferp) +ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type, + uint32_t nxst_subtype, struct ofpbuf **bufferp) { - struct ofp_stats_msg *request; - request = make_openflow(sizeof *request + body_len, OFPT_STATS_REQUEST, - bufferp); - request->type = htons(type); - request->flags = htons(0); - return request + 1; + struct ofpbuf *msg; + + msg = *bufferp = ofpbuf_new(openflow_len); + put_stats__(alloc_xid(), OFPT_STATS_REQUEST, + htons(ofpst_type), htonl(nxst_subtype), msg); + ofpbuf_padto(msg, openflow_len); + + return msg->data; +} + +static void +put_stats_reply__(const struct ofp_stats_msg *request, struct ofpbuf *msg) +{ + assert(request->header.type == OFPT_STATS_REQUEST || + request->header.type == OFPT_STATS_REPLY); + put_stats__(request->header.xid, OFPT_STATS_REPLY, request->type, + (request->type != htons(OFPST_VENDOR) + ? htonl(0) + : ((const struct nicira_stats_msg *) request)->subtype), + msg); } -/* Creates a stats request message with Nicira as vendor and the given - * 'subtype', of total length 'openflow_len'. Returns the message. */ +/* Creates a statistics reply message with total length 'openflow_len' + * (including all headers) and the same type (either a standard OpenFlow + * statistics type or a Nicira extension type and subtype) as 'request', and + * stores the buffer containing the new message in '*bufferp'. + * + * Initializes bytes following the headers to all-bits-zero. + * + * Returns the first byte of the new message. */ void * -ofputil_make_nxstats_request(size_t openflow_len, uint32_t subtype, - struct ofpbuf **bufferp) +ofputil_make_stats_reply(size_t openflow_len, + const struct ofp_stats_msg *request, + struct ofpbuf **bufferp) +{ + struct ofpbuf *msg; + + msg = *bufferp = ofpbuf_new(openflow_len); + put_stats_reply__(request, msg); + ofpbuf_padto(msg, openflow_len); + + return msg->data; +} + +/* Initializes 'replies' as a list of ofpbufs that will contain a series of + * replies to 'request', which should be an OpenFlow or Nicira extension + * statistics request. Initially 'replies' will have a single reply message + * that has only a header. The functions ofputil_reserve_stats_reply() and + * ofputil_append_stats_reply() may be used to add to the reply. */ +void +ofputil_start_stats_reply(const struct ofp_stats_msg *request, + struct list *replies) +{ + struct ofpbuf *msg; + + msg = ofpbuf_new(1024); + put_stats_reply__(request, msg); + + list_init(replies); + list_push_back(replies, &msg->list_node); +} + +/* Prepares to append up to 'len' bytes to the series of statistics replies in + * 'replies', which should have been initialized with + * ofputil_start_stats_reply(). Returns an ofpbuf with at least 'len' bytes of + * tailroom. (The 'len' bytes have not actually be allocated; the caller must + * do so with e.g. ofpbuf_put_uninit().) */ +struct ofpbuf * +ofputil_reserve_stats_reply(size_t len, struct list *replies) { - struct nicira_stats_msg *nsm; + struct ofpbuf *msg = ofpbuf_from_list(list_back(replies)); + struct ofp_stats_msg *osm = msg->data; + + if (msg->size + len <= UINT16_MAX) { + ofpbuf_prealloc_tailroom(msg, len); + } else { + osm->flags |= htons(OFPSF_REPLY_MORE); + + msg = ofpbuf_new(MAX(1024, sizeof(struct nicira_stats_msg) + len)); + put_stats_reply__(osm, msg); + list_push_back(replies, &msg->list_node); + } + return msg; +} - nsm = make_openflow(openflow_len, OFPT_STATS_REQUEST, bufferp); - nsm->type = htons(OFPST_VENDOR); - nsm->flags = htons(0); - nsm->vendor = htonl(NX_VENDOR_ID); - nsm->subtype = htonl(subtype); - return nsm; +/* Appends 'len' bytes to the series of statistics replies in 'replies', and + * returns the first byte. */ +void * +ofputil_append_stats_reply(size_t len, struct list *replies) +{ + return ofpbuf_put_uninit(ofputil_reserve_stats_reply(len, replies), len); } /* Returns the first byte past the ofp_stats_msg header in 'oh'. */ diff --git a/lib/ofp-util.h b/lib/ofp-util.h index bba36630..2404e754 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -221,10 +221,16 @@ void *put_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid, void update_openflow_length(struct ofpbuf *); -void *ofputil_make_stats_request(size_t body_len, uint16_t type, - struct ofpbuf **); -void *ofputil_make_nxstats_request(size_t openflow_len, uint32_t subtype, - struct ofpbuf **); +void *ofputil_make_stats_request(size_t openflow_len, uint16_t type, + uint32_t subtype, struct ofpbuf **); +void *ofputil_make_stats_reply(size_t openflow_len, + const struct ofp_stats_msg *request, + struct ofpbuf **); + +void ofputil_start_stats_reply(const struct ofp_stats_msg *request, + struct list *); +struct ofpbuf *ofputil_reserve_stats_reply(size_t len, struct list *); +void *ofputil_append_stats_reply(size_t len, struct list *); const void *ofputil_stats_body(const struct ofp_header *); size_t ofputil_stats_body_len(const struct ofp_header *); diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c index 8166d6b1..38874816 100644 --- a/lib/ofpbuf.c +++ b/lib/ofpbuf.c @@ -289,6 +289,16 @@ ofpbuf_trim(struct ofpbuf *b) } } +/* If 'b' is shorter than 'length' bytes, pads its tail out with zeros to that + * length. */ +void +ofpbuf_padto(struct ofpbuf *b, size_t length) +{ + if (b->size < length) { + ofpbuf_put_zeros(b, length - b->size); + } +} + /* Appends 'size' bytes of data to the tail end of 'b', reallocating and * copying its data if necessary. Returns a pointer to the first byte of the * new data, which is left uninitialized. */ diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h index 34fcf5f7..7f8338cd 100644 --- a/lib/ofpbuf.h +++ b/lib/ofpbuf.h @@ -91,6 +91,7 @@ size_t ofpbuf_tailroom(const struct ofpbuf *); void ofpbuf_prealloc_headroom(struct ofpbuf *, size_t); void ofpbuf_prealloc_tailroom(struct ofpbuf *, size_t); void ofpbuf_trim(struct ofpbuf *); +void ofpbuf_padto(struct ofpbuf *, size_t); void ofpbuf_clear(struct ofpbuf *); void *ofpbuf_pull(struct ofpbuf *, size_t); diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index 7e7aaae3..403a1403 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -765,6 +765,19 @@ ofconn_send_reply(const struct ofconn *ofconn, struct ofpbuf *msg) ofconn_send(ofconn, msg, ofconn->reply_counter); } +/* Sends each of the messages in list 'replies' on 'ofconn' in order, + * accounting them as replies. */ +void +ofconn_send_replies(const struct ofconn *ofconn, struct list *replies) +{ + struct ofpbuf *reply, *next; + + LIST_FOR_EACH_SAFE (reply, next, list_node, replies) { + list_remove(&reply->list_node); + ofconn_send_reply(ofconn, reply); + } +} + /* Same as pktbuf_retrieve(), using the pktbuf owned by 'ofconn'. */ int ofconn_pktbuf_retrieve(struct ofconn *ofconn, uint32_t id, diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h index 46d2f5d8..9b2e9c56 100644 --- a/ofproto/connmgr.h +++ b/ofproto/connmgr.h @@ -87,6 +87,7 @@ int ofconn_get_miss_send_len(const struct ofconn *); void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len); void ofconn_send_reply(const struct ofconn *, struct ofpbuf *); +void ofconn_send_replies(const struct ofconn *, struct list *); int ofconn_pktbuf_retrieve(struct ofconn *, uint32_t id, struct ofpbuf **bufferp, uint16_t *in_port); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 57f4bedd..3053160c 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1582,88 +1582,15 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } -static struct ofpbuf * -make_ofp_stats_reply(ovs_be32 xid, ovs_be16 type, size_t body_len) -{ - struct ofp_stats_msg *reply; - struct ofpbuf *msg; - - msg = ofpbuf_new(MIN(sizeof *reply + body_len, UINT16_MAX)); - reply = put_openflow_xid(sizeof *reply, OFPT_STATS_REPLY, xid, msg); - reply->type = type; - reply->flags = htons(0); - return msg; -} - -static struct ofpbuf * -start_ofp_stats_reply(const struct ofp_header *request, size_t body_len) -{ - const struct ofp_stats_msg *osm = (const struct ofp_stats_msg *) request; - return make_ofp_stats_reply(osm->header.xid, osm->type, body_len); -} - -static void * -append_ofp_stats_reply(size_t nbytes, struct ofconn *ofconn, - struct ofpbuf **msgp) -{ - struct ofpbuf *msg = *msgp; - assert(nbytes <= UINT16_MAX - sizeof(struct ofp_stats_msg)); - if (nbytes + msg->size > UINT16_MAX) { - struct ofp_stats_msg *reply = msg->data; - reply->flags = htons(OFPSF_REPLY_MORE); - *msgp = make_ofp_stats_reply(reply->header.xid, reply->type, nbytes); - ofconn_send_reply(ofconn, msg); - } - return ofpbuf_put_uninit(*msgp, nbytes); -} - -static struct ofpbuf * -make_nxstats_reply(ovs_be32 xid, ovs_be32 subtype, size_t body_len) -{ - struct nicira_stats_msg *nsm; - struct ofpbuf *msg; - - msg = ofpbuf_new(MIN(sizeof *nsm + body_len, UINT16_MAX)); - nsm = put_openflow_xid(sizeof *nsm, OFPT_STATS_REPLY, xid, msg); - nsm->type = htons(OFPST_VENDOR); - nsm->flags = htons(0); - nsm->vendor = htonl(NX_VENDOR_ID); - nsm->subtype = subtype; - return msg; -} - -static struct ofpbuf * -start_nxstats_reply(const struct nicira_stats_msg *request, size_t body_len) -{ - return make_nxstats_reply(request->header.xid, request->subtype, body_len); -} - -static void -append_nxstats_reply(size_t nbytes, struct ofconn *ofconn, - struct ofpbuf **msgp) -{ - struct ofpbuf *msg = *msgp; - assert(nbytes <= UINT16_MAX - sizeof(struct nicira_stats_msg)); - if (nbytes + msg->size > UINT16_MAX) { - struct nicira_stats_msg *reply = msg->data; - reply->flags = htons(OFPSF_REPLY_MORE); - *msgp = make_nxstats_reply(reply->header.xid, reply->subtype, nbytes); - ofconn_send_reply(ofconn, msg); - } - ofpbuf_prealloc_tailroom(*msgp, nbytes); -} - static int handle_desc_stats_request(struct ofconn *ofconn, - const struct ofp_header *request) + const struct ofp_stats_msg *request) { struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp_desc_stats *ods; struct ofpbuf *msg; - msg = start_ofp_stats_reply(request, sizeof *ods); - ods = append_ofp_stats_reply(sizeof *ods, ofconn, &msg); - memset(ods, 0, sizeof *ods); + ods = ofputil_make_stats_reply(sizeof *ods, request, &msg); ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc); ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc); ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc); @@ -1676,14 +1603,14 @@ handle_desc_stats_request(struct ofconn *ofconn, static int handle_table_stats_request(struct ofconn *ofconn, - const struct ofp_header *request) + const struct ofp_stats_msg *request) { struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp_table_stats *ots; struct ofpbuf *msg; size_t i; - msg = start_ofp_stats_reply(request, sizeof *ots * p->n_tables); + ofputil_make_stats_reply(sizeof(struct ofp_stats_msg), request, &msg); ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables); for (i = 0; i < p->n_tables; i++) { @@ -1701,8 +1628,7 @@ handle_table_stats_request(struct ofconn *ofconn, } static void -append_port_stat(struct ofport *port, struct ofconn *ofconn, - struct ofpbuf **msgp) +append_port_stat(struct ofport *port, struct list *replies) { struct netdev_stats stats; struct ofp_port_stats *ops; @@ -1712,7 +1638,7 @@ append_port_stat(struct ofport *port, struct ofconn *ofconn, * netdev_get_stats() will log errors. */ netdev_get_stats(port->netdev, &stats); - ops = append_ofp_stats_reply(sizeof *ops, ofconn, msgp); + ops = ofputil_append_stats_reply(sizeof *ops, replies); ops->port_no = port->opp.port_no; memset(ops->pad, 0, sizeof ops->pad); put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets)); @@ -1730,27 +1656,26 @@ append_port_stat(struct ofport *port, struct ofconn *ofconn, } static int -handle_port_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) +handle_port_stats_request(struct ofconn *ofconn, + const struct ofp_port_stats_request *psr) { struct ofproto *p = ofconn_get_ofproto(ofconn); - const struct ofp_port_stats_request *psr = ofputil_stats_body(oh); - struct ofp_port_stats *ops; - struct ofpbuf *msg; struct ofport *port; + struct list replies; - msg = start_ofp_stats_reply(oh, sizeof *ops * 16); + ofputil_start_stats_reply(&psr->osm, &replies); if (psr->port_no != htons(OFPP_NONE)) { port = ofproto_get_port(p, ntohs(psr->port_no)); if (port) { - append_port_stat(port, ofconn, &msg); + append_port_stat(port, &replies); } } else { HMAP_FOR_EACH (port, hmap_node, &p->ports) { - append_port_stat(port, ofconn, &msg); + append_port_stat(port, &replies); } } - ofconn_send_reply(ofconn, msg); + ofconn_send_replies(ofconn, &replies); return 0; } @@ -1774,7 +1699,7 @@ calc_flow_duration(long long int start, ovs_be32 *sec_be, ovs_be32 *nsec_be) static void put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, - ovs_be16 out_port, struct ofpbuf **replyp) + ovs_be16 out_port, struct list *replies) { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofp_flow_stats *ofs; @@ -1790,7 +1715,7 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, ofproto->ofproto_class->rule_get_stats(rule, &packet_count, &byte_count); - ofs = append_ofp_stats_reply(len, ofconn, replyp); + ofs = ofputil_append_stats_reply(len, replies); ofs->length = htons(len); ofs->table_id = rule->table_id; ofs->pad = 0; @@ -1854,16 +1779,16 @@ next_matching_table(struct ofproto *ofproto, (CLS) = next_matching_table(OFPROTO, CLS, TABLE_ID)) static int -handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) +handle_flow_stats_request(struct ofconn *ofconn, + const struct ofp_flow_stats_request *fsr) { - const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh); struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct classifier *cls; struct cls_rule target; - struct ofpbuf *reply; + struct list replies; COVERAGE_INC(ofproto_flows_req); - reply = start_ofp_stats_reply(oh, 1024); + ofputil_start_stats_reply(&fsr->osm, &replies); ofputil_cls_rule_from_match(&fsr->match, 0, &target); FOR_EACH_MATCHING_TABLE (cls, fsr->table_id, ofproto) { struct cls_cursor cursor; @@ -1871,17 +1796,16 @@ handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) cls_cursor_init(&cursor, cls, &target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { - put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply); + put_ofp_flow_stats(ofconn, rule, fsr->out_port, &replies); } } - ofconn_send_reply(ofconn, reply); + ofconn_send_replies(ofconn, &replies); return 0; } static void -put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule, - ovs_be16 out_port, struct ofpbuf **replyp) +put_nx_flow_stats(struct rule *rule, ovs_be16 out_port, struct list *replies) { struct nx_flow_stats *nfs; uint64_t packet_count, byte_count; @@ -1897,9 +1821,9 @@ put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule, act_len = sizeof *rule->actions * rule->n_actions; - append_nxstats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, ofconn, replyp); - start_len = (*replyp)->size; - reply = *replyp; + reply = ofputil_reserve_stats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, + replies); + start_len = reply->size; nfs = ofpbuf_put_uninit(reply, sizeof *nfs); nfs->table_id = rule->table_id; @@ -1920,17 +1844,17 @@ put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule, } static int -handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) +handle_nxst_flow(struct ofconn *ofconn, const struct ofp_stats_msg *osm) { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct nx_flow_stats_request *nfsr; struct classifier *cls; struct cls_rule target; - struct ofpbuf *reply; + struct list replies; struct ofpbuf b; int error; - ofpbuf_use_const(&b, oh, ntohs(oh->length)); + ofpbuf_use_const(&b, osm, ntohs(osm->header.length)); /* Dissect the message. */ nfsr = ofpbuf_pull(&b, sizeof *nfsr); @@ -1943,17 +1867,17 @@ handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) } COVERAGE_INC(ofproto_flows_req); - reply = start_nxstats_reply(&nfsr->nsm, 1024); + ofputil_start_stats_reply(osm, &replies); FOR_EACH_MATCHING_TABLE (cls, nfsr->table_id, ofproto) { struct cls_cursor cursor; struct rule *rule; cls_cursor_init(&cursor, cls, &target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { - put_nx_flow_stats(ofconn, rule, nfsr->out_port, &reply); + put_nx_flow_stats(rule, nfsr->out_port, &replies); } } - ofconn_send_reply(ofconn, reply); + ofconn_send_replies(ofconn, &replies); return 0; } @@ -2064,9 +1988,8 @@ query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target, static int handle_aggregate_stats_request(struct ofconn *ofconn, - const struct ofp_header *oh) + const struct ofp_flow_stats_request *request) { - const struct ofp_flow_stats_request *request = ofputil_stats_body(oh); struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofp_aggregate_stats_reply *reply; uint64_t total_packets, total_bytes; @@ -2075,13 +1998,11 @@ handle_aggregate_stats_request(struct ofconn *ofconn, uint32_t n_flows; ofputil_cls_rule_from_match(&request->match, 0, &target); - - msg = start_ofp_stats_reply(oh, sizeof *reply); - reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg); query_aggregate_stats(ofproto, &target, request->out_port, request->table_id, &total_packets, &total_bytes, &n_flows); + reply = ofputil_make_stats_reply(sizeof *reply, &request->osm, &msg); reply->flow_count = htonl(n_flows); put_32aligned_be64(&reply->packet_count, htonll(total_packets)); put_32aligned_be64(&reply->byte_count, htonll(total_bytes)); @@ -2101,12 +2022,12 @@ handle_nxst_aggregate(struct ofconn *ofconn, struct nx_aggregate_stats_reply *reply; uint64_t total_packets, total_bytes; struct cls_rule target; - struct ofpbuf b; - struct ofpbuf *buf; + struct ofpbuf *msg; uint32_t n_flows; + struct ofpbuf b; int error; - ofpbuf_use_const(&b, nasr, ntohs(nasr->nsm.header.length)); + ofpbuf_use_const(&b, nasr, ntohs(nasr->nsm.vsm.osm.header.length)); /* Dissect the message. */ request = ofpbuf_pull(&b, sizeof *request); @@ -2125,21 +2046,20 @@ handle_nxst_aggregate(struct ofconn *ofconn, /* Reply. */ COVERAGE_INC(ofproto_flows_req); - buf = start_nxstats_reply(&request->nsm, sizeof *reply); - reply = ofpbuf_put_uninit(buf, sizeof *reply); + reply = ofputil_make_stats_reply(sizeof *reply, &request->nsm.vsm.osm, + &msg); reply->flow_count = htonl(n_flows); reply->packet_count = htonll(total_packets); reply->byte_count = htonll(total_bytes); memset(reply->pad, 0, sizeof reply->pad); - ofconn_send_reply(ofconn, buf); + ofconn_send_reply(ofconn, msg); return 0; } struct queue_stats_cbdata { - struct ofconn *ofconn; struct ofport *ofport; - struct ofpbuf *msg; + struct list replies; }; static void @@ -2148,7 +2068,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id, { struct ofp_queue_stats *reply; - reply = append_ofp_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg); + reply = ofputil_append_stats_reply(sizeof *reply, &cbdata->replies); reply->port_no = cbdata->ofport->opp.port_no; memset(reply->pad, 0, sizeof reply->pad); reply->queue_id = htonl(queue_id); @@ -2185,24 +2105,18 @@ handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id, } static int -handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) +handle_queue_stats_request(struct ofconn *ofconn, + const struct ofp_queue_stats_request *qsr) { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); - const struct ofp_queue_stats_request *qsr; struct queue_stats_cbdata cbdata; struct ofport *port; unsigned int port_no; uint32_t queue_id; - qsr = ofputil_stats_body(oh); - if (!qsr) { - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - COVERAGE_INC(ofproto_queue_req); - cbdata.ofconn = ofconn; - cbdata.msg = start_ofp_stats_reply(oh, 128); + ofputil_start_stats_reply(&qsr->osm, &cbdata.replies); port_no = ntohs(qsr->port_no); queue_id = ntohl(qsr->queue_id); @@ -2216,10 +2130,10 @@ handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) handle_queue_stats_for_port(port, queue_id, &cbdata); } } else { - ofpbuf_delete(cbdata.msg); + ofpbuf_list_delete(&cbdata.replies); return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT); } - ofconn_send_reply(ofconn, cbdata.msg); + ofconn_send_replies(ofconn, &cbdata.replies); return 0; } @@ -2708,26 +2622,26 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) /* OpenFlow statistics requests. */ case OFPUTIL_OFPST_DESC_REQUEST: - return handle_desc_stats_request(ofconn, oh); + return handle_desc_stats_request(ofconn, msg->data); case OFPUTIL_OFPST_FLOW_REQUEST: - return handle_flow_stats_request(ofconn, oh); + return handle_flow_stats_request(ofconn, msg->data); case OFPUTIL_OFPST_AGGREGATE_REQUEST: - return handle_aggregate_stats_request(ofconn, oh); + return handle_aggregate_stats_request(ofconn, msg->data); case OFPUTIL_OFPST_TABLE_REQUEST: - return handle_table_stats_request(ofconn, oh); + return handle_table_stats_request(ofconn, msg->data); case OFPUTIL_OFPST_PORT_REQUEST: - return handle_port_stats_request(ofconn, oh); + return handle_port_stats_request(ofconn, msg->data); case OFPUTIL_OFPST_QUEUE_REQUEST: - return handle_queue_stats_request(ofconn, oh); + return handle_queue_stats_request(ofconn, msg->data); /* Nicira extension statistics requests. */ case OFPUTIL_NXST_FLOW_REQUEST: - return handle_nxst_flow(ofconn, oh); + return handle_nxst_flow(ofconn, msg->data); case OFPUTIL_NXST_AGGREGATE_REQUEST: return handle_nxst_aggregate(ofconn, msg->data);