mirror of
https://github.com/openvswitch/ovs
synced 2025-09-03 07:45:30 +00:00
Implement OpenFlow 1.5 port desc stats request.
OpenFlow 1.4 and earlier always send the description of every port in response to an OFPMP_PORT_DESC request. OpenFlow 1.5 proposes allowing the controller to request a description of a single port. This commit implements a prototype. EXT-69. Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
@@ -367,8 +367,10 @@ enum ofpraw {
|
||||
/* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */
|
||||
OFPRAW_OFPST13_TABLE_FEATURES_REPLY,
|
||||
|
||||
/* OFPST 1.0+ (13): void. */
|
||||
OFPRAW_OFPST_PORT_DESC_REQUEST,
|
||||
/* OFPST 1.0-1.4 (13): void. */
|
||||
OFPRAW_OFPST10_PORT_DESC_REQUEST,
|
||||
/* OFPST 1.5+ (13): ovs_be32. */
|
||||
OFPRAW_OFPST15_PORT_DESC_REQUEST,
|
||||
|
||||
/* OFPST 1.0 (13): struct ofp10_phy_port[]. */
|
||||
OFPRAW_OFPST10_PORT_DESC_REPLY,
|
||||
@@ -598,7 +600,8 @@ enum ofptype {
|
||||
|
||||
OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */
|
||||
|
||||
OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
|
||||
OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST10_PORT_DESC_REQUEST.
|
||||
* OFPRAW_OFPST15_PORT_DESC_REQUEST. */
|
||||
|
||||
OFPTYPE_PORT_DESC_STATS_REPLY, /* OFPRAW_OFPST10_PORT_DESC_REPLY.
|
||||
* OFPRAW_OFPST11_PORT_DESC_REPLY.
|
||||
|
@@ -1899,6 +1899,23 @@ ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ofp_print_ofpst_port_desc_request(struct ds *string,
|
||||
const struct ofp_header *oh)
|
||||
{
|
||||
enum ofperr error;
|
||||
ofp_port_t port;
|
||||
|
||||
error = ofputil_decode_port_desc_stats_request(oh, &port);
|
||||
if (error) {
|
||||
ofp_print_error(string, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ds_put_cstr(string, " port=");
|
||||
ofputil_format_port(port, string);
|
||||
}
|
||||
|
||||
static void
|
||||
ofp_print_ofpst_port_desc_reply(struct ds *string,
|
||||
const struct ofp_header *oh)
|
||||
@@ -2917,7 +2934,6 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
|
||||
break;
|
||||
|
||||
case OFPTYPE_DESC_STATS_REQUEST:
|
||||
case OFPTYPE_PORT_DESC_STATS_REQUEST:
|
||||
case OFPTYPE_METER_FEATURES_STATS_REQUEST:
|
||||
ofp_print_stats_request(string, oh);
|
||||
break;
|
||||
@@ -2972,6 +2988,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
|
||||
ofp_print_aggregate_stats_reply(string, oh);
|
||||
break;
|
||||
|
||||
case OFPTYPE_PORT_DESC_STATS_REQUEST:
|
||||
ofp_print_stats_request(string, oh);
|
||||
ofp_print_ofpst_port_desc_request(string, oh);
|
||||
break;
|
||||
|
||||
case OFPTYPE_PORT_DESC_STATS_REPLY:
|
||||
ofp_print_stats_reply(string, oh);
|
||||
ofp_print_ofpst_port_desc_reply(string, oh);
|
||||
|
@@ -3928,6 +3928,59 @@ ofputil_put_phy_port(enum ofp_version ofp_version,
|
||||
}
|
||||
}
|
||||
|
||||
enum ofperr
|
||||
ofputil_decode_port_desc_stats_request(const struct ofp_header *request,
|
||||
ofp_port_t *port)
|
||||
{
|
||||
struct ofpbuf b;
|
||||
enum ofpraw raw;
|
||||
|
||||
ofpbuf_use_const(&b, request, ntohs(request->length));
|
||||
raw = ofpraw_pull_assert(&b);
|
||||
if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) {
|
||||
*port = OFPP_ANY;
|
||||
return 0;
|
||||
} else if (raw == OFPRAW_OFPST15_PORT_DESC_REQUEST) {
|
||||
ovs_be32 *ofp11_port;
|
||||
|
||||
ofp11_port = ofpbuf_pull(&b, sizeof *ofp11_port);
|
||||
return ofputil_port_from_ofp11(*ofp11_port, port);
|
||||
} else {
|
||||
OVS_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
struct ofpbuf *
|
||||
ofputil_encode_port_desc_stats_request(enum ofp_version ofp_version,
|
||||
ofp_port_t port)
|
||||
{
|
||||
struct ofpbuf *request;
|
||||
ovs_be32 ofp11_port;
|
||||
|
||||
switch (ofp_version) {
|
||||
case OFP10_VERSION:
|
||||
case OFP11_VERSION:
|
||||
case OFP12_VERSION:
|
||||
case OFP13_VERSION:
|
||||
case OFP14_VERSION:
|
||||
request = ofpraw_alloc(OFPRAW_OFPST10_PORT_DESC_REQUEST,
|
||||
ofp_version, 0);
|
||||
break;
|
||||
|
||||
case OFP15_VERSION:
|
||||
request = ofpraw_alloc(OFPRAW_OFPST15_PORT_DESC_REQUEST,
|
||||
ofp_version, 0);
|
||||
ofp11_port = ofputil_port_to_ofp11(port);
|
||||
ofpbuf_put(request, &ofp11_port, sizeof ofp11_port);
|
||||
break;
|
||||
|
||||
default:
|
||||
OVS_NOT_REACHED();
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void
|
||||
ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
|
||||
struct list *replies)
|
||||
|
@@ -875,7 +875,12 @@ void ofputil_append_flow_update(const struct ofputil_flow_update *,
|
||||
uint32_t ofputil_decode_flow_monitor_cancel(const struct ofp_header *);
|
||||
struct ofpbuf *ofputil_encode_flow_monitor_cancel(uint32_t id);
|
||||
|
||||
/* Encoding OpenFlow stats messages. */
|
||||
/* Port desc stats requests and replies. */
|
||||
enum ofperr ofputil_decode_port_desc_stats_request(const struct ofp_header *,
|
||||
ofp_port_t *portp);
|
||||
struct ofpbuf *ofputil_encode_port_desc_stats_request(
|
||||
enum ofp_version ofp_version, ofp_port_t);
|
||||
|
||||
void ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
|
||||
struct list *replies);
|
||||
|
||||
|
@@ -3170,52 +3170,62 @@ append_port_stat(struct ofport *port, struct list *replies)
|
||||
ofputil_append_port_stat(replies, &ops);
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
handle_port_stats_request(struct ofconn *ofconn,
|
||||
const struct ofp_header *request)
|
||||
static void
|
||||
handle_port_request(struct ofconn *ofconn,
|
||||
const struct ofp_header *request, ofp_port_t port_no,
|
||||
void (*cb)(struct ofport *, struct list *replies))
|
||||
{
|
||||
struct ofproto *p = ofconn_get_ofproto(ofconn);
|
||||
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
|
||||
struct ofport *port;
|
||||
struct list replies;
|
||||
ofp_port_t port_no;
|
||||
enum ofperr error;
|
||||
|
||||
error = ofputil_decode_port_stats_request(request, &port_no);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
ofpmp_init(&replies, request);
|
||||
if (port_no != OFPP_ANY) {
|
||||
port = ofproto_get_port(p, port_no);
|
||||
port = ofproto_get_port(ofproto, port_no);
|
||||
if (port) {
|
||||
append_port_stat(port, &replies);
|
||||
cb(port, &replies);
|
||||
}
|
||||
} else {
|
||||
HMAP_FOR_EACH (port, hmap_node, &p->ports) {
|
||||
append_port_stat(port, &replies);
|
||||
HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
|
||||
cb(port, &replies);
|
||||
}
|
||||
}
|
||||
|
||||
ofconn_send_replies(ofconn, &replies);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
handle_port_stats_request(struct ofconn *ofconn,
|
||||
const struct ofp_header *request)
|
||||
{
|
||||
ofp_port_t port_no;
|
||||
enum ofperr error;
|
||||
|
||||
error = ofputil_decode_port_stats_request(request, &port_no);
|
||||
if (!error) {
|
||||
handle_port_request(ofconn, request, port_no, append_port_stat);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
append_port_desc(struct ofport *port, struct list *replies)
|
||||
{
|
||||
ofputil_append_port_desc_stats_reply(&port->pp, replies);
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
handle_port_desc_stats_request(struct ofconn *ofconn,
|
||||
const struct ofp_header *request)
|
||||
{
|
||||
struct ofproto *p = ofconn_get_ofproto(ofconn);
|
||||
struct ofport *port;
|
||||
struct list replies;
|
||||
ofp_port_t port_no;
|
||||
enum ofperr error;
|
||||
|
||||
ofpmp_init(&replies, request);
|
||||
HMAP_FOR_EACH (port, hmap_node, &p->ports) {
|
||||
ofputil_append_port_desc_stats_reply(&port->pp, &replies);
|
||||
error = ofputil_decode_port_desc_stats_request(request, &port_no);
|
||||
if (!error) {
|
||||
handle_port_request(ofconn, request, port_no, append_port_desc);
|
||||
}
|
||||
|
||||
ofconn_send_replies(ofconn, &replies);
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
@@ -1943,7 +1943,16 @@ AT_CLEANUP
|
||||
AT_SETUP([OFPST_PORT_DESC request - OF1.0])
|
||||
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
|
||||
AT_CHECK([ovs-ofctl ofp-print "0110000c00000001000d0000"], [0], [dnl
|
||||
OFPST_PORT_DESC request (xid=0x1):
|
||||
OFPST_PORT_DESC request (xid=0x1): port=ANY
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([OFPST_PORT_DESC request - OF1.5])
|
||||
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
|
||||
AT_CHECK([ovs-ofctl ofp-print "\
|
||||
06 12 00 14 00 00 00 02 00 0d 00 00 00 00 00 00 \
|
||||
00 00 00 05"], [0], [dnl
|
||||
OFPST_PORT_DESC request (OF1.5) (xid=0x2): port=5
|
||||
])
|
||||
AT_CLEANUP
|
||||
|
||||
|
@@ -144,6 +144,40 @@ OFPST_PORT_DESC reply (OF1.2):
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([ofproto - port-desc stats (OpenFlow 1.5)])
|
||||
OVS_VSWITCHD_START
|
||||
ADD_OF_PORTS([br0], 1, 2, 3)
|
||||
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-ports-desc br0], [0], [stdout])
|
||||
AT_CHECK([STRIP_XIDS stdout | sed 's/00:0./00:0x/'], [0], [dnl
|
||||
OFPST_PORT_DESC reply (OF1.5):
|
||||
1(p1): addr:aa:55:aa:55:00:0x
|
||||
config: PORT_DOWN
|
||||
state: LINK_DOWN
|
||||
speed: 0 Mbps now, 0 Mbps max
|
||||
2(p2): addr:aa:55:aa:55:00:0x
|
||||
config: PORT_DOWN
|
||||
state: LINK_DOWN
|
||||
speed: 0 Mbps now, 0 Mbps max
|
||||
3(p3): addr:aa:55:aa:55:00:0x
|
||||
config: PORT_DOWN
|
||||
state: LINK_DOWN
|
||||
speed: 0 Mbps now, 0 Mbps max
|
||||
LOCAL(br0): addr:aa:55:aa:55:00:0x
|
||||
config: PORT_DOWN
|
||||
state: LINK_DOWN
|
||||
speed: 0 Mbps now, 0 Mbps max
|
||||
])
|
||||
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-ports-desc br0 2], [0], [stdout])
|
||||
AT_CHECK([STRIP_XIDS stdout | sed 's/00:0./00:0x/'], [0], [dnl
|
||||
OFPST_PORT_DESC reply (OF1.5):
|
||||
2(p2): addr:aa:55:aa:55:00:0x
|
||||
config: PORT_DOWN
|
||||
state: LINK_DOWN
|
||||
speed: 0 Mbps now, 0 Mbps max
|
||||
])
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
dnl This is really bare-bones.
|
||||
dnl It at least checks request and reply serialization and deserialization.
|
||||
AT_SETUP([ofproto - queue stats - (OpenFlow 1.0)])
|
||||
|
@@ -70,11 +70,19 @@ Prints to the console statistics for network devices associated with
|
||||
associated with that device will be printed. \fInetdev\fR can be an
|
||||
OpenFlow assigned port number or device name, e.g. \fBeth0\fR.
|
||||
.
|
||||
.TP
|
||||
\fBdump\-ports\-desc \fIswitch\fR
|
||||
.IP "\fBdump\-ports\-desc \fIswitch\fR [\fIport\fR]"
|
||||
Prints to the console detailed information about network devices
|
||||
associated with \fIswitch\fR (version 1.7 or later). This is a subset
|
||||
of the information provided by the \fBshow\fR command.
|
||||
associated with \fIswitch\fR. To dump only a specific port, specify
|
||||
its number as \fIport\fR. Otherwise, if \fIport\fR is omitted, or if
|
||||
it is specified as \fBANY\fR, then all ports are printed. This is a
|
||||
subset of the information provided by the \fBshow\fR command.
|
||||
.IP
|
||||
If the connection to \fIswitch\fR negotiates OpenFlow 1.0, 1.2, or
|
||||
1.2, this command uses an OpenFlow extension only implemented in Open
|
||||
vSwitch (version 1.7 and later).
|
||||
.IP
|
||||
Only OpenFlow 1.5 and later support dumping a specific port. Earlier
|
||||
versions of OpenFlow always dump all ports.
|
||||
.
|
||||
.IP "\fBmod\-port \fIswitch\fR \fIport\fR \fIaction\fR"
|
||||
Modify characteristics of port \fBport\fR in \fIswitch\fR. \fIport\fR
|
||||
|
@@ -305,7 +305,7 @@ usage(void)
|
||||
" get-frags SWITCH print fragment handling behavior\n"
|
||||
" set-frags SWITCH FRAG_MODE set fragment handling behavior\n"
|
||||
" dump-ports SWITCH [PORT] print port statistics\n"
|
||||
" dump-ports-desc SWITCH print port descriptions\n"
|
||||
" dump-ports-desc SWITCH [PORT] print port descriptions\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"
|
||||
@@ -648,7 +648,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
|
||||
ofpbuf_delete(reply);
|
||||
|
||||
if (!has_ports) {
|
||||
request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, version, 0);
|
||||
request = ofputil_encode_port_desc_stats_request(version, OFPP_ANY);
|
||||
dump_stats_transaction(vconn, request);
|
||||
}
|
||||
dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
|
||||
@@ -761,8 +761,8 @@ fetch_port_by_stats(struct vconn *vconn,
|
||||
bool done = false;
|
||||
bool found = false;
|
||||
|
||||
request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST,
|
||||
vconn_get_version(vconn), 0);
|
||||
request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn),
|
||||
port_no);
|
||||
send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
|
||||
|
||||
send_openflow_buffer(vconn, request);
|
||||
@@ -1620,7 +1620,16 @@ ofctl_dump_ports(int argc, char *argv[])
|
||||
static void
|
||||
ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[])
|
||||
{
|
||||
dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_PORT_DESC_REQUEST);
|
||||
struct ofpbuf *request;
|
||||
struct vconn *vconn;
|
||||
ofp_port_t port;
|
||||
|
||||
open_vconn(argv[1], &vconn);
|
||||
port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_ANY;
|
||||
request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn),
|
||||
port);
|
||||
dump_stats_transaction(vconn, request);
|
||||
vconn_close(vconn);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3504,7 +3513,7 @@ static const struct command all_commands[] = {
|
||||
{ "meter-features", 1, 1, ofctl_meter_features },
|
||||
{ "packet-out", 4, INT_MAX, ofctl_packet_out },
|
||||
{ "dump-ports", 1, 2, ofctl_dump_ports },
|
||||
{ "dump-ports-desc", 1, 1, ofctl_dump_ports_desc },
|
||||
{ "dump-ports-desc", 1, 2, ofctl_dump_ports_desc },
|
||||
{ "mod-port", 3, 3, ofctl_mod_port },
|
||||
{ "mod-table", 3, 3, ofctl_mod_table },
|
||||
{ "get-frags", 1, 1, ofctl_get_frags },
|
||||
|
Reference in New Issue
Block a user