2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

dpctl: Properly reflect a rule's offloaded to HW state

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>
This commit is contained in:
Gavi Teitz
2018-06-07 09:36:59 +03:00
committed by Simon Horman
parent 21aade70f3
commit d63ca5329f
12 changed files with 105 additions and 37 deletions

View File

@@ -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);
@@ -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);
}
@@ -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)
{
@@ -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);
@@ -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);

View File

@@ -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

View File

@@ -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 {
@@ -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;
@@ -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;
@@ -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
@@ -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)
@@ -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;
}
@@ -1772,6 +1774,7 @@ 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;
@@ -1779,7 +1782,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
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);
@@ -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);
@@ -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;
@@ -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;
}
@@ -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);

View File

@@ -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 *);
@@ -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);

View File

@@ -33,6 +33,7 @@
#include "util.h"
struct dpif_flow_stats;
struct dpif_flow_attrs;
struct ds;
struct flow_wildcards;
struct minimask;

View File

@@ -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.
@@ -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

View File

@@ -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;
@@ -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;
}
@@ -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)
@@ -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;
}
@@ -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);
@@ -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;

View File

@@ -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);
@@ -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 *);

View File

@@ -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);
}
@@ -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);
}
@@ -2430,7 +2431,8 @@ 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;
@@ -2438,7 +2440,7 @@ netdev_ports_flow_get(const struct dpif_class *dpif_class, struct match *match,
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;
}

View File

@@ -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 *);
@@ -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 */

View File

@@ -458,6 +458,28 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {
}
}
static enum tc_offloaded_state
nl_get_flower_offloaded_state(struct nlattr **attrs)
{
uint32_t flower_flags = 0;
if (attrs[TCA_FLOWER_FLAGS]) {
flower_flags = nl_attr_get_u32(attrs[TCA_FLOWER_FLAGS]);
if (flower_flags & TCA_CLS_FLAGS_NOT_IN_HW) {
return TC_OFFLOADED_STATE_NOT_IN_HW;
} else if (flower_flags & TCA_CLS_FLAGS_IN_HW) {
return TC_OFFLOADED_STATE_IN_HW;
}
}
return TC_OFFLOADED_STATE_UNDEFINED;
}
static void
nl_parse_flower_flags(struct nlattr **attrs, struct tc_flower *flower)
{
flower->offloaded_state = nl_get_flower_offloaded_state(attrs);
}
static const struct nl_policy pedit_policy[] = {
[TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,
.min_len = sizeof(struct tc_pedit),
@@ -942,6 +964,7 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower)
nl_parse_flower_vlan(attrs, flower);
nl_parse_flower_ip(attrs, flower);
nl_parse_flower_tunnel(attrs, flower);
nl_parse_flower_flags(attrs, flower);
return nl_parse_flower_actions(attrs, flower);
}

View File

@@ -141,6 +141,12 @@ struct tc_action {
enum tc_action_type type;
};
enum tc_offloaded_state {
TC_OFFLOADED_STATE_UNDEFINED,
TC_OFFLOADED_STATE_IN_HW,
TC_OFFLOADED_STATE_NOT_IN_HW,
};
struct tc_flower {
uint32_t handle;
uint32_t prio;
@@ -180,6 +186,8 @@ struct tc_flower {
struct tc_cookie act_cookie;
bool needs_full_ip_proto_mask;
enum tc_offloaded_state offloaded_state;
};
/* assert that if we overflow with a masked write of uint32_t to the last byte