summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/meta-flow.c18
-rw-r--r--lib/meta-flow.h1
-rw-r--r--lib/ofp-parse.c49
-rw-r--r--lib/ofp-parse.h4
-rw-r--r--ofproto/ofproto-dpif.c2
-rw-r--r--tests/odp.at65
-rw-r--r--tests/test-odp.c83
-rw-r--r--utilities/ovs-dpctl.8.in10
-rw-r--r--utilities/ovs-dpctl.c47
9 files changed, 264 insertions, 15 deletions
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 3ac396f37..12811ef07 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -1538,6 +1538,24 @@ mf_set_value(const struct mf_field *mf,
}
}
+/* Unwildcard 'mask' member field described by 'mf'. The caller is
+ * responsible for ensuring that 'mask' meets 'mf''s prerequisites. */
+void
+mf_mask_field(const struct mf_field *mf, struct flow *mask)
+{
+ static const union mf_value exact_match_mask = MF_EXACT_MASK_INITIALIZER;
+
+ /* For MFF_DL_VLAN, we cannot send a all 1's to flow_set_dl_vlan()
+ * as that will be considered as OFP10_VLAN_NONE. So consider it as a
+ * special case. For the rest, calling mf_set_flow_value() is good
+ * enough. */
+ if (mf->id == MFF_DL_VLAN) {
+ flow_set_dl_vlan(mask, htons(VLAN_VID_MASK));
+ } else {
+ mf_set_flow_value(mf, &exact_match_mask, mask);
+ }
+}
+
/* Sets 'flow' member field described by 'mf' to 'value'. The caller is
* responsible for ensuring that 'flow' meets 'mf''s prerequisites.*/
void
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index a3f6701fe..d3185e4e6 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -355,6 +355,7 @@ void mf_set_value(const struct mf_field *, const union mf_value *value,
void mf_set_flow_value(const struct mf_field *, const union mf_value *value,
struct flow *);
bool mf_is_zero(const struct mf_field *, const struct flow *);
+void mf_mask_field(const struct mf_field *, struct flow *);
void mf_get(const struct mf_field *, const struct match *,
union mf_value *value, union mf_value *mask);
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 2350de303..17bd7e2cc 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -36,6 +36,7 @@
#include "openflow/openflow.h"
#include "ovs-thread.h"
#include "packets.h"
+#include "simap.h"
#include "socket-util.h"
#include "vconn.h"
@@ -1879,18 +1880,24 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
/* Parses a specification of a flow from 's' into 'flow'. 's' must take the
* form FIELD=VALUE[,FIELD=VALUE]... where each FIELD is the name of a
* mf_field. Fields must be specified in a natural order for satisfying
- * prerequisites.
+ * prerequisites. If 'mask' is specified, fills the mask field for each of the
+ * field specified in flow. If the map, 'names_portno' is specfied, converts
+ * the in_port name into port no while setting the 'flow'.
*
* Returns NULL on success, otherwise a malloc()'d string that explains the
* problem. */
char *
-parse_ofp_exact_flow(struct flow *flow, const char *s)
+parse_ofp_exact_flow(struct flow *flow, struct flow *mask, const char *s,
+ const struct simap *portno_names)
{
char *pos, *key, *value_s;
char *error = NULL;
char *copy;
memset(flow, 0, sizeof *flow);
+ if (mask) {
+ memset(mask, 0, sizeof *mask);
+ }
pos = copy = xstrdup(s);
while (ofputil_parse_key_value(&pos, &key, &value_s)) {
@@ -1901,6 +1908,9 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
goto exit;
}
flow->dl_type = htons(p->dl_type);
+ if (mask) {
+ mask->dl_type = OVS_BE16_MAX;
+ }
if (p->nw_proto) {
if (flow->nw_proto) {
@@ -1909,6 +1919,9 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
goto exit;
}
flow->nw_proto = p->nw_proto;
+ if (mask) {
+ mask->nw_proto = UINT8_MAX;
+ }
}
} else {
const struct mf_field *mf;
@@ -1932,15 +1945,28 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
goto exit;
}
- field_error = mf_parse_value(mf, value_s, &value);
- if (field_error) {
- error = xasprintf("%s: bad value for %s (%s)",
- s, key, field_error);
- free(field_error);
- goto exit;
- }
+ if (!strcmp(key, "in_port")
+ && portno_names
+ && simap_contains(portno_names, value_s)) {
+ flow->in_port.ofp_port = u16_to_ofp(
+ simap_get(portno_names, value_s));
+ if (mask) {
+ mask->in_port.ofp_port = u16_to_ofp(ntohs(OVS_BE16_MAX));
+ }
+ } else {
+ field_error = mf_parse_value(mf, value_s, &value);
+ if (field_error) {
+ error = xasprintf("%s: bad value for %s (%s)",
+ s, key, field_error);
+ free(field_error);
+ goto exit;
+ }
- mf_set_flow_value(mf, &value, flow);
+ mf_set_flow_value(mf, &value, flow);
+ if (mask) {
+ mf_mask_field(mf, mask);
+ }
+ }
}
}
@@ -1953,6 +1979,9 @@ exit:
if (error) {
memset(flow, 0, sizeof *flow);
+ if (mask) {
+ memset(mask, 0, sizeof *mask);
+ }
}
return error;
}
diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
index 47ba036ec..515ccd702 100644
--- a/lib/ofp-parse.h
+++ b/lib/ofp-parse.h
@@ -32,6 +32,7 @@ struct ofputil_flow_stats_request;
struct ofputil_group_mod;
struct ofputil_meter_mod;
struct ofputil_table_mod;
+struct simap;
enum ofputil_protocol;
char *parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
@@ -62,7 +63,8 @@ char *parse_ofpacts(const char *, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
WARN_UNUSED_RESULT;
-char *parse_ofp_exact_flow(struct flow *, const char *);
+char *parse_ofp_exact_flow(struct flow *flow, struct flow *mask, const char *s,
+ const struct simap *portno_names);
char *parse_ofp_meter_mod_str(struct ofputil_meter_mod *, const char *string,
int command,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 8ef1c8cb0..030572c89 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5201,7 +5201,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
goto exit;
}
ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
- } else if (!parse_ofp_exact_flow(&flow, argv[argc - 1])) {
+ } else if (!parse_ofp_exact_flow(&flow, NULL, argv[argc - 1], NULL)) {
if (argc != 3) {
unixctl_command_reply_error(conn, "Must specify bridge name");
goto exit;
diff --git a/tests/odp.at b/tests/odp.at
index 469e120dd..b50534512 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -151,6 +151,71 @@ AT_CHECK_UNQUOTED([test-odp parse-wc-keys < odp.txt], [0], [`cat odp.txt`
])
AT_CLEANUP
+AT_SETUP([OVS datapath wildcarded key filtering.])
+dnl We could add a test for invalid forms, but that's less important.
+AT_DATA([odp-base.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234/0xfff0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41/255.255.255.0,dst=172.16.0.20/255.255.255.0,proto=5/0xf0,tos=0x80/0xf0,ttl=128/0xf0,frag=no/0xf0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,ttl=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,ttl=128,frag=no),udp(src=81/0xff00,dst=6632/0xff)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,ttl=128,frag=no),udp(src=81/0xff,dst=6632/0xff00)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0,ttl=128,frag=no),icmp(type=1/0xf0,code=2/0xff)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1/::255,dst=::2/::255,label=0/0xf0,proto=10/0xf0,tclass=0x70/0xf0,hlimit=128/0xf0,frag=no/0xf0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tclass=0,hlimit=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4/255.255.255.250,tip=5.6.7.8/255.255.255.250,op=1/0xf0,sha=00:0f:10:11:12:13/ff:ff:ff:ff:ff:00,tha=00:14:15:16:17:18/ff:ff:ff:ff:ff:00)
+])
+AT_DATA([odp-vlan-base.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,ttl=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff))
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8100),vlan(vid=100,pcp=7),encap(eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,ttl=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff))
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,ttl=128,frag=no),udp(src=81/0xff00,dst=6632/0xff))
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8100),vlan(vid=100,pcp=7),encap(eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,ttl=128,frag=no),udp(src=81/0xff00,dst=6632/0xff))
+])
+AT_DATA([odp-eth-type.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234/0xfff0)
+])
+AT_DATA([odp-vlan.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,ttl=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff))
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,ttl=128,frag=no),udp(src=81/0xff00,dst=6632/0xff))
+])
+AT_DATA([odp-ipv4.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41/255.255.255.0,dst=172.16.0.20/255.255.255.0,proto=5/0xf0,tos=0x80/0xf0,ttl=128/0xf0,frag=no/0xf0)
+])
+AT_DATA([odp-icmp.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41/255.255.255.0,dst=172.16.0.20/255.255.255.0,proto=5/0xf0,tos=0x80/0xf0,ttl=128/0xf0,frag=no/0xf0)
+])
+AT_DATA([odp-arp.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4/255.255.255.250,tip=5.6.7.8/255.255.255.250,op=1/0xf0,sha=00:0f:10:11:12:13/ff:ff:ff:ff:ff:00,tha=00:14:15:16:17:18/ff:ff:ff:ff:ff:00)
+])
+AT_DATA([odp-tcp.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41/255.255.255.0,dst=172.16.0.20/255.255.255.0,proto=5/0xf0,tos=0x80/0xf0,ttl=128/0xf0,frag=no/0xf0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,ttl=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff)
+])
+AT_DATA([odp-tcp6.txt], [dnl
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1/::255,dst=::2/::255,label=0/0xf0,proto=10/0xf0,tclass=0x70/0xf0,hlimit=128/0xf0,frag=no/0xf0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tclass=0,hlimit=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff)
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_type=0x1235' < odp-base.txt], [0], [`cat odp-eth-type.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_vlan=99' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_vlan=99,ip' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='ip,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='ip,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_type=0x0800,nw_src=35.8.2.199,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='icmp,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-icmp.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='arp,arp_spa=1.2.3.5' < odp-base.txt], [0], [`cat odp-arp.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='tcp,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp.txt`
+])
+AT_CHECK_UNQUOTED([test-odp parse-filter filter='tcp6,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp6.txt`
+])
+AT_CLEANUP
+
AT_SETUP([OVS datapath actions parsing and formatting - valid forms])
AT_DATA([actions.txt], [dnl
1,2,3
diff --git a/tests/test-odp.c b/tests/test-odp.c
index 183a3b3cd..471851b29 100644
--- a/tests/test-odp.c
+++ b/tests/test-odp.c
@@ -20,7 +20,9 @@
#include "dynamic-string.h"
#include "flow.h"
+#include "match.h"
#include "odp-util.h"
+#include "ofp-parse.h"
#include "ofpbuf.h"
#include "util.h"
#include "vlog.h"
@@ -135,15 +137,96 @@ parse_actions(void)
return 0;
}
+static int
+parse_filter(char *filter_parse)
+{
+ struct ds in;
+ struct flow flow_filter;
+ struct flow_wildcards wc_filter;
+ char *error, *filter = NULL;
+
+ vlog_set_levels_from_string_assert("odp_util:console:dbg");
+ if (filter_parse && !strncmp(filter_parse, "filter=", 7)) {
+ filter = strdup(filter_parse+7);
+ memset(&flow_filter, 0, sizeof(flow_filter));
+ memset(&wc_filter, 0, sizeof(wc_filter));
+
+ error = parse_ofp_exact_flow(&flow_filter, &wc_filter.masks, filter,
+ NULL);
+ if (error) {
+ ovs_fatal(0, "Failed to parse filter (%s)", error);
+ }
+ } else {
+ ovs_fatal(0, "No filter to parse.");
+ }
+
+ ds_init(&in);
+ while (!ds_get_test_line(&in, stdin)) {
+ struct ofpbuf odp_key;
+ struct ofpbuf odp_mask;
+ struct ds out;
+ int error;
+
+ /* Convert string to OVS DP key. */
+ ofpbuf_init(&odp_key, 0);
+ ofpbuf_init(&odp_mask, 0);
+ error = odp_flow_from_string(ds_cstr(&in), NULL,
+ &odp_key, &odp_mask);
+ if (error) {
+ printf("odp_flow_from_string: error\n");
+ goto next;
+ }
+
+ if (filter) {
+ struct flow flow;
+ struct flow_wildcards wc;
+ struct match match, match_filter;
+ struct minimatch minimatch;
+
+ odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
+ odp_flow_key_to_mask(odp_mask.data, odp_mask.size, &wc.masks,
+ &flow);
+ match_init(&match, &flow, &wc);
+
+ match_init(&match_filter, &flow_filter, &wc);
+ match_init(&match_filter, &match_filter.flow, &wc_filter);
+ minimatch_init(&minimatch, &match_filter);
+
+ if (!minimatch_matches_flow(&minimatch, &match.flow)) {
+ minimatch_destroy(&minimatch);
+ goto next;
+ }
+ minimatch_destroy(&minimatch);
+ }
+ /* Convert odp_key to string. */
+ ds_init(&out);
+ odp_flow_format(odp_key.data, odp_key.size,
+ odp_mask.data, odp_mask.size, NULL, &out, false);
+ puts(ds_cstr(&out));
+ ds_destroy(&out);
+
+ next:
+ ofpbuf_uninit(&odp_key);
+ ofpbuf_uninit(&odp_mask);
+ }
+ ds_destroy(&in);
+
+ free(filter);
+ return 0;
+}
+
int
main(int argc, char *argv[])
{
+ set_program_name(argv[0]);
if (argc == 2 &&!strcmp(argv[1], "parse-keys")) {
return parse_keys(false);
} else if (argc == 2 &&!strcmp(argv[1], "parse-wc-keys")) {
return parse_keys(true);
} else if (argc == 2 && !strcmp(argv[1], "parse-actions")) {
return parse_actions();
+ } else if (argc == 3 && !strcmp(argv[1], "parse-filter")) {
+ return parse_filter(argv[2]);
} else {
ovs_fatal(0, "usage: %s parse-keys | parse-wc-keys | parse-actions", argv[0]);
}
diff --git a/utilities/ovs-dpctl.8.in b/utilities/ovs-dpctl.8.in
index 5c0157028..35d1be590 100644
--- a/utilities/ovs-dpctl.8.in
+++ b/utilities/ovs-dpctl.8.in
@@ -118,11 +118,19 @@ exactly one datapath exists, in which case that datapath is the
default. When multiple datapaths exist, then a datapath name is
required.
.
-.IP "[\fB\-m \fR| \fB\-\-more\fR] \fBdump\-flows\fR [\fIdp\fR]"
+.IP "[\fB\-m \fR| \fB\-\-more\fR] \fBdump\-flows\fR [\fIdp\fR] [\fBfilter=\fIfilter\fR]"
Prints to the console all flow entries in datapath \fIdp\fR's flow
table. Without \fB\-m\fR or \fB\-\-more\fR, output omits match fields
that a flow wildcards entirely; with \fB\-m\fR or \fB\-\-more\fR,
output includes all wildcarded fields.
+.IP
+If \fBfilter=\fIfilter\fR is specified, only displays the flows
+that match the \fIfilter\fR. \fIfilter\fR is a flow in the form similiar
+to that accepted by \fBovs\-ofctl\fR(8)'s \fBadd\-flow\fR command. (This is
+not an OpenFlow flow: besides other differences, it never contains wildcards.)
+The \fIfilter\fR is also useful to match wildcarded fields in the datapath
+flow. As an example, \fBfilter='tcp,tp_src=100'\fR will match the
+datapath flow containing '\fBtcp(src=80/0xff00,dst=8080/0xff)\fR'.
.
.IP "\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
.IQ "[\fB\-\-clear\fR] [\fB\-\-may-create\fR] [\fB\-s\fR | \fB\-\-statistics\fR] \fBmod\-flow\fR [\fIdp\fR] \fIflow actions\fR"
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index 4fb02dda4..e11e102e3 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -36,9 +36,11 @@
#include "dpif.h"
#include "dynamic-string.h"
#include "flow.h"
+#include "match.h"
#include "netdev.h"
#include "netlink.h"
#include "odp-util.h"
+#include "ofp-parse.h"
#include "ofpbuf.h"
#include "packets.h"
#include "shash.h"
@@ -746,20 +748,38 @@ dpctl_dump_flows(int argc, char *argv[])
struct dpif_port dpif_port;
struct dpif_port_dump port_dump;
struct hmap portno_names;
+ struct simap names_portno;
size_t actions_len;
struct dpif *dpif;
size_t key_len;
size_t mask_len;
struct ds ds;
- char *name;
+ char *name, *error, *filter = NULL;
+ struct flow flow_filter;
+ struct flow_wildcards wc_filter;
+ if (argc > 1 && !strncmp(argv[argc - 1], "filter=", 7)) {
+ filter = xstrdup(argv[--argc] + 7);
+ }
name = (argc == 2) ? xstrdup(argv[1]) : get_one_dp();
+
run(parsed_dpif_open(name, false, &dpif), "opening datapath");
free(name);
hmap_init(&portno_names);
+ simap_init(&names_portno);
DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, dpif) {
odp_portno_names_set(&portno_names, dpif_port.port_no, dpif_port.name);
+ simap_put(&names_portno, dpif_port.name,
+ odp_to_u32(dpif_port.port_no));
+ }
+
+ if (filter) {
+ error = parse_ofp_exact_flow(&flow_filter, &wc_filter.masks, filter,
+ &names_portno);
+ if (error) {
+ ovs_fatal(0, "Failed to parse filter (%s)", error);
+ }
}
ds_init(&ds);
@@ -767,6 +787,26 @@ dpctl_dump_flows(int argc, char *argv[])
while (dpif_flow_dump_next(&flow_dump, &key, &key_len,
&mask, &mask_len,
&actions, &actions_len, &stats)) {
+ if (filter) {
+ struct flow flow;
+ struct flow_wildcards wc;
+ struct match match, match_filter;
+ struct minimatch minimatch;
+
+ odp_flow_key_to_flow(key, key_len, &flow);
+ odp_flow_key_to_mask(mask, mask_len, &wc.masks, &flow);
+ match_init(&match, &flow, &wc);
+
+ match_init(&match_filter, &flow_filter, &wc);
+ match_init(&match_filter, &match_filter.flow, &wc_filter);
+ minimatch_init(&minimatch, &match_filter);
+
+ if (!minimatch_matches_flow(&minimatch, &match.flow)) {
+ minimatch_destroy(&minimatch);
+ continue;
+ }
+ minimatch_destroy(&minimatch);
+ }
ds_clear(&ds);
odp_flow_format(key, key_len, mask, mask_len, &portno_names, &ds,
verbosity);
@@ -778,8 +818,11 @@ dpctl_dump_flows(int argc, char *argv[])
printf("%s\n", ds_cstr(&ds));
}
dpif_flow_dump_done(&flow_dump);
+
+ free(filter);
odp_portno_names_destroy(&portno_names);
hmap_destroy(&portno_names);
+ simap_destroy(&names_portno);
ds_destroy(&ds);
dpif_close(dpif);
}
@@ -1166,7 +1209,7 @@ static const struct command all_commands[] = {
{ "set-if", 2, INT_MAX, dpctl_set_if },
{ "dump-dps", 0, 0, dpctl_dump_dps },
{ "show", 0, INT_MAX, dpctl_show },
- { "dump-flows", 0, 1, dpctl_dump_flows },
+ { "dump-flows", 0, 2, dpctl_dump_flows },
{ "add-flow", 2, 3, dpctl_add_flow },
{ "mod-flow", 2, 3, dpctl_mod_flow },
{ "del-flow", 1, 2, dpctl_del_flow },