Skip to content

Commit

Permalink
dpctl: add add-flows command to dpctl
Browse files Browse the repository at this point in the history
When you would like to add, modify, or delete a lot of flows in the
datapath, for example when you want to measure performance, adding
one flow at the time won't scale. This as it takes a decent amount
of time to set up the datapath connection.

This new command is in-line with the same command available in
ovs-ofctl which allows the same thing, with the only difference that
we do not verify all lines before we start execution. This allows for
a continuous add/delete stream. For example with a command like this:

python3 -c 'while True:
  for i in range(0, 1000):
    print("add in_port(0),eth(),eth_type(0x800),ipv4(src=100.1.{}.{}) 1".format(int(i / 256), i % 256))
  for i in range(0, 1000):
    print("delete in_port(0),eth(),eth_type(0x800),ipv4(src=100.1.{}.{})".format(int(i / 256), i % 256))' \
|  sudo utilities/ovs-dpctl add-flows -

Signed-off-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
chaudron authored and ovsrobot committed Sep 11, 2020
1 parent 5198e8a commit 4ad9379
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 20 deletions.
179 changes: 161 additions & 18 deletions lib/dpctl.c
Expand Up @@ -52,6 +52,12 @@
#include "openvswitch/ofp-flow.h"
#include "openvswitch/ofp-port.h"

enum {
DPCTL_FLOWS_ADD = 0,
DPCTL_FLOWS_DEL,
DPCTL_FLOWS_MOD
};

typedef int dpctl_command_handler(int argc, const char *argv[],
struct dpctl_params *);
struct dpctl_command {
Expand Down Expand Up @@ -1102,28 +1108,22 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}

static int
dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags,
struct dpctl_params *dpctl_p)
dpctl_put_flow_dpif(struct dpif *dpif, const char *key_s,
const char *actions_s,
enum dpif_flow_put_flags flags,
struct dpctl_params *dpctl_p)
{
const char *key_s = argv[argc - 2];
const char *actions_s = argv[argc - 1];
struct dpif_flow_stats stats;
struct dpif_port dpif_port;
struct dpif_port_dump port_dump;
struct ofpbuf actions;
struct ofpbuf key;
struct ofpbuf mask;
struct dpif *dpif;
ovs_u128 ufid;
bool ufid_present;
struct simap port_names;
int n, error;

error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
if (error) {
return error;
}

ufid_present = false;
n = odp_ufid_from_string(key_s, &ufid);
if (n < 0) {
Expand Down Expand Up @@ -1185,6 +1185,24 @@ dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags,
out_freekeymask:
ofpbuf_uninit(&mask);
ofpbuf_uninit(&key);
return error;
}

static int
dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags,
struct dpctl_params *dpctl_p)
{
struct dpif *dpif;
int error;

error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
if (error) {
return error;
}

error = dpctl_put_flow_dpif(dpif, argv[argc - 2], argv[argc - 1], flags,
dpctl_p);

dpif_close(dpif);
return error;
}
Expand Down Expand Up @@ -1258,25 +1276,20 @@ dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}

static int
dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
dpctl_del_flow_dpif(struct dpif *dpif, const char *key_s,
struct dpctl_params *dpctl_p)
{
const char *key_s = argv[argc - 1];
struct dpif_flow_stats stats;
struct dpif_port dpif_port;
struct dpif_port_dump port_dump;
struct ofpbuf key;
struct ofpbuf mask; /* To be ignored. */
struct dpif *dpif;

ovs_u128 ufid;
bool ufid_present;
struct simap port_names;
int n, error;

error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
if (error) {
return error;
}

ufid_present = false;
n = odp_ufid_from_string(key_s, &ufid);
if (n < 0) {
Expand Down Expand Up @@ -1334,6 +1347,23 @@ dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
ofpbuf_uninit(&mask);
ofpbuf_uninit(&key);
simap_destroy(&port_names);
return error;
}

static int
dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
{
const char *key_s = argv[argc - 1];
struct dpif *dpif;
int error;

error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
if (error) {
return error;
}

error = dpctl_del_flow_dpif(dpif, key_s, dpctl_p);

dpif_close(dpif);
return error;
}
Expand All @@ -1356,6 +1386,118 @@ dpctl_del_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
return error;
}

static int
dpctl_parse_add_flows_line(struct ds *s, char **flow, char **action)
{
int command = DPCTL_FLOWS_ADD;
const char *line = ds_cstr(s);
size_t len;

/* First figure out the command, or fallback to FLOWS_ADD. */
line += strspn(line, " \t\r\n");
len = strcspn(line, ", \t\r\n");

if (!strncmp(line, "add", len)) {
command = DPCTL_FLOWS_ADD;
} else if (!strncmp(line, "delete", len)) {
command = DPCTL_FLOWS_DEL;
} else if (!strncmp(line, "modify", len)) {
command = DPCTL_FLOWS_MOD;
} else {
len = 0;
}
line += len;

/* Isolate flow and action (for add/modify). */
line += strspn(line, " \t\r\n");
len = strcspn(line, " \t\r\n");

if (len == 0) {
*flow = NULL;
*action = NULL;
return command;
}

*flow = strndup(line, len);

line += len;
line += strspn(line, " \t\r\n");
if (strlen(line)) {
*action = xstrdup(line);
} else {
*action = NULL;
}

return command;
}

