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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 },
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user