Commit 44f86580 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

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: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d7cb1e3b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ struct tc_action {
	struct tc_cookie	__rcu *act_cookie;
	struct tcf_chain	__rcu *goto_chain;
	u32			tcfa_flags;
	u8			hw_stats_type;
};
#define tcf_index	common.tcfa_index
#define tcf_refcnt	common.tcfa_refcnt
@@ -52,6 +53,9 @@ struct tc_action {
#define tcf_rate_est	common.tcfa_rate_est
#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.
 * We use a temp variable to avoid fetching jiffies twice.
 */
+22 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ enum {
	TCA_ACT_PAD,
	TCA_ACT_COOKIE,
	TCA_ACT_FLAGS,
	TCA_ACT_HW_STATS_TYPE,
	__TCA_ACT_MAX
};

@@ -24,6 +25,27 @@ enum {
					 * 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_OLD_COMPAT (TCA_ACT_MAX+1)
#define TCA_ACT_MAX_PRIO 32
+36 −0
Original line number Diff line number Diff line
@@ -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 */
		+ nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */
		+ 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(sizeof(struct nla_bitfield32)) /* TCA_ACT_FLAGS */
		/* 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();

	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) {
		struct nla_bitfield32 flags = { a->tcfa_flags,
						a->tcfa_flags, };
@@ -854,7 +866,23 @@ static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
	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_hw_stats_type_allowed = TCA_ACT_HW_STATS_TYPE_ANY;

static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
	[TCA_ACT_KIND]		= { .type = NLA_STRING },
	[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_FLAGS]		= { .type = NLA_BITFIELD32,
				    .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,
@@ -871,6 +901,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
				    bool rtnl_held,
				    struct netlink_ext_ack *extack)
{
	u8 hw_stats_type = TCA_ACT_HW_STATS_TYPE_ANY;
	struct nla_bitfield32 flags = { 0, 0 };
	struct tc_action *a;
	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;
			}
		}
		hw_stats_type =
			tcf_action_hw_stats_type_get(tb[TCA_ACT_HW_STATS_TYPE]);
		if (tb[TCA_ACT_FLAGS])
			flags = nla_get_bitfield32(tb[TCA_ACT_FLAGS]);
	} 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])
		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
	 * if it exists and is only bound to in a_o->init() then
	 * ACT_P_CREATED is not returned (a zero is).
+7 −0
Original line number Diff line number Diff line
@@ -3464,6 +3464,10 @@ int tc_setup_flow_action(struct flow_action *flow_action,
	struct tc_action *act;
	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)
		return 0;

@@ -3476,6 +3480,9 @@ int tc_setup_flow_action(struct flow_action *flow_action,
		err = tcf_act_get_cookie(entry, act);
		if (err)
			goto err_out_locked;

		entry->hw_stats_type = act->hw_stats_type;

		if (is_tcf_gact_ok(act)) {
			entry->id = FLOW_ACTION_ACCEPT;
		} else if (is_tcf_gact_shot(act)) {