static int
dpctl_add_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
{
const char *file_name = argv[argc - 1];
int line_number = 0;
struct dpif *dpif;
struct ds line;
FILE *stream;
int error;

error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
if (error) {
return error;
}

stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
if (!stream) {
error = errno;
dpctl_error(dpctl_p, error, "Opening file \"%s\" failed", file_name);
goto out_close_dpif;
}

ds_init(&line);
while (!ds_get_preprocessed_line(&line, stream, &line_number)) {
/* We do not process all the lines first and then execute the actions
* as we would like to take commands as a continuous stream of
* commands from stdin.
*/
char *flow = NULL;
char *action = NULL;
int cmd = dpctl_parse_add_flows_line(&line, &flow, &action);

if ((!flow && !action)
|| ((cmd == DPCTL_FLOWS_ADD || cmd == DPCTL_FLOWS_MOD) && !action)
|| (cmd == DPCTL_FLOWS_DEL && action)) {
dpctl_error(dpctl_p, 0,
"Failed parsing line number %u, skipped!",
line_number);
} else {
switch (cmd) {
case DPCTL_FLOWS_ADD:
dpctl_put_flow_dpif(dpif, flow, action,
DPIF_FP_CREATE, dpctl_p);
break;
case DPCTL_FLOWS_MOD:
dpctl_put_flow_dpif(dpif, flow, action,
DPIF_FP_MODIFY, dpctl_p);
break;
case DPCTL_FLOWS_DEL:
dpctl_del_flow_dpif(dpif, flow, dpctl_p);
break;
}
}

free(flow);
free(action);
}

ds_destroy(&line);
if (stream != stdin) {
fclose(stream);
}
out_close_dpif:
dpif_close(dpif);
return 0;
}

static int
dpctl_help(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
struct dpctl_params *dpctl_p)
Expand Down Expand Up @@ -2506,6 +2648,7 @@ static const struct dpctl_command all_commands[] = {
{ "dump-flows", "[dp] [filter=..] [type=..]",
0, 3, dpctl_dump_flows, DP_RO },
{ "add-flow", "[dp] flow actions", 2, 3, dpctl_add_flow, DP_RW },
{ "add-flows", "[dp] file", 1, 2, dpctl_add_flows, DP_RW },
{ "mod-flow", "[dp] flow actions", 2, 3, dpctl_mod_flow, DP_RW },
{ "get-flow", "[dp] ufid", 1, 2, dpctl_get_flow, DP_RO },
{ "del-flow", "[dp] flow", 1, 2, dpctl_del_flow, DP_RW },
Expand Down
11 changes: 11 additions & 0 deletions lib/dpctl.man
Expand Up @@ -194,6 +194,17 @@ ovs-dpctl add-flow myDP \\
.
.RE
.TP
.DO "\*(DX\fBadd\-flows\fR [\fIdp\fR] \fIfile\fR"
Reads flow entries from \fIfile\fR (or \fBstdin\fR if \fIfile\fR is
\fB\-\fR) and adds each entry to the datapath.
.
Each flow specification (e.g., each line in \fIfile\fR) may start with
\fBadd\fR, \fBmodify\fR, or \fBdelete\fR keyword to specify whether a
flow is to be added, modified, or deleted. A flow specification without
one of these keywords is treated as a flow add. All flow mods are
executed in the order specified.
.
.TP
.DO "[\fB\-s\fR | \fB\-\-statistics\fR]" "\*(DX\fBdel\-flow\fR" "[\fIdp\fR] \fIflow\fR"
Deletes the flow from \fIdp\fR's flow table that matches \fIflow\fR.
If \fB\-s\fR or \fB\-\-statistics\fR is specified, then
Expand Down
5 changes: 3 additions & 2 deletions utilities/ovs-dpctl.c
Expand Up @@ -191,6 +191,7 @@ usage(void *userdata OVS_UNUSED)
" show DP... show basic info on each DP\n"
" dump-flows [DP] display flows in DP\n"
" add-flow [DP] FLOW ACTIONS add FLOW with ACTIONS to DP\n"
" add-flows [DP] FILE add flows from FILE\n"
" mod-flow [DP] FLOW ACTIONS change FLOW actions to ACTIONS in DP\n"
" get-flow [DP] ufid:UFID fetch flow corresponding to UFID\n"
" del-flow [DP] FLOW delete FLOW from DP\n"
Expand All @@ -205,8 +206,8 @@ usage(void *userdata OVS_UNUSED)
"Each IFACE on add-dp, add-if, and set-if may be followed by\n"
"comma-separated options. See ovs-dpctl(8) for syntax, or the\n"
"Interface table in ovs-vswitchd.conf.db(5) for an options list.\n"
"For COMMAND dump-flows, add-flow, mod-flow, del-flow and\n"
"del-flows, DP is optional if there is only one datapath.\n",
"For COMMAND dump-flows, add-flow, add-flows, mod-flow, del-flow\n"
"and del-flows, DP is optional if there is only one datapath.\n",
program_name, program_name);
vlog_usage();
printf("\nOptions for show and mod-flow:\n"
Expand Down

0 comments on commit 4ad9379

Please sign in to comment.