net: sched: expose HW stats types per action used by drivers
authorJiri Pirko <jiri@mellanox.com>
Sat, 28 Mar 2020 15:37:43 +0000 (16:37 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 30 Mar 2020 18:06:49 +0000 (11:06 -0700)
It may be up to the driver (in case ANY HW stats is passed) to select
which type of HW stats he is going to use. Add an infrastructure to
expose this information to user.

$ tc filter add dev enp3s0np1 ingress proto ip handle 1 pref 1 flower dst_ip 192.168.1.1 action drop
$ tc -s filter show dev enp3s0np1 ingress
filter protocol ip pref 1 flower chain 0
filter protocol ip pref 1 flower chain 0 handle 0x1
  eth_type ipv4
  dst_ip 192.168.1.1
  in_hw in_hw_count 2
        action order 1: gact action drop
         random type none pass val 0
         index 1 ref 1 bind 1 installed 10 sec used 10 sec
        Action statistics:
        Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
        backlog 0b 0p requeues 0
        used_hw_stats immediate     <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
18 files changed:
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
include/net/act_api.h
include/net/flow_offload.h
include/net/pkt_cls.h
include/uapi/linux/pkt_cls.h
net/sched/act_api.c
net/sched/cls_flower.c
net/sched/cls_matchall.c

index b19be7549aad2e1da9b475c2e42703466a130a2f..782ea0771221fc49238938fa19681614dc0eaceb 100644 (file)
@@ -1639,7 +1639,7 @@ static int bnxt_tc_get_flow_stats(struct bnxt *bp,
        spin_unlock(&flow->stats_lock);
 
        flow_stats_update(&tc_flow_cmd->stats, stats.bytes, stats.packets,
-                         lastused);
+                         lastused, FLOW_ACTION_HW_STATS_DELAYED);
        return 0;
 }
 
index aec9b90313e7116d1722d05e6614ceaa6646be56..4a5fa9eba0b64cb7a26cc7ac21cd674e5e2e11d4 100644 (file)
@@ -903,7 +903,8 @@ int cxgb4_tc_flower_stats(struct net_device *dev,
                        ofld_stats->last_used = jiffies;
                flow_stats_update(&cls->stats, bytes - ofld_stats->byte_count,
                                  packets - ofld_stats->packet_count,
-                                 ofld_stats->last_used);
+                                 ofld_stats->last_used,
+                                 FLOW_ACTION_HW_STATS_IMMEDIATE);
 
                ofld_stats->packet_count = packets;
                ofld_stats->byte_count = bytes;
index 8a5ae8bc9b7d01988d16eda4651e3c117bce5886..c88c47a14fbb3f2ac15cad3a276090a2824dfd22 100644 (file)
@@ -346,7 +346,8 @@ int cxgb4_tc_matchall_stats(struct net_device *dev,
                flow_stats_update(&cls_matchall->stats,
                                  bytes - tc_port_matchall->ingress.bytes,
                                  packets - tc_port_matchall->ingress.packets,
-                                 tc_port_matchall->ingress.last_used);
+                                 tc_port_matchall->ingress.last_used,
+                                 FLOW_ACTION_HW_STATS_IMMEDIATE);
 
                tc_port_matchall->ingress.packets = packets;
                tc_port_matchall->ingress.bytes = bytes;
index f4b28eb9d943f74e012c4becf586f1e0e0c9ff1c..ad3e3a65d403c1e776e18b97e569e9e180add40b 100644 (file)
@@ -666,7 +666,8 @@ mlx5_tc_ct_block_flow_offload_stats(struct mlx5_ct_ft *ft,
                return -ENOENT;
 
        mlx5_fc_query_cached(entry->counter, &bytes, &packets, &lastuse);
-       flow_stats_update(&f->stats, bytes, packets, lastuse);
+       flow_stats_update(&f->stats, bytes, packets, lastuse,
+                         FLOW_ACTION_HW_STATS_DELAYED);
 
        return 0;
 }
index 6474e0a01a5498e60d04f07c6c29e91424829cb1..438128dde187d7ec58892c2879c6037f807f576f 100644 (file)
@@ -4468,7 +4468,8 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv,
 no_peer_counter:
        mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
 out:
-       flow_stats_update(&f->stats, bytes, packets, lastuse);
+       flow_stats_update(&f->stats, bytes, packets, lastuse,
+                         FLOW_ACTION_HW_STATS_DELAYED);
        trace_mlx5e_stats_flower(f);
 errout:
        mlx5e_flow_put(priv, flow);
@@ -4585,7 +4586,8 @@ void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv,
        dpkts = cur_stats.rx_packets - rpriv->prev_vf_vport_stats.rx_packets;
        dbytes = cur_stats.rx_bytes - rpriv->prev_vf_vport_stats.rx_bytes;
        rpriv->prev_vf_vport_stats = cur_stats;
