net/sched: support per action hw stats
authorOz Shlomo <ozsh@nvidia.com>
Sun, 12 Feb 2023 13:25:16 +0000 (15:25 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 14 Feb 2023 10:00:01 +0000 (11:00 +0100)
There are currently two mechanisms for populating hardware stats:
1. Using flow_offload api to query the flow's statistics.
   The api assumes that the same stats values apply to all
   the flow's actions.
   This assumption breaks when action drops or jumps over following
   actions.
2. Using hw_action api to query specific action stats via a driver
   callback method. This api assures the correct action stats for
   the offloaded action, however, it does not apply to the rest of the
   actions in the flow's actions array.

Extend the flow_offload stats callback to indicate that a per action
stats update is required.
Use the existing flow_offload_action api to query the action's hw stats.
In addition, currently the tc action stats utility only updates hw actions.
Reuse the existing action stats cb infrastructure to query any action
stats.

Signed-off-by: Oz Shlomo <ozsh@nvidia.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/flow_offload.h
include/net/pkt_cls.h
net/sched/act_api.c
net/sched/cls_flower.c
net/sched/cls_matchall.c

index d177bf5f0e1a8c66d046ad6f023ea186d0c82a2a..8c05455b1e34a7ca7bc549800103f0390ea6cee7 100644 (file)
@@ -594,6 +594,7 @@ struct flow_cls_common_offload {
 struct flow_cls_offload {
        struct flow_cls_common_offload common;
        enum flow_cls_command command;
+       bool use_act_stats;
        unsigned long cookie;
        struct flow_rule *rule;
        struct flow_stats stats;
index bf50829d92556c278535c24080454c8bbf52eba6..ace437c6754b4e9d8b11ff0b9c6c85783d01939b 100644 (file)
@@ -292,9 +292,15 @@ static inline void tcf_exts_put_net(struct tcf_exts *exts)
 #define tcf_act_for_each_action(i, a, actions) \
        for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = actions[i]); i++)
 
+static inline bool tc_act_in_hw(struct tc_action *act)
+{
+       return !!act->in_hw_count;
+}
+
 static inline void
 tcf_exts_hw_stats_update(const struct tcf_exts *exts,
-                        struct flow_stats *stats)
+                        struct flow_stats *stats,
+                        bool use_act_stats)
 {
 #ifdef CONFIG_NET_CLS_ACT
        int i;
@@ -302,16 +308,18 @@ tcf_exts_hw_stats_update(const struct tcf_exts *exts,
        for (i = 0; i < exts->nr_actions; i++) {
                struct tc_action *a = exts->actions[i];
 
-               /* if stats from hw, just skip */
-               if (tcf_action_update_hw_stats(a)) {
-                       preempt_disable();
-                       tcf_action_stats_update(a, stats->bytes, stats->pkts, stats->drops,
-                                               stats->lastused, true);
-                       preempt_enable();
-
-                       a->used_hw_stats = stats->used_hw_stats;
-                       a->used_hw_stats_valid = stats->used_hw_stats_valid;
+               if (use_act_stats || tc_act_in_hw(a)) {
+                       if (!tcf_action_update_hw_stats(a))
+                               continue;
                }
+
+               preempt_disable();
+               tcf_action_stats_update(a, stats->bytes, stats->pkts, stats->drops,
+                                       stats->lastused, true);
+               preempt_enable();
+
+               a->used_hw_stats = stats->used_hw_stats;
+               a->used_hw_stats_valid = stats->used_hw_stats_valid;
        }
 #endif
 }
@@ -769,6 +777,7 @@ struct tc_cls_matchall_offload {
        enum tc_matchall_command command;
        struct flow_rule *rule;
        struct flow_stats stats;
+       bool use_act_stats;
        unsigned long cookie;
 };
 
index 917827199102c52311088c4fb7ab56ffdb021ab0..eda58b78da13f1756cc169c2f9e3c9a29728a973 100644 (file)
@@ -169,11 +169,6 @@ static bool tc_act_skip_sw(u32 flags)
        return (flags & TCA_ACT_FLAGS_SKIP_SW) ? true : false;
 }
 
-static bool tc_act_in_hw(struct tc_action *act)
-{
-       return !!act->in_hw_count;
-}
-
 /* SKIP_HW and SKIP_SW are mutually exclusive flags. */
 static bool tc_act_flags_valid(u32 flags)
 {
@@ -308,9 +303,6 @@ int tcf_action_update_hw_stats(struct tc_action *action)
        struct flow_offload_action fl_act = {};
        int err;
 
-       if (!tc_act_in_hw(action))
-               return -EOPNOTSUPP;
-
        err = offload_action_init(&fl_act, action, FLOW_ACT_STATS, NULL);
        if (err)
                return err;
index cb04739a13ce3ac0f821fb7991321092e8104675..885c95191ccfcc67fdd9a5e2c5cc29690ed32654 100644 (file)
@@ -502,7 +502,7 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f,
        tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false,
                         rtnl_held);
 
-       tcf_exts_hw_stats_update(&f->exts, &cls_flower.stats);
+       tcf_exts_hw_stats_update(&f->exts, &cls_flower.stats, cls_flower.use_act_stats);
 }
 
 static void __fl_put(struct cls_fl_filter *f)
index b3883d3d4dbd4c18829b235f6db2dcaa815405ef..fa3bbd187eb9758f8bbd6d6d7f696fcc523bff69 100644 (file)
@@ -331,7 +331,7 @@ static void mall_stats_hw_filter(struct tcf_proto *tp,
 
        tc_setup_cb_call(block, TC_SETUP_CLSMATCHALL, &cls_mall, false, true);
 
-       tcf_exts_hw_stats_update(&head->exts, &cls_mall.stats);
+       tcf_exts_hw_stats_update(&head->exts, &cls_mall.stats, cls_mall.use_act_stats);
 }
 
 static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,