* Rework tag order. I'm not sure whether we need to do anything
for this.
- * Duration for queue stats. (Duration for port stats is already
- implemented.)
-
* On-demand flow counters. I think this might be a real
optimization in some cases for the software switch.
struct tc_queue {
struct hmap_node hmap_node; /* In struct tc's "queues" hmap. */
unsigned int queue_id; /* OpenFlow queue ID. */
+ long long int created; /* Time queue was created, in msecs. */
};
/* A particular kind of traffic control. Each implementation generally maps to
return EOPNOTSUPP;
} else {
const struct tc_queue *queue = tc_find_queue(netdev_, queue_id);
- return (queue
- ? netdev->tc->ops->class_get_stats(netdev_, queue, stats)
- : ENOENT);
+ if (!queue) {
+ return ENOENT;
+ }
+ stats->created = queue->created;
+ return netdev->tc->ops->class_get_stats(netdev_, queue, stats);
}
}
hcp = xmalloc(sizeof *hcp);
queue = &hcp->tc_queue;
queue->queue_id = queue_id;
+ queue->created = time_msec();
hmap_insert(&htb->tc.queues, &queue->hmap_node, hash);
}
hcp = xmalloc(sizeof *hcp);
queue = &hcp->tc_queue;
queue->queue_id = queue_id;
+ queue->created = time_msec();
hmap_insert(&hfsc->tc.queues, &queue->hmap_node, hash);
}
/* Obtains statistics about 'queue_id' on 'netdev'. On success, returns 0 and
* fills 'stats' with the queue's statistics; individual members of 'stats' may
* be set to all-1-bits if the statistic is unavailable. On failure, returns a
- * positive errno value and fills 'stats' with all-1-bits. */
+ * positive errno value and fills 'stats' with values indicating unsupported
+ * statistics. */
int
netdev_get_queue_stats(const struct netdev *netdev, unsigned int queue_id,
struct netdev_queue_stats *stats)
? class->get_queue_stats(netdev, queue_id, stats)
: EOPNOTSUPP);
if (retval) {
- memset(stats, 0xff, sizeof *stats);
+ stats->tx_bytes = UINT64_MAX;
+ stats->tx_packets = UINT64_MAX;
+ stats->tx_errors = UINT64_MAX;
+ stats->created = LLONG_MIN;
}
return retval;
}
uint64_t tx_bytes;
uint64_t tx_packets;
uint64_t tx_errors;
+
+ /* Time at which the queue was created, in msecs, LLONG_MIN if unknown. */
+ long long int created;
};
int netdev_set_policing(struct netdev *, uint32_t kbits_rate,
ofp_print_queue_name(string, qs.queue_id);
ds_put_cstr(string, ": ");
- print_port_stat(string, "bytes=", qs.stats.tx_bytes, 1);
- print_port_stat(string, "pkts=", qs.stats.tx_packets, 1);
- print_port_stat(string, "errors=", qs.stats.tx_errors, 0);
+ print_port_stat(string, "bytes=", qs.tx_bytes, 1);
+ print_port_stat(string, "pkts=", qs.tx_packets, 1);
+ print_port_stat(string, "errors=", qs.tx_errors, 1);
+
+ ds_put_cstr(string, "duration=");
+ if (qs.duration_sec != UINT32_MAX) {
+ ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
+ } else {
+ ds_put_char(string, '?');
+ }
+ ds_put_char(string, '\n');
}
}
{
oqs->port_no = u16_to_ofp(ntohs(qs10->port_no));
oqs->queue_id = ntohl(qs10->queue_id);
- oqs->stats.tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
- oqs->stats.tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
- oqs->stats.tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
+ oqs->tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
+ oqs->tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
+ oqs->tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
+ oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
return 0;
}
}
oqs->queue_id = ntohl(qs11->queue_id);
- oqs->stats.tx_bytes = ntohll(qs11->tx_bytes);
- oqs->stats.tx_packets = ntohll(qs11->tx_packets);
- oqs->stats.tx_errors = ntohll(qs11->tx_errors);
+ oqs->tx_bytes = ntohll(qs11->tx_bytes);
+ oqs->tx_packets = ntohll(qs11->tx_packets);
+ oqs->tx_errors = ntohll(qs11->tx_errors);
+ oqs->duration_sec = oqs->duration_nsec = UINT32_MAX;
return 0;
}
ofputil_queue_stats_from_ofp13(struct ofputil_queue_stats *oqs,
const struct ofp13_queue_stats *qs13)
{
- enum ofperr error
- = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
+ enum ofperr error = ofputil_queue_stats_from_ofp11(oqs, &qs13->qs);
if (!error) {
- /* FIXME: Get qs13->duration_sec and qs13->duration_nsec,
- * Add to netdev_queue_stats? */
+ oqs->duration_sec = ntohl(qs13->duration_sec);
+ oqs->duration_nsec = ntohl(qs13->duration_nsec);
}
return error;
qs10->port_no = htons(ofp_to_u16(oqs->port_no));
memset(qs10->pad, 0, sizeof qs10->pad);
qs10->queue_id = htonl(oqs->queue_id);
- put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->stats.tx_bytes));
- put_32aligned_be64(&qs10->tx_packets, htonll(oqs->stats.tx_packets));
- put_32aligned_be64(&qs10->tx_errors, htonll(oqs->stats.tx_errors));
+ put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->tx_bytes));
+ put_32aligned_be64(&qs10->tx_packets, htonll(oqs->tx_packets));
+ put_32aligned_be64(&qs10->tx_errors, htonll(oqs->tx_errors));
}
static void
{
qs11->port_no = ofputil_port_to_ofp11(oqs->port_no);
qs11->queue_id = htonl(oqs->queue_id);
- qs11->tx_bytes = htonll(oqs->stats.tx_bytes);
- qs11->tx_packets = htonll(oqs->stats.tx_packets);
- qs11->tx_errors = htonll(oqs->stats.tx_errors);
+ qs11->tx_bytes = htonll(oqs->tx_bytes);
+ qs11->tx_packets = htonll(oqs->tx_packets);
+ qs11->tx_errors = htonll(oqs->tx_errors);
}
static void
struct ofp13_queue_stats *qs13)
{
ofputil_queue_stats_to_ofp11(oqs, &qs13->qs);
- /* OF 1.3 adds duration fields */
- /* FIXME: Need to implement queue alive duration (sec + nsec) */
- qs13->duration_sec = htonl(~0);
- qs13->duration_nsec = htonl(~0);
+ if (oqs->duration_sec != UINT32_MAX) {
+ qs13->duration_sec = htonl(oqs->duration_sec);
+ qs13->duration_nsec = htonl(oqs->duration_nsec);
+ } else {
+ qs13->duration_sec = htonl(UINT32_MAX);
+ qs13->duration_nsec = htonl(UINT32_MAX);
+ }
}
/* Encode a queue stat for 'oqs' and append it to 'replies'. */
struct ofputil_queue_stats {
ofp_port_t port_no;
uint32_t queue_id;
- struct netdev_queue_stats stats;
+
+ /* Values of unsupported statistics are set to all-1-bits (UINT64_MAX). */
+ uint64_t tx_bytes;
+ uint64_t tx_packets;
+ uint64_t tx_errors;
+
+ /* UINT32_MAX if unknown. */
+ uint32_t duration_sec;
+ uint32_t duration_nsec;
};
size_t ofputil_count_queue_stats(const struct ofp_header *);
struct queue_stats_cbdata {
struct ofport *ofport;
struct list replies;
+ long long int now;
};
static void
put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
const struct netdev_queue_stats *stats)
{
+ struct ofputil_queue_stats oqs;
- struct ofputil_queue_stats oqs = {
- .port_no = cbdata->ofport->pp.port_no,
- .queue_id = queue_id,
- .stats = *stats,
- };
+ oqs.port_no = cbdata->ofport->pp.port_no;
+ oqs.queue_id = queue_id;
+ oqs.tx_bytes = stats->tx_bytes;
+ oqs.tx_packets = stats->tx_packets;
+ oqs.tx_errors = stats->tx_errors;
+ if (stats->created != LLONG_MIN) {
+ calc_duration(stats->created, cbdata->now,
+ &oqs.duration_sec, &oqs.duration_nsec);
+ } else {
+ oqs.duration_sec = oqs.duration_nsec = UINT32_MAX;
+ }
ofputil_append_queue_stat(&cbdata->replies, &oqs);
}
COVERAGE_INC(ofproto_queue_req);
ofpmp_init(&cbdata.replies, rq);
+ cbdata.now = time_msec();
error = ofputil_decode_queue_stats_request(rq, &oqsr);
if (error) {
00 00 00 00 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPST_QUEUE reply (xid=0x1): 6 queues
- port 3 queue 1: bytes=302, pkts=1, errors=0
- port 3 queue 2: bytes=0, pkts=0, errors=0
- port 2 queue 1: bytes=2100, pkts=20, errors=0
- port 2 queue 2: bytes=0, pkts=0, errors=0
- port 1 queue 1: bytes=0, pkts=0, errors=0
- port 1 queue 2: bytes=0, pkts=0, errors=0
+ port 3 queue 1: bytes=302, pkts=1, errors=0, duration=?
+ port 3 queue 2: bytes=0, pkts=0, errors=0, duration=?
+ port 2 queue 1: bytes=2100, pkts=20, errors=0, duration=?
+ port 2 queue 2: bytes=0, pkts=0, errors=0, duration=?
+ port 1 queue 1: bytes=0, pkts=0, errors=0, duration=?
+ port 1 queue 2: bytes=0, pkts=0, errors=0, duration=?
])
AT_CLEANUP
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPST_QUEUE reply (OF1.1) (xid=0x1): 6 queues
- port 3 queue 1: bytes=302, pkts=1, errors=0
- port 3 queue 2: bytes=0, pkts=0, errors=0
- port 2 queue 1: bytes=2100, pkts=20, errors=0
- port 2 queue 2: bytes=0, pkts=0, errors=0
- port 1 queue 1: bytes=0, pkts=0, errors=0
- port 1 queue 2: bytes=0, pkts=0, errors=0
+ port 3 queue 1: bytes=302, pkts=1, errors=0, duration=?
+ port 3 queue 2: bytes=0, pkts=0, errors=0, duration=?
+ port 2 queue 1: bytes=2100, pkts=20, errors=0, duration=?
+ port 2 queue 2: bytes=0, pkts=0, errors=0, duration=?
+ port 1 queue 1: bytes=0, pkts=0, errors=0, duration=?
+ port 1 queue 2: bytes=0, pkts=0, errors=0, duration=?
])
AT_CLEANUP
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPST_QUEUE reply (OF1.2) (xid=0x1): 6 queues
- port 3 queue 1: bytes=302, pkts=1, errors=0
- port 3 queue 2: bytes=0, pkts=0, errors=0
- port 2 queue 1: bytes=2100, pkts=20, errors=0
- port 2 queue 2: bytes=0, pkts=0, errors=0
- port 1 queue 1: bytes=0, pkts=0, errors=0
- port 1 queue 2: bytes=0, pkts=0, errors=0
+ port 3 queue 1: bytes=302, pkts=1, errors=0, duration=?
+ port 3 queue 2: bytes=0, pkts=0, errors=0, duration=?
+ port 2 queue 1: bytes=2100, pkts=20, errors=0, duration=?
+ port 2 queue 2: bytes=0, pkts=0, errors=0, duration=?
+ port 1 queue 1: bytes=0, pkts=0, errors=0, duration=?
+ port 1 queue 2: bytes=0, pkts=0, errors=0, duration=?
+])
+AT_CLEANUP
AT_SETUP([OFPST_QUEUE reply - OF1.3])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
ff ff ff ff ff ff ff ff \
"], [0], [dnl
OFPST_QUEUE reply (OF1.3) (xid=0x1): 6 queues
- port 3 queue 1: bytes=302, pkts=1, errors=0
- port 3 queue 2: bytes=0, pkts=0, errors=0
- port 2 queue 1: bytes=2100, pkts=20, errors=0
- port 2 queue 2: bytes=0, pkts=0, errors=0
- port 1 queue 1: bytes=0, pkts=0, errors=0
- port 1 queue 2: bytes=0, pkts=0, errors=0
+ port 3 queue 1: bytes=302, pkts=1, errors=0, duration=100.5s
+ port 3 queue 2: bytes=0, pkts=0, errors=0, duration=100.5s
+ port 2 queue 1: bytes=2100, pkts=20, errors=0, duration=100.5s
+ port 2 queue 2: bytes=0, pkts=0, errors=0, duration=100.5s
+ port 1 queue 1: bytes=0, pkts=0, errors=0, duration=100.5s
+ port 1 queue 2: bytes=0, pkts=0, errors=0, duration=?
])
AT_CLEANUP