2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

dpctl: Expand the flow dump type filter

Added new types to the flow dump filter, and allowed multiple filter
types to be passed at once, as a comma separated list. The new types
added are:
 * tc - specifies flows handled by the tc dp
 * non-offloaded - specifies flows not offloaded to the HW
 * all - specifies flows of all types

The type list is now fully parsed by the dpctl, and a new struct was
added to dpif which enables dpctl to define which types of dumps to
provide, rather than passing the type string and having dpif parse it.

Signed-off-by: Gavi Teitz <gavi@mellanox.com>
Acked-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
Gavi Teitz
2018-08-10 11:30:08 +03:00
committed by Simon Horman
parent 0d6b401cf6
commit a692410af0
7 changed files with 129 additions and 66 deletions

View File

@@ -837,18 +837,85 @@ format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
format_odp_actions(ds, f->actions, f->actions_len, ports);
}
static char *supported_dump_types[] = {
"offloaded",
"ovs",
struct dump_types {
bool ovs;
bool tc;
bool offloaded;
bool non_offloaded;
};
static bool
flow_passes_type_filter(const struct dpif_flow *f, char *type)
static void
enable_all_dump_types(struct dump_types *dump_types)
{
if (!strcmp(type, "offloaded")) {
return f->attrs.offloaded;
dump_types->ovs = true;
dump_types->tc = true;
dump_types->offloaded = true;
dump_types->non_offloaded = true;
}
static int
populate_dump_types(char *types_list, struct dump_types *dump_types,
struct dpctl_params *dpctl_p)
{
if (!types_list) {
enable_all_dump_types(dump_types);
return 0;
}
return true;
char *current_type;
while (types_list && types_list[0] != '\0') {
current_type = types_list;
size_t type_len = strcspn(current_type, ",");
types_list += type_len + (types_list[type_len] != '\0');
current_type[type_len] = '\0';
if (!strcmp(current_type, "ovs")) {
dump_types->ovs = true;
} else if (!strcmp(current_type, "tc")) {
dump_types->tc = true;
} else if (!strcmp(current_type, "offloaded")) {
dump_types->offloaded = true;
} else if (!strcmp(current_type, "non-offloaded")) {
dump_types->non_offloaded = true;
} else if (!strcmp(current_type, "all")) {
enable_all_dump_types(dump_types);
} else {
dpctl_error(dpctl_p, EINVAL, "Failed to parse type (%s)",
current_type);
return EINVAL;
}
}
return 0;
}
static void
determine_dpif_flow_dump_types(struct dump_types *dump_types,
struct dpif_flow_dump_types *dpif_dump_types)
{
dpif_dump_types->ovs_flows = dump_types->ovs || dump_types->non_offloaded;
dpif_dump_types->netdev_flows = dump_types->tc || dump_types->offloaded
|| dump_types->non_offloaded;
}
static bool
flow_passes_type_filter(const struct dpif_flow *f,
struct dump_types *dump_types)
{
if (dump_types->ovs && !strcmp(f->attrs.dp_layer, "ovs")) {
return true;
}
if (dump_types->tc && !strcmp(f->attrs.dp_layer, "tc")) {
return true;
}
if (dump_types->offloaded && f->attrs.offloaded) {
return true;
}
if (dump_types->non_offloaded && !(f->attrs.offloaded)) {
return true;
}
return false;
}
static struct hmap *
@@ -888,9 +955,11 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
struct ds ds;
char *filter = NULL;
char *type = NULL;
struct flow flow_filter;
struct flow_wildcards wc_filter;
char *types_list = NULL;
struct dump_types dump_types;
struct dpif_flow_dump_types dpif_dump_types;
struct dpif_flow_dump_thread *flow_dump_thread;
struct dpif_flow_dump *flow_dump;
@@ -903,8 +972,8 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
lastargc = argc;
if (!strncmp(argv[argc - 1], "filter=", 7) && !filter) {
filter = xstrdup(argv[--argc] + 7);
} else if (!strncmp(argv[argc - 1], "type=", 5) && !type) {
type = xstrdup(argv[--argc] + 5);
} else if (!strncmp(argv[argc - 1], "type=", 5) && !types_list) {
types_list = xstrdup(argv[--argc] + 5);
}
}
@@ -937,19 +1006,12 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}
}
if (type) {
error = EINVAL;
for (int i = 0; i < ARRAY_SIZE(supported_dump_types); i++) {
if (!strcmp(supported_dump_types[i], type)) {
error = 0;
break;
}
}
if (error) {
dpctl_error(dpctl_p, error, "Failed to parse type (%s)", type);
goto out_free;
}
memset(&dump_types, 0, sizeof dump_types);
error = populate_dump_types(types_list, &dump_types, dpctl_p);
if (error) {
goto out_free;
}
determine_dpif_flow_dump_types(&dump_types, &dpif_dump_types);
/* Make sure that these values are different. PMD_ID_NULL means that the
* pmd is unspecified (e.g. because the datapath doesn't have different
@@ -959,7 +1021,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
ds_init(&ds);
memset(&f, 0, sizeof f);
flow_dump = dpif_flow_dump_create(dpif, false, (type ? type : "dpctl"));
flow_dump = dpif_flow_dump_create(dpif, false, &dpif_dump_types);
flow_dump_thread = dpif_flow_dump_thread_create(flow_dump);
while (dpif_flow_dump_next(flow_dump_thread, &f, 1)) {
if (filter) {
@@ -995,7 +1057,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}
pmd_id = f.pmd_id;
}
if (!type || flow_passes_type_filter(&f, type)) {
if (flow_passes_type_filter(&f, &dump_types)) {
format_dpif_flow(&ds, &f, portno_names, dpctl_p);
dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
}
@@ -1013,7 +1075,7 @@ out_dpifclose:
dpif_close(dpif);
out_free:
free(filter);
free(type);
free(types_list);
return error;
}

View File

@@ -118,10 +118,16 @@ 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
If \fBtype=\fItype\fR is specified, only displays flows of a specific type.
\fItype\fR can be \fBoffloaded\fR to display only rules offloaded to the HW
or \fBovs\fR to display only rules from the OVS tables.
By default all rules are displayed.
If \fBtype=\fItype\fR is specified, only displays flows of the specified types.
\fItype\fR is a comma separated list, which can contain any of the following:
.
\fBovs\fR - displays flows handled in the ovs dp
\fBtc\fR - displays flows handled in the tc dp
\fBoffloaded\fR - displays flows offloaded to the HW
\fBnon-offloaded\fR - displays flows not offloaded to the HW
\fBall\fR - displays all the types of flows
.IP
By default all the types of flows are displayed.
.
.IP "\*(DX\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
.TP

View File

@@ -3491,7 +3491,7 @@ dpif_netdev_flow_dump_cast(struct dpif_flow_dump *dump)
static struct dpif_flow_dump *
dpif_netdev_flow_dump_create(const struct dpif *dpif_, bool terse,
char *type OVS_UNUSED)
struct dpif_flow_dump_types *types OVS_UNUSED)
{
struct dpif_netdev_flow_dump *dump;

View File

@@ -1465,16 +1465,6 @@ dpif_netlink_init_flow_del(struct dpif_netlink *dpif,
del->ufid, del->terse, request);
}
enum {
DUMP_OVS_FLOWS_BIT = 0,
DUMP_NETDEV_FLOWS_BIT = 1,
};
enum {
DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT),
DUMP_NETDEV_FLOWS = (1 << DUMP_NETDEV_FLOWS_BIT),
};
struct dpif_netlink_flow_dump {
struct dpif_flow_dump up;
struct nl_dump nl_dump;
@@ -1483,7 +1473,7 @@ struct dpif_netlink_flow_dump {
int netdev_dumps_num; /* Number of netdev_flow_dumps */
struct ovs_mutex netdev_lock; /* Guards the following. */
int netdev_current_dump OVS_GUARDED; /* Shared current dump */
int type; /* Type of dump */
struct dpif_flow_dump_types types; /* Type of dump */
};
static struct dpif_netlink_flow_dump *
@@ -1498,7 +1488,7 @@ start_netdev_dump(const struct dpif *dpif_,
{
ovs_mutex_init(&dump->netdev_lock);
if (!(dump->type & DUMP_NETDEV_FLOWS)) {
if (!(dump->types.netdev_flows)) {
dump->netdev_dumps_num = 0;
dump->netdev_dumps = NULL;
return;
@@ -1512,24 +1502,21 @@ start_netdev_dump(const struct dpif *dpif_,
ovs_mutex_unlock(&dump->netdev_lock);
}
static int
dpif_netlink_get_dump_type(char *str) {
int type = 0;
if (!str || !strcmp(str, "ovs") || !strcmp(str, "dpctl")) {
type |= DUMP_OVS_FLOWS;
static void
dpif_netlink_populate_flow_dump_types(struct dpif_netlink_flow_dump *dump,
struct dpif_flow_dump_types *types)
{
if (!types) {
dump->types.ovs_flows = true;
dump->types.netdev_flows = true;
} else {
memcpy(&dump->types, types, sizeof *types);
}
if ((netdev_is_flow_api_enabled() && !str)
|| (str && (!strcmp(str, "offloaded") || !strcmp(str, "dpctl")))) {
type |= DUMP_NETDEV_FLOWS;
}
return type;
}
static struct dpif_flow_dump *
dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse,
char *type)
struct dpif_flow_dump_types *types)
{
const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
struct dpif_netlink_flow_dump *dump;
@@ -1539,9 +1526,9 @@ dpif_netlink_flow_dump_create(const struct dpif *dpif_, bool terse,
dump = xmalloc(sizeof *dump);
dpif_flow_dump_init(&dump->up, dpif_);
dump->type = dpif_netlink_get_dump_type(type);
dpif_netlink_populate_flow_dump_types(dump, types);
if (dump->type & DUMP_OVS_FLOWS) {
if (dump->types.ovs_flows) {
dpif_netlink_flow_init(&request);
request.cmd = OVS_FLOW_CMD_GET;
request.dp_ifindex = dpif->dp_ifindex;
@@ -1568,7 +1555,7 @@ dpif_netlink_flow_dump_destroy(struct dpif_flow_dump *dump_)
unsigned int nl_status = 0;
int dump_status;
if (dump->type & DUMP_OVS_FLOWS) {
if (dump->types.ovs_flows) {
nl_status = nl_dump_done(&dump->nl_dump);
}
@@ -1804,7 +1791,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
}
}
if (!(dump->type & DUMP_OVS_FLOWS)) {
if (!(dump->types.ovs_flows)) {
return n_flows;
}

View File

@@ -284,9 +284,11 @@ struct dpif_class {
* If 'terse' is true, then only UID and statistics will
* be returned in the dump. Otherwise, all fields will be returned.
*
* If 'type' isn't null, dumps only the flows of the given type. */
struct dpif_flow_dump *(*flow_dump_create)(const struct dpif *dpif,
bool terse, char *type);
* If 'types' isn't null, dumps only the flows of the passed types. */
struct dpif_flow_dump *(*flow_dump_create)(
const struct dpif *dpif,
bool terse,
struct dpif_flow_dump_types *types);
int (*flow_dump_destroy)(struct dpif_flow_dump *dump);
struct dpif_flow_dump_thread *(*flow_dump_thread_create)(

View File

@@ -1080,9 +1080,10 @@ dpif_flow_del(struct dpif *dpif,
* This function always successfully returns a dpif_flow_dump. Error
* reporting is deferred to dpif_flow_dump_destroy(). */
struct dpif_flow_dump *
dpif_flow_dump_create(const struct dpif *dpif, bool terse, char *type)
dpif_flow_dump_create(const struct dpif *dpif, bool terse,
struct dpif_flow_dump_types *types)
{
return dpif->dpif_class->flow_dump_create(dpif, terse, type);
return dpif->dpif_class->flow_dump_create(dpif, terse, types);
}
/* Destroys 'dump', which must have been created with dpif_flow_dump_create().

View File

@@ -512,6 +512,11 @@ struct dpif_flow_attrs {
const char *dp_layer; /* DP layer the flow is handled in. */
};
struct dpif_flow_dump_types {
bool ovs_flows;
bool netdev_flows;
};
void dpif_flow_stats_extract(const struct flow *, const struct dp_packet *packet,
long long int used, struct dpif_flow_stats *);
void dpif_flow_stats_format(const struct dpif_flow_stats *, struct ds *);
@@ -573,7 +578,7 @@ int dpif_flow_get(struct dpif *,
* All error reporting is deferred to the call to dpif_flow_dump_destroy().
*/
struct dpif_flow_dump *dpif_flow_dump_create(const struct dpif *, bool terse,
char *type);
struct dpif_flow_dump_types *);
int dpif_flow_dump_destroy(struct dpif_flow_dump *);
struct dpif_flow_dump_thread *dpif_flow_dump_thread_create(