Skip to content

Commit

Permalink
dpctl: Properly reflect a rule's offloaded to HW state
Browse files Browse the repository at this point in the history
Previously, any rule that is offloaded via a netdev, not necessarily
to the HW, would be reported as "offloaded". This patch fixes this
misalignment, and introduces the 'dp' state, as follows:

rule is in HW via TC offload  -> offloaded=yes dp:tc
rule is in not HW over TC DP  -> offloaded=no  dp:tc
rule is in not HW over OVS DP -> offloaded=no  dp:ovs

To achieve this, the flows's 'offloaded' flag was encapsulated in a new
attrs struct, which contains the offloaded state of the flow and the
DP layer the flow is handled in, and instead of setting the flow's
'offloaded' state based solely on the type of dump it was acquired
via, for netdev flows it now sends the new attrs struct to be
collected along with the rest of the flow via the netdev, allowing
it to be set per flow.

For TC offloads, the offloaded state is set based on the 'in_hw' and
'not_in_hw' flags received from the TC as part of the flower. If no
such flag was received, due to lack of kernel support, it defaults
to true.

Signed-off-by: Gavi Teitz <gavi@mellanox.com>
Acked-by: Roi Dayan <roid@mellanox.com>
[simon: resolved conflict in lib/dpctl.man]
Signed-off-by: Simon Horman <simon.horman@netronome.com>
  • Loading branch information
Gavi Teitz authored and shorman-netronome committed Jun 18, 2018
1 parent 21aade7 commit d63ca53
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 37 deletions.
25 changes: 19 additions & 6 deletions lib/dpctl.c
Expand Up @@ -771,7 +771,7 @@ dpctl_dump_dps(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,

static void
format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
char *type, struct dpctl_params *dpctl_p)
struct dpctl_params *dpctl_p)
{
if (dpctl_p->verbosity && f->ufid_present) {
odp_format_ufid(&f->ufid, ds);
Expand All @@ -782,9 +782,12 @@ format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
ds_put_cstr(ds, ", ");

dpif_flow_stats_format(&f->stats, ds);
if (dpctl_p->verbosity && !type && f->offloaded) {
if (dpctl_p->verbosity && f->attrs.offloaded) {
ds_put_cstr(ds, ", offloaded:yes");
}
if (dpctl_p->verbosity && f->attrs.dp_layer) {
ds_put_format(ds, ", dp:%s", f->attrs.dp_layer);
}
ds_put_cstr(ds, ", actions:");
format_odp_actions(ds, f->actions, f->actions_len, ports);
}
Expand All @@ -794,6 +797,15 @@ static char *supported_dump_types[] = {
"ovs",
};

static bool
flow_passes_type_filter(const struct dpif_flow *f, char *type)
{
if (!strcmp(type, "offloaded")) {
return f->attrs.offloaded;
}
return true;
}

static struct hmap *
dpctl_get_portno_names(struct dpif *dpif, const struct dpctl_params *dpctl_p)
{
Expand Down Expand Up @@ -938,9 +950,10 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}
pmd_id = f.pmd_id;
}
format_dpif_flow(&ds, &f, portno_names, type, dpctl_p);

dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
if (!type || flow_passes_type_filter(&f, type)) {
format_dpif_flow(&ds, &f, portno_names, dpctl_p);
dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
}
}
dpif_flow_dump_thread_destroy(flow_dump_thread);
error = dpif_flow_dump_destroy(flow_dump);
Expand Down Expand Up @@ -1102,7 +1115,7 @@ dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p)
}

ds_init(&ds);
format_dpif_flow(&ds, &flow, portno_names, NULL, dpctl_p);
format_dpif_flow(&ds, &flow, portno_names, dpctl_p);
dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
ds_destroy(&ds);

Expand Down
6 changes: 3 additions & 3 deletions lib/dpctl.man
Expand Up @@ -119,9 +119,9 @@ 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 offloaded rules or \fBovs\fR
to display only non-offloaded rules.
By default both offloaded and non-offloaded rules are displayed.
\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.
.
.IP "\*(DX\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
.TP
Expand Down
27 changes: 16 additions & 11 deletions lib/dpif-netlink.c
Expand Up @@ -1463,13 +1463,13 @@ dpif_netlink_init_flow_del(struct dpif_netlink *dpif,
}

