sched: act: allow user to specify type of HW stats for a filter
authorJiri Pirko <jiri@mellanox.com>
Sat, 7 Mar 2020 11:40:20 +0000 (12:40 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Mar 2020 04:07:48 +0000 (21:07 -0700)
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>
include/net/act_api.h
include/uapi/linux/pkt_cls.h
net/sched/act_api.c
net/sched/cls_api.c

index 71347a90a9d1d769fc801412b0a21c1452fd56fe..41337c7fc72814c93e069ff7342dacdfcfd5ce02 100644 (file)
@@ -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.
  */
index 449a63971451f0ff1892f2e39a5ebc10f02a9b53..81cc1a8695884d9f4534cef0af51b0cce87cd4bc 100644 (file)
@@ -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
index 8c466a712cda047001973652603c4f0e0c4e2b4d..aa7b737fed2e02404f4cdc5f93f0f14a94bd8420 100644 (file)
@@ -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).
index 4e766c5ab77a1ec1875b18b7d86303cea607a4e3..e91448640a4f790aa46ad54879cd7601f4efb3b8 100644 (file)
@@ -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)) {