mirror of
https://github.com/openvswitch/ovs
synced 2025-09-03 15:55:19 +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:
25
lib/dpctl.c
25
lib/dpctl.c
@@ -771,7 +771,7 @@ dpctl_dump_dps(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports,
|
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) {
|
if (dpctl_p->verbosity && f->ufid_present) {
|
||||||
odp_format_ufid(&f->ufid, ds);
|
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, ", ");
|
ds_put_cstr(ds, ", ");
|
||||||
|
|
||||||
dpif_flow_stats_format(&f->stats, 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");
|
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:");
|
ds_put_cstr(ds, ", actions:");
|
||||||
format_odp_actions(ds, f->actions, f->actions_len, ports);
|
format_odp_actions(ds, f->actions, f->actions_len, ports);
|
||||||
}
|
}
|
||||||
@@ -794,6 +797,15 @@ static char *supported_dump_types[] = {
|
|||||||
"ovs",
|
"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 *
|
static struct hmap *
|
||||||
dpctl_get_portno_names(struct dpif *dpif, const struct dpctl_params *dpctl_p)
|
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;
|
pmd_id = f.pmd_id;
|
||||||
}
|
}
|
||||||
format_dpif_flow(&ds, &f, portno_names, type, dpctl_p);
|
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));
|
dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dpif_flow_dump_thread_destroy(flow_dump_thread);
|
dpif_flow_dump_thread_destroy(flow_dump_thread);
|
||||||
error = dpif_flow_dump_destroy(flow_dump);
|
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);
|
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));
|
dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
|
||||||
ds_destroy(&ds);
|
ds_destroy(&ds);
|
||||||
|
|
||||||
|
@@ -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'.
|
datapath flow containing '\fBtcp(src=80/0xff00,dst=8080/0xff)\fR'.
|
||||||
.IP
|
.IP
|
||||||
If \fBtype=\fItype\fR is specified, only displays flows of a specific type.
|
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
|
\fItype\fR can be \fBoffloaded\fR to display only rules offloaded to the HW
|
||||||
to display only non-offloaded rules.
|
or \fBovs\fR to display only rules from the OVS tables.
|
||||||
By default both offloaded and non-offloaded rules are displayed.
|
By default all rules are displayed.
|
||||||
.
|
.
|
||||||
.IP "\*(DX\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
|
.IP "\*(DX\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
|
||||||
.TP
|
.TP
|
||||||
|
@@ -1463,13 +1463,13 @@ dpif_netlink_init_flow_del(struct dpif_netlink *dpif,
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DUMP_OVS_FLOWS_BIT = 0,
|
DUMP_OVS_FLOWS_BIT = 0,
|
||||||
DUMP_OFFLOADED_FLOWS_BIT = 1,
|
DUMP_NETDEV_FLOWS_BIT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT),
|
DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT),
|
||||||
DUMP_OFFLOADED_FLOWS = (1 << DUMP_OFFLOADED_FLOWS_BIT),
|
DUMP_NETDEV_FLOWS = (1 << DUMP_NETDEV_FLOWS_BIT),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dpif_netlink_flow_dump {
|
struct dpif_netlink_flow_dump {
|
||||||
@@ -1495,7 +1495,7 @@ start_netdev_dump(const struct dpif *dpif_,
|
|||||||
{
|
{
|
||||||
ovs_mutex_init(&dump->netdev_lock);
|
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_num = 0;
|
||||||
dump->netdev_dumps = NULL;
|
dump->netdev_dumps = NULL;
|
||||||
return;
|
return;
|
||||||
@@ -1518,7 +1518,7 @@ dpif_netlink_get_dump_type(char *str) {
|
|||||||
}
|
}
|
||||||
if ((netdev_is_flow_api_enabled() && !str)
|
if ((netdev_is_flow_api_enabled() && !str)
|
||||||
|| (str && (!strcmp(str, "offloaded") || !strcmp(str, "dpctl")))) {
|
|| (str && (!strcmp(str, "offloaded") || !strcmp(str, "dpctl")))) {
|
||||||
type |= DUMP_OFFLOADED_FLOWS;
|
type |= DUMP_NETDEV_FLOWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
@@ -1656,7 +1656,8 @@ dpif_netlink_flow_to_dpif_flow(struct dpif *dpif, struct dpif_flow *dpif_flow,
|
|||||||
&dpif_flow->ufid);
|
&dpif_flow->ufid);
|
||||||
}
|
}
|
||||||
dpif_netlink_flow_get_stats(datapath_flow, &dpif_flow->stats);
|
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
|
/* 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 ofpbuf *mask_buf,
|
||||||
struct nlattr *actions,
|
struct nlattr *actions,
|
||||||
struct dpif_flow_stats *stats,
|
struct dpif_flow_stats *stats,
|
||||||
|
struct dpif_flow_attrs *attrs,
|
||||||
ovs_u128 *ufid,
|
ovs_u128 *ufid,
|
||||||
struct dpif_flow *flow,
|
struct dpif_flow *flow,
|
||||||
bool terse OVS_UNUSED)
|
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->pmd_id = PMD_ID_NULL;
|
||||||
|
|
||||||
flow->offloaded = true;
|
memcpy(&flow->attrs, attrs, sizeof *attrs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1772,6 +1774,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
|
|||||||
struct match match;
|
struct match match;
|
||||||
struct nlattr *actions;
|
struct nlattr *actions;
|
||||||
struct dpif_flow_stats stats;
|
struct dpif_flow_stats stats;
|
||||||
|
struct dpif_flow_attrs attrs;
|
||||||
ovs_u128 ufid;
|
ovs_u128 ufid;
|
||||||
bool has_next;
|
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(&act, actbuf, sizeof *actbuf);
|
||||||
ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf);
|
ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf);
|
||||||
has_next = netdev_flow_dump_next(netdev_dump, &match,
|
has_next = netdev_flow_dump_next(netdev_dump, &match,
|
||||||
&actions, &stats,
|
&actions, &stats, &attrs,
|
||||||
&ufid,
|
&ufid,
|
||||||
&thread->nl_flows,
|
&thread->nl_flows,
|
||||||
&act);
|
&act);
|
||||||
@@ -1788,6 +1791,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_,
|
|||||||
&key, &mask,
|
&key, &mask,
|
||||||
actions,
|
actions,
|
||||||
&stats,
|
&stats,
|
||||||
|
&attrs,
|
||||||
&ufid,
|
&ufid,
|
||||||
f,
|
f,
|
||||||
dump->up.terse);
|
dump->up.terse);
|
||||||
@@ -2055,6 +2059,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get)
|
|||||||
struct match match;
|
struct match match;
|
||||||
struct nlattr *actions;
|
struct nlattr *actions;
|
||||||
struct dpif_flow_stats stats;
|
struct dpif_flow_stats stats;
|
||||||
|
struct dpif_flow_attrs attrs;
|
||||||
struct ofpbuf buf;
|
struct ofpbuf buf;
|
||||||
uint64_t act_buf[1024 / 8];
|
uint64_t act_buf[1024 / 8];
|
||||||
struct odputil_keybuf maskbuf;
|
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);
|
ofpbuf_use_stack(&buf, &act_buf, sizeof act_buf);
|
||||||
err = netdev_ports_flow_get(dpif->dpif.dpif_class, &match,
|
err = netdev_ports_flow_get(dpif->dpif.dpif_class, &match,
|
||||||
&actions, get->ufid, &stats, &buf);
|
&actions, get->ufid, &stats, &attrs, &buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
return 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(&act, &actbuf, sizeof actbuf);
|
||||||
ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
|
ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
|
||||||
dpif_netlink_netdev_match_to_dpif_flow(&match, &key, &mask, actions,
|
dpif_netlink_netdev_match_to_dpif_flow(&match, &key, &mask, actions,
|
||||||
&stats,
|
&stats, &attrs,
|
||||||
(ovs_u128 *) get->ufid,
|
(ovs_u128 *) get->ufid,
|
||||||
dpif_flow,
|
dpif_flow,
|
||||||
false);
|
false);
|
||||||
|
@@ -507,6 +507,11 @@ struct dpif_flow_stats {
|
|||||||
uint16_t tcp_flags;
|
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,
|
void dpif_flow_stats_extract(const struct flow *, const struct dp_packet *packet,
|
||||||
long long int used, struct dpif_flow_stats *);
|
long long int used, struct dpif_flow_stats *);
|
||||||
void dpif_flow_stats_format(const struct dpif_flow_stats *, struct ds *);
|
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.*/
|
bool ufid_present; /* True if 'ufid' was provided by datapath.*/
|
||||||
unsigned pmd_id; /* Datapath poll mode driver id. */
|
unsigned pmd_id; /* Datapath poll mode driver id. */
|
||||||
struct dpif_flow_stats stats; /* Flow statistics. */
|
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 *,
|
int dpif_flow_dump_next(struct dpif_flow_dump_thread *,
|
||||||
struct dpif_flow *flows, int max_flows);
|
struct dpif_flow *flows, int max_flows);
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
struct dpif_flow_stats;
|
struct dpif_flow_stats;
|
||||||
|
struct dpif_flow_attrs;
|
||||||
struct ds;
|
struct ds;
|
||||||
struct flow_wildcards;
|
struct flow_wildcards;
|
||||||
struct minimask;
|
struct minimask;
|
||||||
|
@@ -837,7 +837,8 @@ struct netdev_class {
|
|||||||
* to be pre allocated by the caller. */
|
* to be pre allocated by the caller. */
|
||||||
bool (*flow_dump_next)(struct netdev_flow_dump *, struct match *,
|
bool (*flow_dump_next)(struct netdev_flow_dump *, struct match *,
|
||||||
struct nlattr **actions,
|
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);
|
struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
|
||||||
|
|
||||||
/* Offload the given flow on netdev.
|
/* Offload the given flow on netdev.
|
||||||
@@ -857,7 +858,7 @@ struct netdev_class {
|
|||||||
* Return 0 if successful, otherwise returns a positive errno value. */
|
* Return 0 if successful, otherwise returns a positive errno value. */
|
||||||
int (*flow_get)(struct netdev *, struct match *, struct nlattr **actions,
|
int (*flow_get)(struct netdev *, struct match *, struct nlattr **actions,
|
||||||
const ovs_u128 *ufid, struct dpif_flow_stats *,
|
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.
|
/* Delete a flow specified by ufid from netdev.
|
||||||
* 'stats' is populated according to the rules set out in the description
|
* 'stats' is populated according to the rules set out in the description
|
||||||
|
@@ -398,6 +398,7 @@ parse_tc_flower_to_match(struct tc_flower *flower,
|
|||||||
struct match *match,
|
struct match *match,
|
||||||
struct nlattr **actions,
|
struct nlattr **actions,
|
||||||
struct dpif_flow_stats *stats,
|
struct dpif_flow_stats *stats,
|
||||||
|
struct dpif_flow_attrs *attrs,
|
||||||
struct ofpbuf *buf)
|
struct ofpbuf *buf)
|
||||||
{
|
{
|
||||||
size_t act_off;
|
size_t act_off;
|
||||||
@@ -565,6 +566,10 @@ parse_tc_flower_to_match(struct tc_flower *flower,
|
|||||||
stats->used = flower->lastused;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,6 +578,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
|
|||||||
struct match *match,
|
struct match *match,
|
||||||
struct nlattr **actions,
|
struct nlattr **actions,
|
||||||
struct dpif_flow_stats *stats,
|
struct dpif_flow_stats *stats,
|
||||||
|
struct dpif_flow_attrs *attrs,
|
||||||
ovs_u128 *ufid,
|
ovs_u128 *ufid,
|
||||||
struct ofpbuf *rbuffer,
|
struct ofpbuf *rbuffer,
|
||||||
struct ofpbuf *wbuffer)
|
struct ofpbuf *wbuffer)
|
||||||
@@ -587,7 +593,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_tc_flower_to_match(&flower, match, actions, stats,
|
if (parse_tc_flower_to_match(&flower, match, actions, stats, attrs,
|
||||||
wbuffer)) {
|
wbuffer)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1119,6 +1125,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
|
|||||||
struct nlattr **actions,
|
struct nlattr **actions,
|
||||||
const ovs_u128 *ufid,
|
const ovs_u128 *ufid,
|
||||||
struct dpif_flow_stats *stats,
|
struct dpif_flow_stats *stats,
|
||||||
|
struct dpif_flow_attrs *attrs,
|
||||||
struct ofpbuf *buf)
|
struct ofpbuf *buf)
|
||||||
{
|
{
|
||||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
|
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);
|
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->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
|
||||||
match->flow.in_port.odp_port = in_port;
|
match->flow.in_port.odp_port = in_port;
|
||||||
|
@@ -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 *,
|
bool netdev_tc_flow_dump_next(struct netdev_flow_dump *, struct match *,
|
||||||
struct nlattr **actions,
|
struct nlattr **actions,
|
||||||
struct dpif_flow_stats *,
|
struct dpif_flow_stats *,
|
||||||
|
struct dpif_flow_attrs *,
|
||||||
ovs_u128 *ufid,
|
ovs_u128 *ufid,
|
||||||
struct ofpbuf *rbuffer,
|
struct ofpbuf *rbuffer,
|
||||||
struct ofpbuf *wbuffer);
|
struct ofpbuf *wbuffer);
|
||||||
@@ -34,7 +35,8 @@ int netdev_tc_flow_put(struct netdev *, struct match *,
|
|||||||
struct dpif_flow_stats *);
|
struct dpif_flow_stats *);
|
||||||
int netdev_tc_flow_get(struct netdev *, struct match *,
|
int netdev_tc_flow_get(struct netdev *, struct match *,
|
||||||
struct nlattr **actions, const ovs_u128 *,
|
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 *,
|
int netdev_tc_flow_del(struct netdev *, const ovs_u128 *,
|
||||||
struct dpif_flow_stats *);
|
struct dpif_flow_stats *);
|
||||||
int netdev_tc_init_flow_api(struct netdev *);
|
int netdev_tc_init_flow_api(struct netdev *);
|
||||||
|
18
lib/netdev.c
18
lib/netdev.c
@@ -2162,14 +2162,14 @@ netdev_flow_dump_destroy(struct netdev_flow_dump *dump)
|
|||||||
bool
|
bool
|
||||||
netdev_flow_dump_next(struct netdev_flow_dump *dump, struct match *match,
|
netdev_flow_dump_next(struct netdev_flow_dump *dump, struct match *match,
|
||||||
struct nlattr **actions, struct dpif_flow_stats *stats,
|
struct nlattr **actions, struct dpif_flow_stats *stats,
|
||||||
ovs_u128 *ufid, struct ofpbuf *rbuffer,
|
struct dpif_flow_attrs *attrs, ovs_u128 *ufid,
|
||||||
struct ofpbuf *wbuffer)
|
struct ofpbuf *rbuffer, struct ofpbuf *wbuffer)
|
||||||
{
|
{
|
||||||
const struct netdev_class *class = dump->netdev->netdev_class;
|
const struct netdev_class *class = dump->netdev->netdev_class;
|
||||||
|
|
||||||
return (class->flow_dump_next
|
return (class->flow_dump_next
|
||||||
? class->flow_dump_next(dump, match, actions, stats, ufid,
|
? class->flow_dump_next(dump, match, actions, stats, attrs,
|
||||||
rbuffer, wbuffer)
|
ufid, rbuffer, wbuffer)
|
||||||
: false);
|
: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2190,12 +2190,13 @@ netdev_flow_put(struct netdev *netdev, struct match *match,
|
|||||||
int
|
int
|
||||||
netdev_flow_get(struct netdev *netdev, struct match *match,
|
netdev_flow_get(struct netdev *netdev, struct match *match,
|
||||||
struct nlattr **actions, const ovs_u128 *ufid,
|
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;
|
const struct netdev_class *class = netdev->netdev_class;
|
||||||
|
|
||||||
return (class->flow_get
|
return (class->flow_get
|
||||||
? class->flow_get(netdev, match, actions, ufid, stats, buf)
|
? class->flow_get(netdev, match, actions, ufid, stats, attrs, buf)
|
||||||
: EOPNOTSUPP);
|
: EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2430,7 +2431,8 @@ netdev_ports_flow_del(const struct dpif_class *dpif_class,
|
|||||||
int
|
int
|
||||||
netdev_ports_flow_get(const struct dpif_class *dpif_class, struct match *match,
|
netdev_ports_flow_get(const struct dpif_class *dpif_class, struct match *match,
|
||||||
struct nlattr **actions, const ovs_u128 *ufid,
|
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;
|
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) {
|
HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
|
||||||
if (data->dpif_class == dpif_class
|
if (data->dpif_class == dpif_class
|
||||||
&& !netdev_flow_get(data->netdev, match, actions,
|
&& !netdev_flow_get(data->netdev, match, actions,
|
||||||
ufid, stats, buf)) {
|
ufid, stats, attrs, buf)) {
|
||||||
ovs_mutex_unlock(&netdev_hmap_mutex);
|
ovs_mutex_unlock(&netdev_hmap_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -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 *);
|
int netdev_flow_dump_destroy(struct netdev_flow_dump *);
|
||||||
bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *,
|
bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *,
|
||||||
struct nlattr **actions, struct dpif_flow_stats *,
|
struct nlattr **actions, struct dpif_flow_stats *,
|
||||||
ovs_u128 *ufid, struct ofpbuf *rbuffer,
|
struct dpif_flow_attrs *, ovs_u128 *ufid,
|
||||||
struct ofpbuf *wbuffer);
|
struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
|
||||||
int netdev_flow_put(struct netdev *, struct match *, struct nlattr *actions,
|
int netdev_flow_put(struct netdev *, struct match *, struct nlattr *actions,
|
||||||
size_t actions_len, const ovs_u128 *,
|
size_t actions_len, const ovs_u128 *,
|
||||||
struct offload_info *, struct dpif_flow_stats *);
|
struct offload_info *, struct dpif_flow_stats *);
|
||||||
int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions,
|
int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions,
|
||||||
const ovs_u128 *, struct dpif_flow_stats *,
|
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 *,
|
int netdev_flow_del(struct netdev *, const ovs_u128 *,
|
||||||
struct dpif_flow_stats *);
|
struct dpif_flow_stats *);
|
||||||
int netdev_init_flow_api(struct netdev *);
|
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,
|
struct nlattr **actions,
|
||||||
const ovs_u128 *ufid,
|
const ovs_u128 *ufid,
|
||||||
struct dpif_flow_stats *stats,
|
struct dpif_flow_stats *stats,
|
||||||
|
struct dpif_flow_attrs *attrs,
|
||||||
struct ofpbuf *buf);
|
struct ofpbuf *buf);
|
||||||
|
|
||||||
/* native tunnel APIs */
|
/* native tunnel APIs */
|
||||||
|
23
lib/tc.c
23
lib/tc.c
@@ -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[] = {
|
static const struct nl_policy pedit_policy[] = {
|
||||||
[TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,
|
[TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,
|
||||||
.min_len = sizeof(struct tc_pedit),
|
.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_vlan(attrs, flower);
|
||||||
nl_parse_flower_ip(attrs, flower);
|
nl_parse_flower_ip(attrs, flower);
|
||||||
nl_parse_flower_tunnel(attrs, flower);
|
nl_parse_flower_tunnel(attrs, flower);
|
||||||
|
nl_parse_flower_flags(attrs, flower);
|
||||||
return nl_parse_flower_actions(attrs, flower);
|
return nl_parse_flower_actions(attrs, flower);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
lib/tc.h
8
lib/tc.h
@@ -141,6 +141,12 @@ struct tc_action {
|
|||||||
enum tc_action_type type;
|
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 {
|
struct tc_flower {
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
uint32_t prio;
|
uint32_t prio;
|
||||||
@@ -180,6 +186,8 @@ struct tc_flower {
|
|||||||
struct tc_cookie act_cookie;
|
struct tc_cookie act_cookie;
|
||||||
|
|
||||||
bool needs_full_ip_proto_mask;
|
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
|
/* assert that if we overflow with a masked write of uint32_t to the last byte
|
||||||
|
Reference in New Issue
Block a user