enum {
DUMP_OVS_FLOWS_BIT = 0,
DUMP_OFFLOADED_FLOWS_BIT = 1,
DUMP_OVS_FLOWS_BIT = 0,
DUMP_NETDEV_FLOWS_BIT = 1,
};

enum {
DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT),
DUMP_OFFLOADED_FLOWS = (1 << DUMP_OFFLOADED_FLOWS_BIT),
DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT),
DUMP_NETDEV_FLOWS = (1 << DUMP_NETDEV_FLOWS_BIT),
};

struct dpif_netlink_flow_dump {
Expand All @@ -1495,7 +1495,7 @@ start_netdev_dump(const struct dpif *dpif_,
{
ovs_mutex_init(&dump->netdev_lock);

if (!(dump->type & DUMP_OFFLOADED_FLOWS)) {
if (!(dump->type & DUMP_NETDEV_FLOWS)) {
dump->netdev_dumps_num = 0;
dump->netdev_dumps = NULL;
return;
Expand All @@ -1518,7 +1518,7 @@ dpif_netlink_get_dump_type(char *str) {
}
if ((netdev_is_flow_api_enabled() && !str)
|| (str && (!strcmp(str, "offloaded") || !strcmp(str, "dpctl")))) {
type |= DUMP_OFFLOADED_FLOWS;
type |= DUMP_NETDEV_FLOWS;
}

return type;
Expand Down Expand Up @@ -1656,7 +1656,8 @@ dpif_netlink_flow_to_dpif_flow(struct dpif *dpif, struct dpif_flow *dpif_flow,
&dpif_flow->ufid);
}
dpif_netlink_flow_get_stats(datapath_flow, &dpif_flow->stats);
dpif_flow->offloaded = false;
dpif_flow->attrs.offloaded = false;
dpif_flow->attrs.dp_layer = "ovs";
}

/* The design is such that all threads are working together on the first dump
Expand Down Expand Up @@ -1698,6 +1699,7 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match,
struct ofpbuf *mask_buf,
struct nlattr *actions,
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs,
ovs_u128 *ufid,
struct dpif_flow *flow,
bool terse OVS_UNUSED)
Expand Down Expand Up @@ -1740,7 +1742,7 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match,

flow->pmd_id = PMD_ID_NULL;

flow->offloaded = true;
memcpy(&flow->attrs, attrs, sizeof *attrs);

return 0;
}
Expand Down Expand Up @@ -1772,14 +1774,15 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
struct match match;
struct nlattr *actions;
struct dpif_flow_stats stats;
struct dpif_flow_attrs attrs;
ovs_u128 ufid;
bool has_next;

ofpbuf_use_stack(&key, keybuf, sizeof *keybuf);
ofpbuf_use_stack(&act, actbuf, sizeof *actbuf);
ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf);
has_next = netdev_flow_dump_next(netdev_dump, &match,
&actions, &stats,
&actions, &stats, &attrs,
&ufid,
&thread->nl_flows,
&act);
Expand All @@ -1788,6 +1791,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
&key, &mask,
actions,
&stats,
&attrs,
&ufid,
f,
dump->up.terse);
Expand Down Expand Up @@ -2055,6 +2059,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get)
struct match match;
struct nlattr *actions;
struct dpif_flow_stats stats;
struct dpif_flow_attrs attrs;
struct ofpbuf buf;
uint64_t act_buf[1024 / 8];
struct odputil_keybuf maskbuf;
Expand All @@ -2065,7 +2070,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get)

ofpbuf_use_stack(&buf, &act_buf, sizeof act_buf);
err = netdev_ports_flow_get(dpif->dpif.dpif_class, &match,
&actions, get->ufid, &stats, &buf);
&actions, get->ufid, &stats, &attrs, &buf);
if (err) {
return err;
}
Expand All @@ -2076,7 +2081,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get)
ofpbuf_use_stack(&act, &actbuf, sizeof actbuf);
ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
dpif_netlink_netdev_match_to_dpif_flow(&match, &key, &mask, actions,
&stats,
&stats, &attrs,
(ovs_u128 *) get->ufid,
dpif_flow,
false);
Expand Down
7 changes: 6 additions & 1 deletion lib/dpif.h
Expand Up @@ -507,6 +507,11 @@ struct dpif_flow_stats {
uint16_t tcp_flags;
};

struct dpif_flow_attrs {
bool offloaded; /* True if flow is offloaded to HW. */
const char *dp_layer; /* DP layer the flow is handled in. */
};

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 *);
Expand Down Expand Up @@ -589,7 +594,7 @@ struct dpif_flow {
bool ufid_present; /* True if 'ufid' was provided by datapath.*/
unsigned pmd_id; /* Datapath poll mode driver id. */
struct dpif_flow_stats stats; /* Flow statistics. */
bool offloaded; /* True if flow is offloaded */
struct dpif_flow_attrs attrs; /* Flow attributes. */
};
int dpif_flow_dump_next(struct dpif_flow_dump_thread *,
struct dpif_flow *flows, int max_flows);
Expand Down
1 change: 1 addition & 0 deletions lib/flow.h
Expand Up @@ -33,6 +33,7 @@
#include "util.h"

struct dpif_flow_stats;
struct dpif_flow_attrs;
struct ds;
struct flow_wildcards;
struct minimask;
Expand Down
5 changes: 3 additions & 2 deletions lib/netdev-provider.h
Expand Up @@ -837,7 +837,8 @@ struct netdev_class {
* to be pre allocated by the caller. */
bool (*flow_dump_next)(struct netdev_flow_dump *, struct match *,
struct nlattr **actions,
struct dpif_flow_stats *stats, ovs_u128 *ufid,
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs, ovs_u128 *ufid,
struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);

/* Offload the given flow on netdev.
Expand All @@ -857,7 +858,7 @@ struct netdev_class {
* Return 0 if successful, otherwise returns a positive errno value. */
int (*flow_get)(struct netdev *, struct match *, struct nlattr **actions,
const ovs_u128 *ufid, struct dpif_flow_stats *,
struct ofpbuf *wbuffer);
struct dpif_flow_attrs *, struct ofpbuf *wbuffer);

/* Delete a flow specified by ufid from netdev.
* 'stats' is populated according to the rules set out in the description
Expand Down
11 changes: 9 additions & 2 deletions lib/netdev-tc-offloads.c
Expand Up @@ -398,6 +398,7 @@ parse_tc_flower_to_match(struct tc_flower *flower,
struct match *match,
struct nlattr **actions,
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs,
struct ofpbuf *buf)
{
size_t act_off;
Expand Down Expand Up @@ -565,6 +566,10 @@ parse_tc_flower_to_match(struct tc_flower *flower,
stats->used = flower->lastused;
}

attrs->offloaded = (flower->offloaded_state == TC_OFFLOADED_STATE_IN_HW)
|| (flower->offloaded_state == TC_OFFLOADED_STATE_UNDEFINED);
attrs->dp_layer = "tc";

return 0;
}

Expand All @@ -573,6 +578,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
struct match *match,
struct nlattr **actions,
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs,
ovs_u128 *ufid,
struct ofpbuf *rbuffer,
struct ofpbuf *wbuffer)
Expand All @@ -587,7 +593,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
continue;
}

if (parse_tc_flower_to_match(&flower, match, actions, stats,
if (parse_tc_flower_to_match(&flower, match, actions, stats, attrs,
wbuffer)) {
continue;
}
Expand Down Expand Up @@ -1119,6 +1125,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
struct nlattr **actions,
const ovs_u128 *ufid,
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs,
struct ofpbuf *buf)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
Expand Down Expand Up @@ -1154,7 +1161,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
}

in_port = netdev_ifindex_to_odp_port(ifindex);
parse_tc_flower_to_match(&flower, match, actions, stats, buf);
parse_tc_flower_to_match(&flower, match, actions, stats, attrs, buf);

match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
match->flow.in_port.odp_port = in_port;
Expand Down
4 changes: 3 additions & 1 deletion lib/netdev-tc-offloads.h
Expand Up @@ -25,6 +25,7 @@ int netdev_tc_flow_dump_destroy(struct netdev_flow_dump *);
bool netdev_tc_flow_dump_next(struct netdev_flow_dump *, struct match *,
struct nlattr **actions,
struct dpif_flow_stats *,
struct dpif_flow_attrs *,
ovs_u128 *ufid,
struct ofpbuf *rbuffer,
struct ofpbuf *wbuffer);
Expand All @@ -34,7 +35,8 @@ int netdev_tc_flow_put(struct netdev *, struct match *,
struct dpif_flow_stats *);
int netdev_tc_flow_get(struct netdev *, struct match *,
struct nlattr **actions, const ovs_u128 *,
struct dpif_flow_stats *, struct ofpbuf *);
struct dpif_flow_stats *,
struct dpif_flow_attrs *, struct ofpbuf *);
int netdev_tc_flow_del(struct netdev *, const ovs_u128 *,
struct dpif_flow_stats *);
int netdev_tc_init_flow_api(struct netdev *);
Expand Down
18 changes: 10 additions & 8 deletions lib/netdev.c
Expand Up @@ -2162,14 +2162,14 @@ netdev_flow_dump_destroy(struct netdev_flow_dump *dump)
bool
netdev_flow_dump_next(struct netdev_flow_dump *dump, struct match *match,
struct nlattr **actions, struct dpif_flow_stats *stats,
ovs_u128 *ufid, struct ofpbuf *rbuffer,
struct ofpbuf *wbuffer)
struct dpif_flow_attrs *attrs, ovs_u128 *ufid,
struct ofpbuf *rbuffer, struct ofpbuf *wbuffer)
{
const struct netdev_class *class = dump->netdev->netdev_class;

return (class->flow_dump_next
? class->flow_dump_next(dump, match, actions, stats, ufid,
rbuffer, wbuffer)
? class->flow_dump_next(dump, match, actions, stats, attrs,
ufid, rbuffer, wbuffer)
: false);
}

Expand All @@ -2190,12 +2190,13 @@ netdev_flow_put(struct netdev *netdev, struct match *match,
int
netdev_flow_get(struct netdev *netdev, struct match *match,
struct nlattr **actions, const ovs_u128 *ufid,
struct dpif_flow_stats *stats, struct ofpbuf *buf)
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs, struct ofpbuf *buf)
{
const struct netdev_class *class = netdev->netdev_class;

return (class->flow_get
? class->flow_get(netdev, match, actions, ufid, stats, buf)
? class->flow_get(netdev, match, actions, ufid, stats, attrs, buf)
: EOPNOTSUPP);
}

Expand Down Expand Up @@ -2430,15 +2431,16 @@ netdev_ports_flow_del(const struct dpif_class *dpif_class,
int
netdev_ports_flow_get(const struct dpif_class *dpif_class, struct match *match,
struct nlattr **actions, const ovs_u128 *ufid,
struct dpif_flow_stats *stats, struct ofpbuf *buf)
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs, struct ofpbuf *buf)
{
struct port_to_netdev_data *data;

ovs_mutex_lock(&netdev_hmap_mutex);
HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
if (data->dpif_class == dpif_class
&& !netdev_flow_get(data->netdev, match, actions,
ufid, stats, buf)) {
ufid, stats, attrs, buf)) {
ovs_mutex_unlock(&netdev_hmap_mutex);
return 0;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/netdev.h
Expand Up @@ -209,14 +209,14 @@ int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump);
int netdev_flow_dump_destroy(struct netdev_flow_dump *);
bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *,
struct nlattr **actions, struct dpif_flow_stats *,
ovs_u128 *ufid, struct ofpbuf *rbuffer,
struct ofpbuf *wbuffer);
struct dpif_flow_attrs *, ovs_u128 *ufid,
struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
int netdev_flow_put(struct netdev *, struct match *, struct nlattr *actions,
size_t actions_len, const ovs_u128 *,
struct offload_info *, struct dpif_flow_stats *);
int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions,
const ovs_u128 *, struct dpif_flow_stats *,
struct ofpbuf *wbuffer);
struct dpif_flow_attrs *, struct ofpbuf *wbuffer);
int netdev_flow_del(struct netdev *, const ovs_u128 *,
struct dpif_flow_stats *);
int netdev_init_flow_api(struct netdev *);
Expand All @@ -239,6 +239,7 @@ int netdev_ports_flow_get(const struct dpif_class *, struct match *match,
struct nlattr **actions,
const ovs_u128 *ufid,
struct dpif_flow_stats *stats,
struct dpif_flow_attrs *attrs,
struct ofpbuf *buf);

/* native tunnel APIs */
Expand Down

0 comments on commit d63ca53

Please sign in to comment.