sched: act: allow user to specify type of HW stats for a filter
Currently, user who is adding an action expects HW to report stats, however it does not have exact expectations about the stats types. That is aligned with TCA_ACT_HW_STATS_TYPE_ANY. Allow user to specify the type of HW stats for an action and require it. Pass the information down to flow_offload layer. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
d7cb1e3ba1
Коммит
44f8658017
|
@ -41,6 +41,7 @@ struct tc_action {
|
||||||
struct tc_cookie __rcu *act_cookie;
|
struct tc_cookie __rcu *act_cookie;
|
||||||
struct tcf_chain __rcu *goto_chain;
|
struct tcf_chain __rcu *goto_chain;
|
||||||
u32 tcfa_flags;
|
u32 tcfa_flags;
|
||||||
|
u8 hw_stats_type;
|
||||||
};
|
};
|
||||||
#define tcf_index common.tcfa_index
|
#define tcf_index common.tcfa_index
|
||||||
#define tcf_refcnt common.tcfa_refcnt
|
#define tcf_refcnt common.tcfa_refcnt
|
||||||
|
@ -52,6 +53,9 @@ struct tc_action {
|
||||||
#define tcf_rate_est common.tcfa_rate_est
|
#define tcf_rate_est common.tcfa_rate_est
|
||||||
#define tcf_lock common.tcfa_lock
|
#define tcf_lock common.tcfa_lock
|
||||||
|
|
||||||
|
#define TCA_ACT_HW_STATS_TYPE_ANY (TCA_ACT_HW_STATS_TYPE_IMMEDIATE | \
|
||||||
|
TCA_ACT_HW_STATS_TYPE_DELAYED)
|
||||||
|
|
||||||
/* Update lastuse only if needed, to avoid dirtying a cache line.
|
/* Update lastuse only if needed, to avoid dirtying a cache line.
|
||||||
* We use a temp variable to avoid fetching jiffies twice.
|
* We use a temp variable to avoid fetching jiffies twice.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,6 +17,7 @@ enum {
|
||||||
TCA_ACT_PAD,
|
TCA_ACT_PAD,
|
||||||
TCA_ACT_COOKIE,
|
TCA_ACT_COOKIE,
|
||||||
TCA_ACT_FLAGS,
|
TCA_ACT_FLAGS,
|
||||||
|
TCA_ACT_HW_STATS_TYPE,
|
||||||
__TCA_ACT_MAX
|
__TCA_ACT_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,6 +25,27 @@ enum {
|
||||||
* actions stats.
|
* actions stats.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tca HW stats type
|
||||||
|
* When user does not pass the attribute, he does not care.
|
||||||
|
* It is the same as if he would pass the attribute with
|
||||||
|
* all supported bits set.
|
||||||
|
* In case no bits are set, user is not interested in getting any HW statistics.
|
||||||
|
*/
|
||||||
|
#define TCA_ACT_HW_STATS_TYPE_IMMEDIATE (1 << 0) /* Means that in dump, user
|
||||||
|
* gets the current HW stats
|
||||||
|
* state from the device
|
||||||
|
* queried at the dump time.
|
||||||
|
*/
|
||||||
|
#define TCA_ACT_HW_STATS_TYPE_DELAYED (1 << 1) /* Means that in dump, user gets
|
||||||
|
* HW stats that might be out
|
||||||
|
* of date for some time, maybe
|
||||||
|
* couple of seconds. This is
|
||||||
|
* the case when driver polls
|
||||||
|
* stats updates periodically
|
||||||
|
* or when it gets async stats update
|
||||||
|
* from the device.
|
||||||
|
*/
|
||||||
|
|
||||||
#define TCA_ACT_MAX __TCA_ACT_MAX
|
#define TCA_ACT_MAX __TCA_ACT_MAX
|
||||||
#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
|
#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
|
||||||
#define TCA_ACT_MAX_PRIO 32
|
#define TCA_ACT_MAX_PRIO 32
|
||||||
|
|
|
@ -185,6 +185,7 @@ static size_t tcf_action_shared_attrs_size(const struct tc_action *act)
|
||||||
return nla_total_size(0) /* action number nested */
|
return nla_total_size(0) /* action number nested */
|
||||||
+ nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */
|
+ nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */
|
||||||
+ cookie_len /* TCA_ACT_COOKIE */
|
+ cookie_len /* TCA_ACT_COOKIE */
|
||||||
|
+ nla_total_size(sizeof(struct nla_bitfield32)) /* TCA_ACT_HW_STATS_TYPE */
|
||||||
+ nla_total_size(0) /* TCA_ACT_STATS nested */
|
+ nla_total_size(0) /* TCA_ACT_STATS nested */
|
||||||
+ nla_total_size(sizeof(struct nla_bitfield32)) /* TCA_ACT_FLAGS */
|
+ nla_total_size(sizeof(struct nla_bitfield32)) /* TCA_ACT_FLAGS */
|
||||||
/* TCA_STATS_BASIC */
|
/* TCA_STATS_BASIC */
|
||||||
|
@ -788,6 +789,17 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
if (a->hw_stats_type != TCA_ACT_HW_STATS_TYPE_ANY) {
|
||||||
|
struct nla_bitfield32 hw_stats_type = {
|
||||||
|
a->hw_stats_type,
|
||||||
|
TCA_ACT_HW_STATS_TYPE_ANY,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (nla_put(skb, TCA_ACT_HW_STATS_TYPE, sizeof(hw_stats_type),
|
||||||
|
&hw_stats_type))
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
|
||||||
if (a->tcfa_flags) {
|
if (a->tcfa_flags) {
|
||||||
struct nla_bitfield32 flags = { a->tcfa_flags,
|
struct nla_bitfield32 flags = { a->tcfa_flags,
|
||||||
a->tcfa_flags, };
|
a->tcfa_flags, };
|
||||||
|
@ -854,7 +866,23 @@ static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 tcf_action_hw_stats_type_get(struct nlattr *hw_stats_type_attr)
|
||||||
|
{
|
||||||
|
struct nla_bitfield32 hw_stats_type_bf;
|
||||||
|
|
||||||
|
/* If the user did not pass the attr, that means he does
|
||||||
|
* not care about the type. Return "any" in that case
|
||||||
|
* which is setting on all supported types.
|
||||||
|
*/
|
||||||
|
if (!hw_stats_type_attr)
|
||||||
|
return TCA_ACT_HW_STATS_TYPE_ANY;
|
||||||
|
hw_stats_type_bf = nla_get_bitfield32(hw_stats_type_attr);
|
||||||
|
return hw_stats_type_bf.value;
|
||||||
|
}
|
||||||
|
|
||||||
static const u32 tca_act_flags_allowed = TCA_ACT_FLAGS_NO_PERCPU_STATS;
|
static const u32 tca_act_flags_allowed = TCA_ACT_FLAGS_NO_PERCPU_STATS;
|
||||||
|
static const u32 tca_act_hw_stats_type_allowed = TCA_ACT_HW_STATS_TYPE_ANY;
|
||||||
|
|
||||||
static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
|
static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
|
||||||
[TCA_ACT_KIND] = { .type = NLA_STRING },
|
[TCA_ACT_KIND] = { .type = NLA_STRING },
|
||||||
[TCA_ACT_INDEX] = { .type = NLA_U32 },
|
[TCA_ACT_INDEX] = { .type = NLA_U32 },
|
||||||
|
@ -863,6 +891,8 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
|
||||||
[TCA_ACT_OPTIONS] = { .type = NLA_NESTED },
|
[TCA_ACT_OPTIONS] = { .type = NLA_NESTED },
|
||||||
[TCA_ACT_FLAGS] = { .type = NLA_BITFIELD32,
|
[TCA_ACT_FLAGS] = { .type = NLA_BITFIELD32,
|
||||||
.validation_data = &tca_act_flags_allowed },
|
.validation_data = &tca_act_flags_allowed },
|
||||||
|
[TCA_ACT_HW_STATS_TYPE] = { .type = NLA_BITFIELD32,
|
||||||
|
.validation_data = &tca_act_hw_stats_type_allowed },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
||||||
|
@ -871,6 +901,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
||||||
bool rtnl_held,
|
bool rtnl_held,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
|
u8 hw_stats_type = TCA_ACT_HW_STATS_TYPE_ANY;
|
||||||
struct nla_bitfield32 flags = { 0, 0 };
|
struct nla_bitfield32 flags = { 0, 0 };
|
||||||
struct tc_action *a;
|
struct tc_action *a;
|
||||||
struct tc_action_ops *a_o;
|
struct tc_action_ops *a_o;
|
||||||
|
@ -903,6 +934,8 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hw_stats_type =
|
||||||
|
tcf_action_hw_stats_type_get(tb[TCA_ACT_HW_STATS_TYPE]);
|
||||||
if (tb[TCA_ACT_FLAGS])
|
if (tb[TCA_ACT_FLAGS])
|
||||||
flags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
|
flags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -953,6 +986,9 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
||||||
if (!name && tb[TCA_ACT_COOKIE])
|
if (!name && tb[TCA_ACT_COOKIE])
|
||||||
tcf_set_action_cookie(&a->act_cookie, cookie);
|
tcf_set_action_cookie(&a->act_cookie, cookie);
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
a->hw_stats_type = hw_stats_type;
|
||||||
|
|
||||||
/* module count goes up only when brand new policy is created
|
/* module count goes up only when brand new policy is created
|
||||||
* if it exists and is only bound to in a_o->init() then
|
* if it exists and is only bound to in a_o->init() then
|
||||||
* ACT_P_CREATED is not returned (a zero is).
|
* ACT_P_CREATED is not returned (a zero is).
|
||||||
|
|
|
@ -3464,6 +3464,10 @@ int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
struct tc_action *act;
|
struct tc_action *act;
|
||||||
int i, j, k, err = 0;
|
int i, j, k, err = 0;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(TCA_ACT_HW_STATS_TYPE_ANY != FLOW_ACTION_HW_STATS_TYPE_ANY);
|
||||||
|
BUILD_BUG_ON(TCA_ACT_HW_STATS_TYPE_IMMEDIATE != FLOW_ACTION_HW_STATS_TYPE_IMMEDIATE);
|
||||||
|
BUILD_BUG_ON(TCA_ACT_HW_STATS_TYPE_DELAYED != FLOW_ACTION_HW_STATS_TYPE_DELAYED);
|
||||||
|
|
||||||
if (!exts)
|
if (!exts)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -3476,6 +3480,9 @@ int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
err = tcf_act_get_cookie(entry, act);
|
err = tcf_act_get_cookie(entry, act);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out_locked;
|
goto err_out_locked;
|
||||||
|
|
||||||
|
entry->hw_stats_type = act->hw_stats_type;
|
||||||
|
|
||||||
if (is_tcf_gact_ok(act)) {
|
if (is_tcf_gact_ok(act)) {
|
||||||
entry->id = FLOW_ACTION_ACCEPT;
|
entry->id = FLOW_ACTION_ACCEPT;
|
||||||
} else if (is_tcf_gact_shot(act)) {
|
} else if (is_tcf_gact_shot(act)) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче