mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51: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:
parent
4ce9c31573
commit
bdcc592595
1
NEWS
1
NEWS
@ -8,6 +8,7 @@ post-v1.7.0
|
||||
- A new test utility that can create L3 tunnel between two Open
|
||||
vSwitches and detect connectivity issues.
|
||||
- ovs-ofctl:
|
||||
- New --sort and --rsort options for "dump-flows" command.
|
||||
- "mod-port" command can now control all OpenFlow config flags.
|
||||
- OpenFlow:
|
||||
- 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);
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
ds_put_char(string, '\n');
|
||||
|
||||
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);
|
||||
ofp_print_flow_stats(string, &fs);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void
|
||||
ofp_to_string__(const struct ofp_header *oh,
|
||||
const struct ofputil_msg_type *type, struct ds *string,
|
||||
int verbosity)
|
||||
void
|
||||
ofp_print_version(const struct ofp_header *oh,
|
||||
struct ds *string)
|
||||
{
|
||||
enum ofputil_msg_code code;
|
||||
const void *msg = oh;
|
||||
|
||||
ds_put_cstr(string, ofputil_msg_type_name(type));
|
||||
switch (oh->version) {
|
||||
case OFP10_VERSION:
|
||||
break;
|
||||
@ -1377,7 +1377,18 @@ ofp_to_string__(const struct ofp_header *oh,
|
||||
break;
|
||||
}
|
||||
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);
|
||||
switch (code) {
|
||||
case OFPUTIL_MSG_INVALID:
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct ofp_flow_mod;
|
||||
struct ofp10_match;
|
||||
struct ds;
|
||||
struct ofp10_match;
|
||||
struct ofp_flow_mod;
|
||||
struct ofp_header;
|
||||
struct ofputil_flow_stats;
|
||||
|
||||
#ifdef __cplusplus
|
||||
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 *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
|
||||
}
|
||||
#endif
|
||||
|
@ -1357,3 +1357,92 @@ ofp_util|INFO|post: @&t@
|
||||
OVS_VSWITCHD_STOP
|
||||
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
|
||||
|
@ -161,12 +161,18 @@ whether a packet is a fragment and on its fragment offset.
|
||||
Prints to the console all flow entries in \fIswitch\fR's
|
||||
tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows
|
||||
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.
|
||||
.
|
||||
.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
|
||||
\fBdump\-aggregate \fIswitch \fR[\fIflows\fR]
|
||||
Prints to the console aggregate statistics for flows in
|
||||
Prints to the console aggregate statistics for flows in
|
||||
\fIswitch\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted,
|
||||
the statistics are aggregated across all flows in the switch's flow
|
||||
tables. See \fBFlow Syntax\fR, below, for the syntax of \fIflows\fR.
|
||||
@ -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
|
||||
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 \
|
||||
\fBovs\-ofctl\fR detaches only when executing the \fBmonitor\fR or \
|
||||
\fBsnoop\fR commands.
|
||||
|
@ -55,6 +55,8 @@
|
||||
#include "util.h"
|
||||
#include "vconn.h"
|
||||
#include "vlog.h"
|
||||
#include "meta-flow.h"
|
||||
#include "sort.h"
|
||||
|
||||
VLOG_DEFINE_THIS_MODULE(ofctl);
|
||||
|
||||
@ -83,11 +85,24 @@ static int verbosity;
|
||||
* "snoop" command? */
|
||||
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 void usage(void) NO_RETURN;
|
||||
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
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@ -98,6 +113,27 @@ main(int argc, char *argv[])
|
||||
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
|
||||
parse_options(int argc, char *argv[])
|
||||
{
|
||||
@ -105,6 +141,8 @@ parse_options(int argc, char *argv[])
|
||||
OPT_STRICT = UCHAR_MAX + 1,
|
||||
OPT_READD,
|
||||
OPT_TIMESTAMP,
|
||||
OPT_SORT,
|
||||
OPT_RSORT,
|
||||
DAEMON_OPTION_ENUMS,
|
||||
VLOG_OPTION_ENUMS
|
||||
};
|
||||
@ -116,6 +154,8 @@ parse_options(int argc, char *argv[])
|
||||
{"packet-in-format", required_argument, NULL, 'P'},
|
||||
{"more", no_argument, NULL, 'm'},
|
||||
{"timestamp", no_argument, NULL, OPT_TIMESTAMP},
|
||||
{"sort", optional_argument, NULL, OPT_SORT},
|
||||
{"rsort", optional_argument, NULL, OPT_RSORT},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
DAEMON_LONG_OPTIONS,
|
||||
@ -183,6 +223,14 @@ parse_options(int argc, char *argv[])
|
||||
timestamp = true;
|
||||
break;
|
||||
|
||||
case OPT_SORT:
|
||||
add_sort_criterion(SORT_ASC, optarg);
|
||||
break;
|
||||
|
||||
case OPT_RSORT:
|
||||
add_sort_criterion(SORT_DESC, optarg);
|
||||
break;
|
||||
|
||||
DAEMON_OPTION_HANDLERS
|
||||
VLOG_OPTION_HANDLERS
|
||||
STREAM_SSL_OPTION_HANDLERS
|
||||
@ -194,6 +242,12 @@ parse_options(int argc, char *argv[])
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (n_criteria) {
|
||||
/* Always do a final sort pass based on priority. */
|
||||
add_sort_criterion(SORT_DESC, "priority");
|
||||
}
|
||||
|
||||
free(short_options);
|
||||
}
|
||||
|
||||
@ -244,6 +298,8 @@ usage(void)
|
||||
" -m, --more be more verbose printing OpenFlow\n"
|
||||
" --timestamp (monitor, snoop) print timestamps\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"
|
||||
" -V, --version display version information\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -770,12 +826,12 @@ set_protocol_for_flow_dump(struct vconn *vconn,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
|
||||
static struct vconn *
|
||||
prepare_dump_flows(int argc, char *argv[], bool aggregate,
|
||||
struct ofpbuf **requestp)
|
||||
{
|
||||
enum ofputil_protocol usable_protocols, protocol;
|
||||
struct ofputil_flow_stats_request fsr;
|
||||
struct ofpbuf *request;
|
||||
struct vconn *vconn;
|
||||
|
||||
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 = 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);
|
||||
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
|
||||
ofctl_dump_flows(int argc, char *argv[])
|
||||
{
|
||||
return ofctl_dump_flows__(argc, argv, false);
|
||||
if (!n_criteria) {
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user