Skip to content

Commit 5a0a570

Browse files
committed
ovs-dpctl: Add a 'filter' option to match wildcarded 'dump-flows'.
With mega-flows, many flows in the kernel datapath are wildcarded. For someone that is debugging a system and wants to find a particular flow and its actions, it is a little hard to zero-in on the flow because some fields are wildcarded. With the filter='$filter' option, we can now filter on the o/p of 'ovs-dpctl dump-flows'. Signed-off-by: Gurucharan Shetty <gshetty@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
1 parent aa0667b commit 5a0a570

9 files changed

Lines changed: 264 additions & 15 deletions

File tree

lib/meta-flow.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,24 @@ mf_set_value(const struct mf_field *mf,
15381538
}
15391539
}
15401540

1541+
/* Unwildcard 'mask' member field described by 'mf'. The caller is
1542+
* responsible for ensuring that 'mask' meets 'mf''s prerequisites. */
1543+
void
1544+
mf_mask_field(const struct mf_field *mf, struct flow *mask)
1545+
{
1546+
static const union mf_value exact_match_mask = MF_EXACT_MASK_INITIALIZER;
1547+
1548+
/* For MFF_DL_VLAN, we cannot send a all 1's to flow_set_dl_vlan()
1549+
* as that will be considered as OFP10_VLAN_NONE. So consider it as a
1550+
* special case. For the rest, calling mf_set_flow_value() is good
1551+
* enough. */
1552+
if (mf->id == MFF_DL_VLAN) {
1553+
flow_set_dl_vlan(mask, htons(VLAN_VID_MASK));
1554+
} else {
1555+
mf_set_flow_value(mf, &exact_match_mask, mask);
1556+
}
1557+
}
1558+
15411559
/* Sets 'flow' member field described by 'mf' to 'value'. The caller is
15421560
* responsible for ensuring that 'flow' meets 'mf''s prerequisites.*/
15431561
void

