}
if (!rates->xid) {
struct ofp_stats_request *rq;
+ struct ofp_port_stats_request *psr;
struct ofpbuf *b;
rates->xid = random_uint32();
rates->xid, &b);
rq->type = htons(OFPST_PORT);
rq->flags = htons(0);
+ psr = ofbuf_put_uninit(b, sizeof *psr);
+ memset(psr, 0, sizeof *psr);
+ psr->port_no = htons(OFPP_NONE);
+ update_openflow_length(b);
rconn_send_with_limit(rates->rconn, b, counter, 10);
}
OFPST_TABLE,
/* Physical port statistics.
- * The request body is empty.
+ * The request body is struct ofp_port_stats_request.
* The reply body is an array of struct ofp_port_stats. */
OFPST_PORT,
};
OFP_ASSERT(sizeof(struct ofp_table_stats) == 64);
+/* Body for ofp_stats_request of type OFPST_PORT. */
+struct ofp_port_stats_request {
+ uint16_t 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);
+
/* Body of reply to OFPST_PORT request. If a counter is unsupported, set
* the field to all ones. */
struct ofp_port_stats {
}
}
+static void
+ofp_port_stats_request(struct ds *string, const void *body_,
+ size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+{
+ const struct ofp_port_stats_request *psr = body_;
+ ds_put_format(string, "port_no=%"PRIu16, ntohs(psr->port_no));
+}
+
static void
ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
int verbosity)
{
OFPST_PORT,
"port",
- { 0, 0, NULL, },
+ { sizeof(struct ofp_port_stats_request),
+ sizeof(struct ofp_port_stats_request),
+ ofp_port_stats_request },
{ 0, SIZE_MAX, ofp_port_stats_reply },
},
{
return 0;
}
+static void
+append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn,
+ struct ofpbuf *msg)
+{
+ struct netdev_stats stats;
+ struct ofp_port_stats *ops;
+
+ /* Intentionally ignore return value, since errors will set
+ * 'stats' to all-1s, which is correct for OpenFlow, and
+ * netdev_get_stats() will log errors. */
+ netdev_get_stats(port->netdev, &stats);
+
+ ops = append_stats_reply(sizeof *ops, ofconn, &msg);
+ ops->port_no = htons(odp_port_to_ofp_port(port_no));
+ memset(ops->pad, 0, sizeof ops->pad);
+ ops->rx_packets = htonll(stats.rx_packets);
+ ops->tx_packets = htonll(stats.tx_packets);
+ ops->rx_bytes = htonll(stats.rx_bytes);
+ ops->tx_bytes = htonll(stats.tx_bytes);
+ ops->rx_dropped = htonll(stats.rx_dropped);
+ ops->tx_dropped = htonll(stats.tx_dropped);
+ ops->rx_errors = htonll(stats.rx_errors);
+ ops->tx_errors = htonll(stats.tx_errors);
+ ops->rx_frame_err = htonll(stats.rx_frame_errors);
+ ops->rx_over_err = htonll(stats.rx_over_errors);
+ ops->rx_crc_err = htonll(stats.rx_crc_errors);
+ ops->collisions = htonll(stats.collisions);
+}
+
static int
handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
- struct ofp_stats_request *request)
+ struct ofp_stats_request *osr,
+ size_t arg_size)
{
+ struct ofp_port_stats_request *psr;
struct ofp_port_stats *ops;
struct ofpbuf *msg;
struct ofport *port;
unsigned int port_no;
- msg = start_stats_reply(request, sizeof *ops * 16);
- PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
- struct netdev_stats stats;
-
- /* Intentionally ignore return value, since errors will set 'stats' to
- * all-1s, which is correct for OpenFlow, and netdev_get_stats() will
- * log errors. */
- netdev_get_stats(port->netdev, &stats);
-
- ops = append_stats_reply(sizeof *ops, ofconn, &msg);
- ops->port_no = htons(odp_port_to_ofp_port(port_no));
- memset(ops->pad, 0, sizeof ops->pad);
- ops->rx_packets = htonll(stats.rx_packets);
- ops->tx_packets = htonll(stats.tx_packets);
- ops->rx_bytes = htonll(stats.rx_bytes);
- ops->tx_bytes = htonll(stats.tx_bytes);
- ops->rx_dropped = htonll(stats.rx_dropped);
- ops->tx_dropped = htonll(stats.tx_dropped);
- ops->rx_errors = htonll(stats.rx_errors);
- ops->tx_errors = htonll(stats.tx_errors);
- ops->rx_frame_err = htonll(stats.rx_frame_errors);
- ops->rx_over_err = htonll(stats.rx_over_errors);
- ops->rx_crc_err = htonll(stats.rx_crc_errors);
- ops->collisions = htonll(stats.collisions);
+ if (arg_size != sizeof *psr) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+ psr = (struct ofp_port_stats_request *) osr->body;
+
+ msg = start_stats_reply(osr, sizeof *ops * 16);
+ if (psr->port_no != htons(OFPP_NONE)) {
+ port = port_array_get(&p->ports,
+ ofp_port_to_odp_port(ntohs(psr->port_no)));
+ if (port) {
+ append_port_stat(port, ntohs(psr->port_no), ofconn, msg);
+ }
+ } else {
+ PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
+ append_port_stat(port, port_no, ofconn, msg);
+ }
}
queue_tx(msg, ofconn, ofconn->reply_counter);
return handle_table_stats_request(p, ofconn, osr);
case OFPST_PORT:
- return handle_port_stats_request(p, ofconn, osr);
+ return handle_port_stats_request(p, ofconn, osr, arg_size);
case OFPST_VENDOR:
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
\fIswitch\fR.
.TP
-\fBdump-ports \fIswitch\fR
-Prints to the console statistics for each of the network devices
-associated with \fIswitch\fR.
+\fBdump-ports \fIswitch\fR [\fInetdev\fR]
+Prints to the console statistics for network devices associated with
+\fIswitch\fR. If \fInetdev\fR is specified, only the statistics
+associated with that device will be printed. \fInetdev\fR can be an
+OpenFlow assigned port number or device name, e.g. \fBeth0\fR.
.TP
\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR
" dump-desc SWITCH print switch description\n"
" dump-tables SWITCH print table stats\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
- " dump-ports SWITCH print port statistics\n"
+ " dump-ports SWITCH [PORT] print port statistics\n"
" dump-flows SWITCH print all flow entries\n"
" dump-flows SWITCH FLOW print matching FLOWs\n"
" dump-aggregate SWITCH print aggregate flow statistics\n"
return n_wild;
}
+static uint16_t
+str_to_port_no(const char *vconn_name, const char *str)
+{
+ struct ofpbuf *request, *reply;
+ struct ofp_switch_features *osf;
+ struct vconn *vconn;
+ int n_ports;
+ int port_idx;
+ unsigned int port_no;
+
+
+ /* Check if the argument is a port index. Otherwise, treat it as
+ * the port name. */
+ if (str_to_uint(str, 10, &port_no)) {
+ return port_no;
+ }
+
+ /* Send a "Features Request" to resolve the name into a number. */
+ make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
+ open_vconn(vconn_name, &vconn);
+ run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
+
+ osf = reply->data;
+ n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
+
+ for (port_idx = 0; port_idx < n_ports; port_idx++) {
+ /* Check argument as an interface name */
+ if (!strncmp((char *)osf->ports[port_idx].name, str,
+ sizeof osf->ports[0].name)) {
+ break;
+ }
+ }
+ if (port_idx == n_ports) {
+ ovs_fatal(0, "couldn't find monitored port: %s", str);
+ }
+
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
+
+ return port_idx;
+}
+
static void *
put_action(struct ofpbuf *b, size_t size, uint16_t type)
{
}
static void
-do_dump_ports(int argc OVS_UNUSED, char *argv[])
+do_dump_ports(int argc, char *argv[])
{
- dump_trivial_stats_transaction(argv[1], OFPST_PORT);
+ struct ofp_port_stats_request *req;
+ struct ofpbuf *request;
+ uint16_t port;
+
+ req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
+ port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
+ req->port_no = htons(port);
+ dump_stats_transaction(argv[1], request);
}
static void
{ "add-flows", 2, 2, do_add_flows },
{ "mod-flows", 2, 2, do_mod_flows },
{ "del-flows", 1, 2, do_del_flows },
- { "dump-ports", 1, 1, do_dump_ports },
+ { "dump-ports", 1, 2, do_dump_ports },
{ "mod-port", 3, 3, do_mod_port },
{ "probe", 1, 1, do_probe },
{ "ping", 1, 2, do_ping },