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:
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
|
||||
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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "util.h"
|
||||
|
||||
struct dpif_flow_stats;
|
||||
struct dpif_flow_attrs;
|
||||
struct ds;
|
||||
struct flow_wildcards;
|
||||
struct minimask;
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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 *);
|
||||
|
18
lib/netdev.c
18
lib/netdev.c
@@ -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;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
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[] = {
|
||||
[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);
|
||||
}
|
||||
|
||||
|
8
lib/tc.h
8
lib/tc.h
@@ -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
|
||||
|
Reference in New Issue
Block a user