lib/meta-flow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ void mf_set_value(const struct mf_field *, const union mf_value *value,
355355
void mf_set_flow_value(const struct mf_field *, const union mf_value *value,
356356
struct flow *);
357357
bool mf_is_zero(const struct mf_field *, const struct flow *);
358+
void mf_mask_field(const struct mf_field *, struct flow *);
358359

359360
void mf_get(const struct mf_field *, const struct match *,
360361
union mf_value *value, union mf_value *mask);

lib/ofp-parse.c

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "openflow/openflow.h"
3737
#include "ovs-thread.h"
3838
#include "packets.h"
39+
#include "simap.h"
3940
#include "socket-util.h"
4041
#include "vconn.h"
4142

@@ -1879,18 +1880,24 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
18791880
/* Parses a specification of a flow from 's' into 'flow'. 's' must take the
18801881
* form FIELD=VALUE[,FIELD=VALUE]... where each FIELD is the name of a
18811882
* mf_field. Fields must be specified in a natural order for satisfying
1882-
* prerequisites.
1883+
* prerequisites. If 'mask' is specified, fills the mask field for each of the
1884+
* field specified in flow. If the map, 'names_portno' is specfied, converts
1885+
* the in_port name into port no while setting the 'flow'.
18831886
*
18841887
* Returns NULL on success, otherwise a malloc()'d string that explains the
18851888
* problem. */
18861889
char *
1887-
parse_ofp_exact_flow(struct flow *flow, const char *s)
1890+
parse_ofp_exact_flow(struct flow *flow, struct flow *mask, const char *s,
1891+
const struct simap *portno_names)
18881892
{
18891893
char *pos, *key, *value_s;
18901894
char *error = NULL;
18911895
char *copy;
18921896

18931897
memset(flow, 0, sizeof *flow);
1898+
if (mask) {
1899+
memset(mask, 0, sizeof *mask);
1900+
}
18941901

18951902
pos = copy = xstrdup(s);
18961903
while (ofputil_parse_key_value(&pos, &key, &value_s)) {
@@ -1901,6 +1908,9 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
19011908
goto exit;
19021909
}
19031910
flow->dl_type = htons(p->dl_type);
1911+
if (mask) {
1912+
mask->dl_type = OVS_BE16_MAX;
1913+
}
19041914

19051915
if (p->nw_proto) {
19061916
if (flow->nw_proto) {
@@ -1909,6 +1919,9 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
19091919
goto exit;
19101920
}
19111921
flow->nw_proto = p->nw_proto;
1922+
if (mask) {
1923+
mask->nw_proto = UINT8_MAX;
1924+
}
19121925
}
19131926
} else {
19141927
const struct mf_field *mf;
@@ -1932,15 +1945,28 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
19321945
goto exit;
19331946
}
19341947

1935-
field_error = mf_parse_value(mf, value_s, &value);
1936-
if (field_error) {
1937-
error = xasprintf("%s: bad value for %s (%s)",
1938-
s, key, field_error);
1939-
free(field_error);
1940-
goto exit;
1941-
}
1948+
if (!strcmp(key, "in_port")
1949+
&& portno_names
1950+
&& simap_contains(portno_names, value_s)) {
1951+
flow->in_port.ofp_port = u16_to_ofp(
1952+
simap_get(portno_names, value_s));
1953+
if (mask) {
1954+
mask->in_port.ofp_port = u16_to_ofp(ntohs(OVS_BE16_MAX));
1955+
}
1956+
} else {
1957+
field_error = mf_parse_value(mf, value_s, &value);
1958+
if (field_error) {
1959+
error = xasprintf("%s: bad value for %s (%s)",
1960+
s, key, field_error);
1961+
free(field_error);
1962+
goto exit;
1963+
}
19421964

1943-
mf_set_flow_value(mf, &value, flow);
1965+
mf_set_flow_value(mf, &value, flow);
1966+
if (mask) {
1967+
mf_mask_field(mf, mask);
1968+
}
1969+
}
19441970
}
19451971
}
19461972

@@ -1953,6 +1979,9 @@ parse_ofp_exact_flow(struct flow *flow, const char *s)
19531979

19541980
if (error) {
19551981
memset(flow, 0, sizeof *flow);
1982+
if (mask) {
1983+
memset(mask, 0, sizeof *mask);
1984+
}
19561985
}
19571986
return error;
19581987
}

lib/ofp-parse.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct ofputil_flow_stats_request;
3232
struct ofputil_group_mod;
3333
struct ofputil_meter_mod;
3434
struct ofputil_table_mod;
35+
struct simap;
3536
enum ofputil_protocol;
3637

3738
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,
6263
enum ofputil_protocol *usable_protocols)
6364
WARN_UNUSED_RESULT;
6465

65-
char *parse_ofp_exact_flow(struct flow *, const char *);
66+
char *parse_ofp_exact_flow(struct flow *flow, struct flow *mask, const char *s,
67+
const struct simap *portno_names);
6668

