mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 14:25:26 +00:00
ovs-ofctl: Add --sort and --rsort options for "dump-flows" command.
Feature #8754. Signed-off-by: Arun Sharma <arun.sharma@calsoftinc.com> [blp@nicira.com rewrote most of the code] Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
1
NEWS
1
NEWS
@@ -8,6 +8,7 @@ post-v1.7.0
|
|||||||
- A new test utility that can create L3 tunnel between two Open
|
- A new test utility that can create L3 tunnel between two Open
|
||||||
vSwitches and detect connectivity issues.
|
vSwitches and detect connectivity issues.
|
||||||
- ovs-ofctl:
|
- ovs-ofctl:
|
||||||
|
- New --sort and --rsort options for "dump-flows" command.
|
||||||
- "mod-port" command can now control all OpenFlow config flags.
|
- "mod-port" command can now control all OpenFlow config flags.
|
||||||
- OpenFlow:
|
- OpenFlow:
|
||||||
- Allow general bitwise masking for IPv4 and IPv6 addresses in
|
- Allow general bitwise masking for IPv4 and IPv6 addresses in
|
||||||
|
@@ -972,6 +972,37 @@ ofp_print_flow_stats_request(struct ds *string,
|
|||||||
cls_rule_format(&fsr.match, string);
|
cls_rule_format(&fsr.match, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs)
|
||||||
|
{
|
||||||
|
ds_put_format(string, " cookie=0x%"PRIx64", duration=",
|
||||||
|
ntohll(fs->cookie));
|
||||||
|
|
||||||
|
ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
|
||||||
|
ds_put_format(string, ", table=%"PRIu8", ", fs->table_id);
|
||||||
|
ds_put_format(string, "n_packets=%"PRIu64", ", fs->packet_count);
|
||||||
|
ds_put_format(string, "n_bytes=%"PRIu64", ", fs->byte_count);
|
||||||
|
if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
|
||||||
|
ds_put_format(string, "idle_timeout=%"PRIu16", ", fs->idle_timeout);
|
||||||
|
}
|
||||||
|
if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
|
||||||
|
ds_put_format(string, "hard_timeout=%"PRIu16", ", fs->hard_timeout);
|
||||||
|
}
|
||||||
|
if (fs->idle_age >= 0) {
|
||||||
|
ds_put_format(string, "idle_age=%d, ", fs->idle_age);
|
||||||
|
}
|
||||||
|
if (fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
|
||||||
|
ds_put_format(string, "hard_age=%d, ", fs->hard_age);
|
||||||
|
}
|
||||||
|
|
||||||
|
cls_rule_format(&fs->rule, string);
|
||||||
|
if (string->string[string->length - 1] != ' ') {
|
||||||
|
ds_put_char(string, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
|
ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
|
||||||
{
|
{
|
||||||
@@ -991,35 +1022,9 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ds_put_char(string, '\n');
|
ds_put_char(string, '\n');
|
||||||
|
ofp_print_flow_stats(string, &fs);
|
||||||
ds_put_format(string, " cookie=0x%"PRIx64", duration=",
|
|
||||||
ntohll(fs.cookie));
|
|
||||||
ofp_print_duration(string, fs.duration_sec, fs.duration_nsec);
|
|
||||||
ds_put_format(string, ", table=%"PRIu8", ", fs.table_id);
|
|
||||||
ds_put_format(string, "n_packets=%"PRIu64", ", fs.packet_count);
|
|
||||||
ds_put_format(string, "n_bytes=%"PRIu64", ", fs.byte_count);
|
|
||||||
if (fs.idle_timeout != OFP_FLOW_PERMANENT) {
|
|
||||||
ds_put_format(string, "idle_timeout=%"PRIu16", ", fs.idle_timeout);
|
|
||||||
}
|
}
|
||||||
if (fs.hard_timeout != OFP_FLOW_PERMANENT) {
|
|
||||||
ds_put_format(string, "hard_timeout=%"PRIu16", ", fs.hard_timeout);
|
|
||||||
}
|
|
||||||
if (fs.idle_age >= 0) {
|
|
||||||
ds_put_format(string, "idle_age=%d, ", fs.idle_age);
|
|
||||||
}
|
|
||||||
if (fs.hard_age >= 0 && fs.hard_age != fs.duration_sec) {
|
|
||||||
ds_put_format(string, "hard_age=%d, ", fs.hard_age);
|
|
||||||
}
|
|
||||||
|
|
||||||
cls_rule_format(&fs.rule, string);
|
|
||||||
if (string->string[string->length - 1] != ' ') {
|
|
||||||
ds_put_char(string, ' ');
|
|
||||||
}
|
|
||||||
ofpacts_format(fs.ofpacts, fs.ofpacts_len, string);
|
|
||||||
}
|
|
||||||
ofpbuf_uninit(&ofpacts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1354,15 +1359,10 @@ ofp_print_nxt_set_controller_id(struct ds *string,
|
|||||||
ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
|
ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
ofp_to_string__(const struct ofp_header *oh,
|
ofp_print_version(const struct ofp_header *oh,
|
||||||
const struct ofputil_msg_type *type, struct ds *string,
|
struct ds *string)
|
||||||
int verbosity)
|
|
||||||
{
|
{
|
||||||
enum ofputil_msg_code code;
|
|
||||||
const void *msg = oh;
|
|
||||||
|
|
||||||
ds_put_cstr(string, ofputil_msg_type_name(type));
|
|
||||||
switch (oh->version) {
|
switch (oh->version) {
|
||||||
case OFP10_VERSION:
|
case OFP10_VERSION:
|
||||||
break;
|
break;
|
||||||
@@ -1377,7 +1377,18 @@ ofp_to_string__(const struct ofp_header *oh,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid));
|
ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ofp_to_string__(const struct ofp_header *oh,
|
||||||
|
const struct ofputil_msg_type *type, struct ds *string,
|
||||||
|
int verbosity)
|
||||||
|
{
|
||||||
|
enum ofputil_msg_code code;
|
||||||
|
const void *msg = oh;
|
||||||
|
|
||||||
|
ds_put_cstr(string, ofputil_msg_type_name(type));
|
||||||
|
ofp_print_version(oh, string);
|
||||||
code = ofputil_msg_type_code(type);
|
code = ofputil_msg_type_code(type);
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case OFPUTIL_MSG_INVALID:
|
case OFPUTIL_MSG_INVALID:
|
||||||
|
@@ -22,9 +22,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
struct ofp_flow_mod;
|
|
||||||
struct ofp10_match;
|
|
||||||
struct ds;
|
struct ds;
|
||||||
|
struct ofp10_match;
|
||||||
|
struct ofp_flow_mod;
|
||||||
|
struct ofp_header;
|
||||||
|
struct ofputil_flow_stats;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -39,6 +41,9 @@ char *ofp_to_string(const void *, size_t, int verbosity);
|
|||||||
char *ofp10_match_to_string(const struct ofp10_match *, int verbosity);
|
char *ofp10_match_to_string(const struct ofp10_match *, int verbosity);
|
||||||
char *ofp_packet_to_string(const void *data, size_t len);
|
char *ofp_packet_to_string(const void *data, size_t len);
|
||||||
|
|
||||||
|
void ofp_print_flow_stats(struct ds *, struct ofputil_flow_stats *);
|
||||||
|
void ofp_print_version(const struct ofp_header *, struct ds *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1357,3 +1357,92 @@ ofp_util|INFO|post: @&t@
|
|||||||
OVS_VSWITCHD_STOP
|
OVS_VSWITCHD_STOP
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
|
dnl Check that --sort and --rsort works with dump-flows
|
||||||
|
dnl Default field is 'priority'. Flow entries are displayed based
|
||||||
|
dnl on field to sort.
|
||||||
|
AT_SETUP([ovs-ofctl dump-flows with sorting])
|
||||||
|
OVS_VSWITCHD_START
|
||||||
|
AT_KEYWORDS([sort])
|
||||||
|
AT_DATA([allflows.txt], [[
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
]])
|
||||||
|
|
||||||
|
AT_CHECK([ovs-ofctl add-flows br0 allflows.txt
|
||||||
|
], [0], [ignore])
|
||||||
|
AT_CHECK([ovs-ofctl --sort dump-flows br0 | ofctl_strip], [0], [dnl
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
])
|
||||||
|
AT_CHECK([ovs-ofctl --rsort dump-flows br0 | ofctl_strip], [0], [dnl
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
])
|
||||||
|
AT_CHECK([ovs-ofctl --sort=in_port dump-flows br0 | ofctl_strip], [0], [dnl
|
||||||
|
priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
])
|
||||||
|
AT_CHECK([ovs-ofctl --rsort=in_port dump-flows br0 | ofctl_strip], [0], [dnl
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
])
|
||||||
|
AT_CHECK([ovs-ofctl --sort=tcp_src dump-flows br0 | ofctl_strip], [0], [dnl
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
])
|
||||||
|
AT_CHECK(
|
||||||
|
[ovs-ofctl --sort=in_port --sort=tcp_src dump-flows br0 | ofctl_strip], [0],
|
||||||
|
[ priority=2,in_port=1025 actions=output:47
|
||||||
|
priority=1,in_port=1026 actions=output:45
|
||||||
|
priority=6,in_port=1027 actions=output:64
|
||||||
|
priority=3,in_port=1028 actions=output:44
|
||||||
|
priority=7,in_port=1029 actions=output:43
|
||||||
|
priority=5,in_port=1029 actions=output:43
|
||||||
|
priority=4,in_port=23213 actions=output:42
|
||||||
|
priority=8,tcp,tp_src=5 actions=drop
|
||||||
|
priority=9,tcp,tp_src=6 actions=drop
|
||||||
|
])
|
||||||
|
OVS_VSWITCHD_STOP
|
||||||
|
AT_CLEANUP
|
||||||
|
@@ -164,6 +164,12 @@ in the switch are retrieved. See \fBFlow Syntax\fR, below, for the
|
|||||||
syntax of \fIflows\fR. The output format is described in
|
syntax of \fIflows\fR. The output format is described in
|
||||||
\fBTable Entry Output\fR.
|
\fBTable Entry Output\fR.
|
||||||
.
|
.
|
||||||
|
.IP
|
||||||
|
By default, \fBovs\-ofctl\fR prints flow entries in the same order
|
||||||
|
that the switch sends them, which is unlikely to be intuitive or
|
||||||
|
consistent. See the description of \fB\-\-sort\fR and \fB\-\-rsort\fR,
|
||||||
|
under \fBOPTIONS\fR below, to influence the display order.
|
||||||
|
.
|
||||||
.TP
|
.TP
|
||||||
\fBdump\-aggregate \fIswitch \fR[\fIflows\fR]
|
\fBdump\-aggregate \fIswitch \fR[\fIflows\fR]
|
||||||
Prints to the console aggregate statistics for flows in
|
Prints to the console aggregate statistics for flows in
|
||||||
@@ -1317,6 +1323,33 @@ Increases the verbosity of OpenFlow messages printed and logged by
|
|||||||
\fBovs\-ofctl\fR commands. Specify this option more than once to
|
\fBovs\-ofctl\fR commands. Specify this option more than once to
|
||||||
increase verbosity further.
|
increase verbosity further.
|
||||||
.
|
.
|
||||||
|
.IP \fB\-\-sort\fR[\fB=\fIfield\fR]
|
||||||
|
.IQ \fB\-\-rsort\fR[\fB=\fIfield\fR]
|
||||||
|
Display output sorted by flow \fIfield\fR in ascending
|
||||||
|
(\fB\-\-sort\fR) or descending (\fB\-\-rsort\fR) order, where
|
||||||
|
\fIfield\fR is any of the fields that are allowed for matching or
|
||||||
|
\fBpriority\fR to sort by priority. When \fIfield\fR is omitted, the
|
||||||
|
output is sorted by priority. Specify these options multiple times to
|
||||||
|
sort by multiple fields.
|
||||||
|
.IP
|
||||||
|
Any given flow will not necessarily specify a value for a given
|
||||||
|
field. This requires special treatement:
|
||||||
|
.RS
|
||||||
|
.IP \(bu
|
||||||
|
A flow that does not specify any part of a field that is used for sorting is
|
||||||
|
sorted after all the flows that do specify the field. For example,
|
||||||
|
\fB\-\-sort=tcp_src\fR will sort all the flows that specify a TCP
|
||||||
|
source port in ascending order, followed by the flows that do not
|
||||||
|
specify a TCP source port at all.
|
||||||
|
.IP \(bu
|
||||||
|
A flow that only specifies some bits in a field is sorted as if the
|
||||||
|
wildcarded bits were zero. For example, \fB\-\-sort=nw_src\fR would
|
||||||
|
sort a flow that specifies \fBnw_src=192.168.0.0/24\fR the same as
|
||||||
|
\fBnw_src=192.168.0.0\fR.
|
||||||
|
.RE
|
||||||
|
.IP
|
||||||
|
These options currently affect only \fBdump\-flows\fR output.
|
||||||
|
.
|
||||||
.ds DD \
|
.ds DD \
|
||||||
\fBovs\-ofctl\fR detaches only when executing the \fBmonitor\fR or \
|
\fBovs\-ofctl\fR detaches only when executing the \fBmonitor\fR or \
|
||||||
\fBsnoop\fR commands.
|
\fBsnoop\fR commands.
|
||||||
|
@@ -55,6 +55,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "vconn.h"
|
#include "vconn.h"
|
||||||
#include "vlog.h"
|
#include "vlog.h"
|
||||||
|
#include "meta-flow.h"
|
||||||
|
#include "sort.h"
|
||||||
|
|
||||||
VLOG_DEFINE_THIS_MODULE(ofctl);
|
VLOG_DEFINE_THIS_MODULE(ofctl);
|
||||||
|
|
||||||
@@ -83,11 +85,24 @@ static int verbosity;
|
|||||||
* "snoop" command? */
|
* "snoop" command? */
|
||||||
static bool timestamp;
|
static bool timestamp;
|
||||||
|
|
||||||
|
/* --sort, --rsort: Sort order. */
|
||||||
|
enum sort_order { SORT_ASC, SORT_DESC };
|
||||||
|
struct sort_criterion {
|
||||||
|
const struct mf_field *field; /* NULL means to sort by priority. */
|
||||||
|
enum sort_order order;
|
||||||
|
};
|
||||||
|
static struct sort_criterion *criteria;
|
||||||
|
static size_t n_criteria, allocated_criteria;
|
||||||
|
|
||||||
static const struct command all_commands[];
|
static const struct command all_commands[];
|
||||||
|
|
||||||
static void usage(void) NO_RETURN;
|
static void usage(void) NO_RETURN;
|
||||||
static void parse_options(int argc, char *argv[]);
|
static void parse_options(int argc, char *argv[]);
|
||||||
|
|
||||||
|
static bool recv_flow_stats_reply(struct vconn *, ovs_be32 send_xid,
|
||||||
|
struct ofpbuf **replyp,
|
||||||
|
struct ofputil_flow_stats *,
|
||||||
|
struct ofpbuf *ofpacts);
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -98,6 +113,27 @@ main(int argc, char *argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_sort_criterion(enum sort_order order, const char *field)
|
||||||
|
{
|
||||||
|
struct sort_criterion *sc;
|
||||||
|
|
||||||
|
if (n_criteria >= allocated_criteria) {
|
||||||
|
criteria = x2nrealloc(criteria, &allocated_criteria, sizeof *criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc = &criteria[n_criteria++];
|
||||||
|
if (!field || !strcasecmp(field, "priority")) {
|
||||||
|
sc->field = NULL;
|
||||||
|
} else {
|
||||||
|
sc->field = mf_from_name(field);
|
||||||
|
if (!sc->field) {
|
||||||
|
ovs_fatal(0, "%s: unknown field name", field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sc->order = order;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
parse_options(int argc, char *argv[])
|
parse_options(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -105,6 +141,8 @@ parse_options(int argc, char *argv[])
|
|||||||
OPT_STRICT = UCHAR_MAX + 1,
|
OPT_STRICT = UCHAR_MAX + 1,
|
||||||
OPT_READD,
|
OPT_READD,
|
||||||
OPT_TIMESTAMP,
|
OPT_TIMESTAMP,
|
||||||
|
OPT_SORT,
|
||||||
|
OPT_RSORT,
|
||||||
DAEMON_OPTION_ENUMS,
|
DAEMON_OPTION_ENUMS,
|
||||||
VLOG_OPTION_ENUMS
|
VLOG_OPTION_ENUMS
|
||||||
};
|
};
|
||||||
@@ -116,6 +154,8 @@ parse_options(int argc, char *argv[])
|
|||||||
{"packet-in-format", required_argument, NULL, 'P'},
|
{"packet-in-format", required_argument, NULL, 'P'},
|
||||||
{"more", no_argument, NULL, 'm'},
|
{"more", no_argument, NULL, 'm'},
|
||||||
{"timestamp", no_argument, NULL, OPT_TIMESTAMP},
|
{"timestamp", no_argument, NULL, OPT_TIMESTAMP},
|
||||||
|
{"sort", optional_argument, NULL, OPT_SORT},
|
||||||
|
{"rsort", optional_argument, NULL, OPT_RSORT},
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{"version", no_argument, NULL, 'V'},
|
{"version", no_argument, NULL, 'V'},
|
||||||
DAEMON_LONG_OPTIONS,
|
DAEMON_LONG_OPTIONS,
|
||||||
@@ -183,6 +223,14 @@ parse_options(int argc, char *argv[])
|
|||||||
timestamp = true;
|
timestamp = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_SORT:
|
||||||
|
add_sort_criterion(SORT_ASC, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_RSORT:
|
||||||
|
add_sort_criterion(SORT_DESC, optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
DAEMON_OPTION_HANDLERS
|
DAEMON_OPTION_HANDLERS
|
||||||
VLOG_OPTION_HANDLERS
|
VLOG_OPTION_HANDLERS
|
||||||
STREAM_SSL_OPTION_HANDLERS
|
STREAM_SSL_OPTION_HANDLERS
|
||||||
@@ -194,6 +242,12 @@ parse_options(int argc, char *argv[])
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n_criteria) {
|
||||||
|
/* Always do a final sort pass based on priority. */
|
||||||
|
add_sort_criterion(SORT_DESC, "priority");
|
||||||
|
}
|
||||||
|
|
||||||
free(short_options);
|
free(short_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +298,8 @@ usage(void)
|
|||||||
" -m, --more be more verbose printing OpenFlow\n"
|
" -m, --more be more verbose printing OpenFlow\n"
|
||||||
" --timestamp (monitor, snoop) print timestamps\n"
|
" --timestamp (monitor, snoop) print timestamps\n"
|
||||||
" -t, --timeout=SECS give up after SECS seconds\n"
|
" -t, --timeout=SECS give up after SECS seconds\n"
|
||||||
|
" --sort[=field] sort in ascending order\n"
|
||||||
|
" --rsort[=field] sort in descending order\n"
|
||||||
" -h, --help display this help message\n"
|
" -h, --help display this help message\n"
|
||||||
" -V, --version display version information\n");
|
" -V, --version display version information\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
@@ -770,12 +826,12 @@ set_protocol_for_flow_dump(struct vconn *vconn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static struct vconn *
|
||||||
ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
|
prepare_dump_flows(int argc, char *argv[], bool aggregate,
|
||||||
|
struct ofpbuf **requestp)
|
||||||
{
|
{
|
||||||
enum ofputil_protocol usable_protocols, protocol;
|
enum ofputil_protocol usable_protocols, protocol;
|
||||||
struct ofputil_flow_stats_request fsr;
|
struct ofputil_flow_stats_request fsr;
|
||||||
struct ofpbuf *request;
|
|
||||||
struct vconn *vconn;
|
struct vconn *vconn;
|
||||||
|
|
||||||
parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
|
parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
|
||||||
@@ -783,15 +839,121 @@ ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
|
|||||||
|
|
||||||
protocol = open_vconn(argv[1], &vconn);
|
protocol = open_vconn(argv[1], &vconn);
|
||||||
protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
|
protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
|
||||||
request = ofputil_encode_flow_stats_request(&fsr, protocol);
|
*requestp = ofputil_encode_flow_stats_request(&fsr, protocol);
|
||||||
|
return vconn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
|
||||||
|
{
|
||||||
|
struct ofpbuf *request;
|
||||||
|
struct vconn *vconn;
|
||||||
|
|
||||||
|
vconn = prepare_dump_flows(argc, argv, aggregate, &request);
|
||||||
dump_stats_transaction__(vconn, request);
|
dump_stats_transaction__(vconn, request);
|
||||||
vconn_close(vconn);
|
vconn_close(vconn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_flows(const void *afs_, const void *bfs_)
|
||||||
|
{
|
||||||
|
const struct ofputil_flow_stats *afs = afs_;
|
||||||
|
const struct ofputil_flow_stats *bfs = bfs_;
|
||||||
|
const struct cls_rule *a = &afs->rule;
|
||||||
|
const struct cls_rule *b = &bfs->rule;
|
||||||
|
const struct sort_criterion *sc;
|
||||||
|
|
||||||
|
for (sc = criteria; sc < &criteria[n_criteria]; sc++) {
|
||||||
|
const struct mf_field *f = sc->field;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
ret = a->priority < b->priority ? -1 : a->priority > b->priority;
|
||||||
|
} else {
|
||||||
|
bool ina, inb;
|
||||||
|
|
||||||
|
ina = mf_are_prereqs_ok(f, &a->flow) && !mf_is_all_wild(f, &a->wc);
|
||||||
|
inb = mf_are_prereqs_ok(f, &b->flow) && !mf_is_all_wild(f, &b->wc);
|
||||||
|
if (ina != inb) {
|
||||||
|
/* Skip the test for sc->order, so that missing fields always
|
||||||
|
* sort to the end whether we're sorting in ascending or
|
||||||
|
* descending order. */
|
||||||
|
return ina ? -1 : 1;
|
||||||
|
} else {
|
||||||
|
union mf_value aval, bval;
|
||||||
|
|
||||||
|
mf_get_value(f, &a->flow, &aval);
|
||||||
|
mf_get_value(f, &b->flow, &bval);
|
||||||
|
ret = memcmp(&aval, &bval, f->n_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
return sc->order == SORT_ASC ? ret : -ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ofctl_dump_flows(int argc, char *argv[])
|
ofctl_dump_flows(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
if (!n_criteria) {
|
||||||
return ofctl_dump_flows__(argc, argv, false);
|
return ofctl_dump_flows__(argc, argv, false);
|
||||||
|
} else {
|
||||||
|
struct ofputil_flow_stats *fses;
|
||||||
|
size_t n_fses, allocated_fses;
|
||||||
|
struct ofpbuf *request;
|
||||||
|
struct ofpbuf ofpacts;
|
||||||
|
struct ofpbuf *reply;
|
||||||
|
struct vconn *vconn;
|
||||||
|
ovs_be32 send_xid;
|
||||||
|
struct ds s;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
vconn = prepare_dump_flows(argc, argv, false, &request);
|
||||||
|
send_xid = ((struct ofp_header *) request->data)->xid;
|
||||||
|
send_openflow_buffer(vconn, request);
|
||||||
|
|
||||||
|
fses = NULL;
|
||||||
|
n_fses = allocated_fses = 0;
|
||||||
|
reply = NULL;
|
||||||
|
ofpbuf_init(&ofpacts, 0);
|
||||||
|
for (;;) {
|
||||||
|
struct ofputil_flow_stats *fs;
|
||||||
|
|
||||||
|
if (n_fses >= allocated_fses) {
|
||||||
|
fses = x2nrealloc(fses, &allocated_fses, sizeof *fses);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = &fses[n_fses];
|
||||||
|
if (!recv_flow_stats_reply(vconn, send_xid, &reply, fs,
|
||||||
|
&ofpacts)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fs->ofpacts = xmemdup(fs->ofpacts, fs->ofpacts_len);
|
||||||
|
n_fses++;
|
||||||
|
}
|
||||||
|
ofpbuf_uninit(&ofpacts);
|
||||||
|
|
||||||
|
qsort(fses, n_fses, sizeof *fses, compare_flows);
|
||||||
|
|
||||||
|
ds_init(&s);
|
||||||
|
for (i = 0; i < n_fses; i++) {
|
||||||
|
ds_clear(&s);
|
||||||
|
ofp_print_flow_stats(&s, &fses[i]);
|
||||||
|
puts(ds_cstr(&s));
|
||||||
|
}
|
||||||
|
ds_destroy(&s);
|
||||||
|
|
||||||
|
for (i = 0; i < n_fses; i++) {
|
||||||
|
free(fses[i].ofpacts);
|
||||||
|
}
|
||||||
|
free(fses);
|
||||||
|
|
||||||
|
vconn_close(vconn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Reference in New Issue
Block a user