-       flow_stats_update(&ma->stats, dpkts, dbytes, jiffies);
+       flow_stats_update(&ma->stats, dpkts, dbytes, jiffies,
+                         FLOW_ACTION_HW_STATS_DELAYED);
 }
 
 static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
index 273e373a37b61bf16f5b999c19a24a378c79477e..9f06f7a5308aac8b928908f241765e97261432f6 100644 (file)
@@ -786,7 +786,8 @@ struct mlxsw_sp_acl_rule_info *
 mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule);
 int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
                                struct mlxsw_sp_acl_rule *rule,
-                               u64 *packets, u64 *bytes, u64 *last_use);
+                               u64 *packets, u64 *bytes, u64 *last_use,
+                               enum flow_action_hw_stats *used_hw_stats);
 
 struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp);
 
index 6fc1496b9514cf2fb1a373c0602f7086c9f100f4..67ee880a87279e8be04ed492133c403c93e5d416 100644 (file)
@@ -967,7 +967,8 @@ static void mlxsw_sp_acl_rule_activity_update_work(struct work_struct *work)
 
 int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
                                struct mlxsw_sp_acl_rule *rule,
-                               u64 *packets, u64 *bytes, u64 *last_use)
+                               u64 *packets, u64 *bytes, u64 *last_use,
+                               enum flow_action_hw_stats *used_hw_stats)
 
 {
        struct mlxsw_sp_acl_rule_info *rulei;
@@ -982,6 +983,7 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
                                                &current_bytes);
                if (err)
                        return err;
+               *used_hw_stats = FLOW_ACTION_HW_STATS_IMMEDIATE;
        }
        *packets = current_packets - rule->last_packets;
        *bytes = current_bytes - rule->last_bytes;
index 33a5e2a0a1adf8898bac3d804907fdaea8132f55..2f76908cae730c4a1d5db47714107a7418f02962 100644 (file)
@@ -571,6 +571,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
                          struct mlxsw_sp_acl_block *block,
                          struct flow_cls_offload *f)
 {
+       enum flow_action_hw_stats used_hw_stats = FLOW_ACTION_HW_STATS_DISABLED;
        struct mlxsw_sp_acl_ruleset *ruleset;
        struct mlxsw_sp_acl_rule *rule;
        u64 packets;
@@ -589,11 +590,11 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp *mlxsw_sp,
                return -EINVAL;
 
        err = mlxsw_sp_acl_rule_get_stats(mlxsw_sp, rule, &packets, &bytes,
-                                         &lastuse);
+                                         &lastuse, &used_hw_stats);
        if (err)
                goto err_rule_get_stats;
 
-       flow_stats_update(&f->stats, bytes, packets, lastuse);
+       flow_stats_update(&f->stats, bytes, packets, lastuse, used_hw_stats);
 
        mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
        return 0;
index 873a9944fbfbec6b4354387fe1b068a377ddab2d..829987eb74cbd1d9249fb322844ee52541cec2c9 100644 (file)
@@ -224,7 +224,8 @@ int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
        if (ret)
                return ret;
 
-       flow_stats_update(&f->stats, 0x0, ace.stats.pkts, 0x0);
+       flow_stats_update(&f->stats, 0x0, ace.stats.pkts, 0x0,
+                         FLOW_ACTION_HW_STATS_IMMEDIATE);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
index 7ca5c1becfcfef0c6b677556bae93f612cedf9bc..c694dbc239d0129bb22c0787c9c23fca5d501f0a 100644 (file)
@@ -1490,7 +1490,8 @@ nfp_flower_get_stats(struct nfp_app *app, struct net_device *netdev,
                nfp_flower_update_merge_stats(app, nfp_flow);
 
        flow_stats_update(&flow->stats, priv->stats[ctx_id].bytes,
-                         priv->stats[ctx_id].pkts, priv->stats[ctx_id].used);
+                         priv->stats[ctx_id].pkts, priv->stats[ctx_id].used,
+                         FLOW_ACTION_HW_STATS_DELAYED);
 
        priv->stats[ctx_id].pkts = 0;
        priv->stats[ctx_id].bytes = 0;
index 124a43dc136a8a28ba1e4a971f6ded621cfaf7e6..d18a830e426490496f5e3281a9641f009131a3b4 100644 (file)
@@ -320,7 +320,8 @@ nfp_flower_stats_rate_limiter(struct nfp_app *app, struct net_device *netdev,
        spin_unlock_bh(&fl_priv->qos_stats_lock);
 
        flow_stats_update(&flow->stats, diff_bytes, diff_pkts,
-                         repr_priv->qos_table.last_update);
+                         repr_priv->qos_table.last_update,
+                         FLOW_ACTION_HW_STATS_DELAYED);
        return 0;
 }
 
index ecdec9d6ead0974586744f64c606a8e391be1430..c24d7643548ee927b4741f963a20e00925e755d9 100644 (file)
@@ -42,6 +42,8 @@ struct tc_action {
        struct tcf_chain        __rcu *goto_chain;
        u32                     tcfa_flags;
        u8                      hw_stats;
+       u8                      used_hw_stats;
+       bool                    used_hw_stats_valid;
 };
 #define tcf_index      common.tcfa_index
 #define tcf_refcnt     common.tcfa_refcnt