6769
char *parse_ofp_meter_mod_str(struct ofputil_meter_mod *, const char *string,
6870
int command,

ofproto/ofproto-dpif.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5201,7 +5201,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
52015201
goto exit;
52025202
}
52035203
ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
5204-
} else if (!parse_ofp_exact_flow(&flow, argv[argc - 1])) {
5204+
} else if (!parse_ofp_exact_flow(&flow, NULL, argv[argc - 1], NULL)) {
52055205
if (argc != 3) {
52065206
unixctl_command_reply_error(conn, "Must specify bridge name");
52075207
goto exit;

tests/odp.at

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,71 @@ AT_CHECK_UNQUOTED([test-odp parse-wc-keys < odp.txt], [0], [`cat odp.txt`
151151
])
152152
AT_CLEANUP
153153

154+
AT_SETUP([OVS datapath wildcarded key filtering.])
155+
dnl We could add a test for invalid forms, but that's less important.
156+
AT_DATA([odp-base.txt], [dnl
157+
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234/0xfff0)
158+
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)
159+
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)
160+
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)
161+
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)
162+
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)
163+
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)
164+
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)
165+
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)
166+
])
167+
AT_DATA([odp-vlan-base.txt], [dnl
168+
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))
169+
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))
170+
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))
171+
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))
172+
])
173+
AT_DATA([odp-eth-type.txt], [dnl
174+
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234/0xfff0)
175+
])
176+
AT_DATA([odp-vlan.txt], [dnl
177+
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))
178+
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))
179+
])
180+
AT_DATA([odp-ipv4.txt], [dnl
181+
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)
182+
])
183+
AT_DATA([odp-icmp.txt], [dnl
184+
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)
185+
])
186+
AT_DATA([odp-arp.txt], [dnl
187+
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)
188+
])
189+
AT_DATA([odp-tcp.txt], [dnl
190+
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)
191+
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)
192+
])
193+
AT_DATA([odp-tcp6.txt], [dnl
194+
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)
195+
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)
196+
])
197+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_type=0x1235' < odp-base.txt], [0], [`cat odp-eth-type.txt`
198+
])
199+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_vlan=99' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
200+
])
201+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_vlan=99,ip' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
202+
])
203+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='ip,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
204+
])
205+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='ip,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
206+
])
207+
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`
208+
])
209+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='icmp,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-icmp.txt`
210+
])
211+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='arp,arp_spa=1.2.3.5' < odp-base.txt], [0], [`cat odp-arp.txt`
212+
])
213+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='tcp,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp.txt`
214+
])
215+
AT_CHECK_UNQUOTED([test-odp parse-filter filter='tcp6,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp6.txt`
216+
])
217+
AT_CLEANUP
218+
154219
AT_SETUP([OVS datapath actions parsing and formatting - valid forms])
155220
AT_DATA([actions.txt], [dnl
156221
1,2,3

tests/test-odp.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020

2121
#include "dynamic-string.h"
2222
#include "flow.h"
23+
#include "match.h"
2324
#include "odp-util.h"
25+
#include "ofp-parse.h"
2426
#include "ofpbuf.h"
2527
#include "util.h"
2628
#include "vlog.h"
@@ -135,15 +137,96 @@ parse_actions(void)
135137
return 0;
136138
}
137139

140+
static int
141+
parse_filter(char *filter_parse)
142+
{
143+
struct ds in;
144+
struct flow flow_filter;
145+
struct flow_wildcards wc_filter;
146+
char *error, *filter = NULL;
147+
148+
vlog_set_levels_from_string_assert("odp_util:console:dbg");
149+
if (filter_parse && !strncmp(filter_parse, "filter=", 7)) {
150+
filter = strdup(filter_parse+7);
151+
memset(&flow_filter, 0, sizeof(flow_filter));
152+
memset(&wc_filter, 0, sizeof(wc_filter));
153+
154+
error = parse_ofp_exact_flow(&flow_filter, &wc_filter.masks, filter,
155+
NULL);
156+
if (error) {
157+
ovs_fatal(0, "Failed to parse filter (%s)", error);
158+
}
159+
} else {
160+
ovs_fatal(0, "No filter to parse.");
161+
}
162+
163+
ds_init(&in);
164+
while (!ds_get_test_line(&in, stdin)) {
165+
struct ofpbuf odp_key;
166+
struct ofpbuf odp_mask;
167+
struct ds out;
168+
int error;
169+
170+
/* Convert string to OVS DP key. */
171+
ofpbuf_init(&odp_key, 0);
172+
ofpbuf_init(&odp_mask, 0);
173+
error = odp_flow_from_string(ds_cstr(&in), NULL,
174+
&odp_key, &odp_mask);
175+
if (error) {
176+
printf("odp_flow_from_string: error\n");
177+
goto next;
178+
}
179+
180+
if (filter) {
181+
struct flow flow;
182+
struct flow_wildcards wc;
183+
struct match match, match_filter;
184+
struct minimatch minimatch;
185+
186+
odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
187+
odp_flow_key_to_mask(odp_mask.data, odp_mask.size, &wc.masks,
188+
&flow);
189+
match_init(&match, &flow, &wc);
190+
191+
match_init(&match_filter, &flow_filter, &wc);
192+
match_init(&match_filter, &match_filter.flow, &wc_filter);
193+
minimatch_init(&minimatch, &match_filter);
194+
195+
if (!minimatch_matches_flow(&minimatch, &match.flow)) {
196+
minimatch_destroy(&minimatch);
197+
goto next;
198+
}
199+
minimatch_destroy(&minimatch);
200+
}
201+
/* Convert odp_key to string. */
202+
ds_init(&out);
203+
odp_flow_format(odp_key.data, odp_key.size,
204+
odp_mask.data, odp_mask.size, NULL, &out, false);
205+
puts(ds_cstr(&out));
206+
ds_destroy(&out);
207+
208+
next:
209+
ofpbuf_uninit(&odp_key);
210+
ofpbuf_uninit(&odp_mask);
211+
}
212+
ds_destroy(&in);
213+
214+
free(filter);
215+
return 0;
216+
}
217+
138218
int
139219
main(int argc, char *argv[])
140220
{
221+
set_program_name(argv[0]);
141222
if (argc == 2 &&!strcmp(argv[1], "parse-keys")) {
142223
return parse_keys(false);
143224
} else if (argc == 2 &&!strcmp(argv[1], "parse-wc-keys")) {
144225
return parse_keys(true);
145226
} else if (argc == 2 && !strcmp(argv[1], "parse-actions")) {
146227
return parse_actions();
228+
} else if (argc == 3 && !strcmp(argv[1], "parse-filter")) {
229+
return parse_filter(argv[2]);
147230
} else {
148231
ovs_fatal(0, "usage: %s parse-keys | parse-wc-keys | parse-actions", argv[0]);
149232
}

utilities/ovs-dpctl.8.in

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,19 @@ exactly one datapath exists, in which case that datapath is the
118118
default. When multiple datapaths exist, then a datapath name is
119119
required.
120120
.
121-
.IP "[\fB\-m \fR| \fB\-\-more\fR] \fBdump\-flows\fR [\fIdp\fR]"
121+
.IP "[\fB\-m \fR| \fB\-\-more\fR] \fBdump\-flows\fR [\fIdp\fR] [\fBfilter=\fIfilter\fR]"
122122
Prints to the console all flow entries in datapath \fIdp\fR's flow
123123
table. Without \fB\-m\fR or \fB\-\-more\fR, output omits match fields
124124
that a flow wildcards entirely; with \fB\-m\fR or \fB\-\-more\fR,
125125
output includes all wildcarded fields.
126+
.IP
127+
If \fBfilter=\fIfilter\fR is specified, only displays the flows
128+
that match the \fIfilter\fR. \fIfilter\fR is a flow in the form similiar
129+
to that accepted by \fBovs\-ofctl\fR(8)'s \fBadd\-flow\fR command. (This is
130+
not an OpenFlow flow: besides other differences, it never contains wildcards.)
131+
The \fIfilter\fR is also useful to match wildcarded fields in the datapath
132+
flow. As an example, \fBfilter='tcp,tp_src=100'\fR will match the
133+
datapath flow containing '\fBtcp(src=80/0xff00,dst=8080/0xff)\fR'.
126134
.
127135
.IP "\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
128136
.IQ "[\fB\-\-clear\fR] [\fB\-\-may-create\fR] [\fB\-s\fR | \fB\-\-statistics\fR] \fBmod\-flow\fR [\fIdp\fR] \fIflow actions\fR"

0 commit comments

Comments
 (0)