2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-29 15:28:56 +00:00

ofproto: Querying port stats for individual ports (OpenFlow 1.0)

OpenFlow 1.0 adds "port_no" field to the Port Stat request messages to
allow stats for individual ports to be queried.  Port stats for all ports
can still be requested by specifying OFPP_NONE as the port number.

NOTE: OVS at this point is not wire-compatible with OpenFlow 1.0 until
the final commit in this OpenFlow 1.0 set.
This commit is contained in:
Justin Pettit
2010-01-19 22:35:18 -08:00
parent 834377ea55
commit abaad8cf1b
6 changed files with 132 additions and 34 deletions

View File

@@ -1105,6 +1105,7 @@ do_show_data_rates(void *rates_)
}
if (!rates->xid) {
struct ofp_stats_request *rq;
struct ofp_port_stats_request *psr;
struct ofpbuf *b;
rates->xid = random_uint32();
@@ -1112,6 +1113,10 @@ do_show_data_rates(void *rates_)
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);
}

View File

@@ -693,7 +693,7 @@ enum ofp_stats_types {
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,
@@ -807,6 +807,15 @@ struct ofp_table_stats {
};
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 {

View File

@@ -1063,6 +1063,14 @@ static void print_port_stat(struct ds *string, const char *leader,
}
}
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)
@@ -1187,7 +1195,9 @@ print_stats(struct ds *string, int type, const void *body, size_t body_len,
{
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 },
},
{

View File

@@ -2458,22 +2458,16 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn,
return 0;
}
static int
handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
struct ofp_stats_request *request)
static void
append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn,
struct ofpbuf *msg)
{
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;
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. */
/* 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);
@@ -2491,6 +2485,35 @@ handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
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 *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;
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);
@@ -2763,7 +2786,7 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
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);

View File

@@ -60,9 +60,11 @@ Prints to the console statistics for each of the flow tables used by
\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

View File

@@ -153,7 +153,7 @@ usage(void)
" 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"
@@ -469,6 +469,48 @@ str_to_ip(const char *str_, uint32_t *ip)
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)
{
@@ -995,9 +1037,16 @@ do_monitor(int argc OVS_UNUSED, char *argv[])
}
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
@@ -1205,7 +1254,7 @@ static const struct command all_commands[] = {
{ "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 },