index ff071eaede17fc9482b1ca81aea0c028d08990f5..f66fc6a3020d838e979ef4d64da918cb817189fd 100644 (file)
@@ -370,14 +370,24 @@ struct flow_stats {
        u64     pkts;
        u64     bytes;
        u64     lastused;
+       enum flow_action_hw_stats used_hw_stats;
+       bool used_hw_stats_valid;
 };
 
 static inline void flow_stats_update(struct flow_stats *flow_stats,
-                                    u64 bytes, u64 pkts, u64 lastused)
+                                    u64 bytes, u64 pkts, u64 lastused,
+                                    enum flow_action_hw_stats used_hw_stats)
 {
        flow_stats->pkts        += pkts;
        flow_stats->bytes       += bytes;
        flow_stats->lastused    = max_t(u64, flow_stats->lastused, lastused);
+
+       /* The driver should pass value with a maximum of one bit set.
+        * Passing FLOW_ACTION_HW_STATS_ANY is invalid.
+        */
+       WARN_ON(used_hw_stats == FLOW_ACTION_HW_STATS_ANY);
+       flow_stats->used_hw_stats |= used_hw_stats;
+       flow_stats->used_hw_stats_valid = true;
 }
 
 enum flow_block_command {
index 41902e10d50343667eb268bfa60dea66bbff185d..04aa0649f3b09bb093cfee126f9cd51378006e4a 100644 (file)
@@ -262,7 +262,8 @@ static inline void tcf_exts_put_net(struct tcf_exts *exts)
 
 static inline void
 tcf_exts_stats_update(const struct tcf_exts *exts,
-                     u64 bytes, u64 packets, u64 lastuse)
+                     u64 bytes, u64 packets, u64 lastuse,
+                     u8 used_hw_stats, bool used_hw_stats_valid)
 {
 #ifdef CONFIG_NET_CLS_ACT
        int i;
@@ -273,6 +274,8 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
                struct tc_action *a = exts->actions[i];
 
                tcf_action_stats_update(a, bytes, packets, lastuse, true);
+               a->used_hw_stats = used_hw_stats;
+               a->used_hw_stats_valid = used_hw_stats_valid;
        }
 
        preempt_enable();
index 6fcf7307e5342a3f8021ef2a3b7e37b9578ec2c2..9f06d29cab705871c3b2b78a15284b429314849c 100644 (file)
@@ -18,6 +18,7 @@ enum {
        TCA_ACT_COOKIE,
        TCA_ACT_FLAGS,
        TCA_ACT_HW_STATS,
+       TCA_ACT_USED_HW_STATS,
        __TCA_ACT_MAX
 };
 
index 33cc77e6e56cdced90ca312473f186c9b7028173..df456090915769c6e782aaf5b03c75632f383550 100644 (file)
@@ -794,6 +794,11 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
                               a->hw_stats, TCA_ACT_HW_STATS_ANY))
                goto nla_put_failure;
 
+       if (a->used_hw_stats_valid &&
+           nla_put_bitfield32(skb, TCA_ACT_USED_HW_STATS,
+                              a->used_hw_stats, TCA_ACT_HW_STATS_ANY))
+               goto nla_put_failure;
+
        if (a->tcfa_flags &&
            nla_put_bitfield32(skb, TCA_ACT_FLAGS,
                               a->tcfa_flags, a->tcfa_flags))
index 9b6acd736dc8519cf76b9db9e27abf5ca7722bb5..74a0febcafb83231438251f57fe7b9e9e48fff94 100644 (file)
@@ -492,7 +492,9 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f,
 
        tcf_exts_stats_update(&f->exts, cls_flower.stats.bytes,
                              cls_flower.stats.pkts,
-                             cls_flower.stats.lastused);
+                             cls_flower.stats.lastused,
+                             cls_flower.stats.used_hw_stats,
+                             cls_flower.stats.used_hw_stats_valid);
 }
 
 static void __fl_put(struct cls_fl_filter *f)
index a34b36adb9b71b1e8b01e11abcdc8c52dc9749b5..8d39dbcf17466eafc031cd9b6f3f0c6cda596819 100644 (file)
@@ -338,7 +338,9 @@ static void mall_stats_hw_filter(struct tcf_proto *tp,
        tc_setup_cb_call(block, TC_SETUP_CLSMATCHALL, &cls_mall, false, true);
 
        tcf_exts_stats_update(&head->exts, cls_mall.stats.bytes,
-                             cls_mall.stats.pkts, cls_mall.stats.lastused);
+                             cls_mall.stats.pkts, cls_mall.stats.lastused,
+                             cls_mall.stats.used_hw_stats,
+                             cls_mall.stats.used_hw_stats_valid);
 }
 
 static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,