+ if (arg_size != sizeof *asr) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+ asr = (struct ofp_aggregate_stats_request *) osr->body;
+
+ COVERAGE_INC(ofproto_agg_request);
+ cbdata.ofproto = p;
+ cbdata.out_port = asr->out_port;
+ cbdata.packet_count = 0;
+ cbdata.byte_count = 0;
+ cbdata.n_flows = 0;
+ cls_rule_from_match(&asr->match, 0, false, 0, &target);
+ classifier_for_each_match(&p->cls, &target,
+ table_id_to_include(asr->table_id),
+ aggregate_stats_cb, &cbdata);
+
+ msg = start_stats_reply(osr, sizeof *reply);
+ reply = append_stats_reply(sizeof *reply, ofconn, &msg);
+ reply->flow_count = htonl(cbdata.n_flows);
+ reply->packet_count = htonll(cbdata.packet_count);
+ reply->byte_count = htonll(cbdata.byte_count);
+ queue_tx(msg, ofconn, ofconn->reply_counter);
+ return 0;
+}
+
+struct queue_stats_cbdata {
+ struct ofconn *ofconn;
+ struct ofport *ofport;
+ struct ofpbuf *msg;
+};
+
+static void
+put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
+ const struct netdev_queue_stats *stats)
+{
+ struct ofp_queue_stats *reply;
+
+ reply = append_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg);
+ reply->port_no = htons(cbdata->ofport->opp.port_no);
+ memset(reply->pad, 0, sizeof reply->pad);
+ reply->queue_id = htonl(queue_id);
+ reply->tx_bytes = htonll(stats->tx_bytes);
+ reply->tx_packets = htonll(stats->tx_packets);
+ reply->tx_errors = htonll(stats->tx_errors);
+}
+
+static void
+handle_queue_stats_dump_cb(uint32_t queue_id,
+ struct netdev_queue_stats *stats,
+ void *cbdata_)
+{
+ struct queue_stats_cbdata *cbdata = cbdata_;
+
+ put_queue_stats(cbdata, queue_id, stats);
+}
+
+static void
+handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id,
+ struct queue_stats_cbdata *cbdata)
+{
+ cbdata->ofport = port;
+ if (queue_id == OFPQ_ALL) {
+ netdev_dump_queue_stats(port->netdev,
+ handle_queue_stats_dump_cb, cbdata);
+ } else {
+ struct netdev_queue_stats stats;
+
+ netdev_get_queue_stats(port->netdev, queue_id, &stats);
+ put_queue_stats(cbdata, queue_id, &stats);
+ }
+}
+
+static int
+handle_queue_stats_request(struct ofproto *ofproto, struct ofconn *ofconn,
+ const struct ofp_stats_request *osr,
+ size_t arg_size)
+{
+ struct ofp_queue_stats_request *qsr;
+ struct queue_stats_cbdata cbdata;
+ struct ofport *port;
+ unsigned int port_no;
+ uint32_t queue_id;
+
+ if (arg_size != sizeof *qsr) {