net: sparx5: add support for matchall mirror stats
authorDaniel Machon <daniel.machon@microchip.com>
Sat, 20 Apr 2024 19:29:14 +0000 (21:29 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 24 Apr 2024 12:08:07 +0000 (13:08 +0100)
Add support for tc matchall mirror stats. When a new matchall mirror
rule is added, the baseline stats for that port is saved.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/microchip/sparx5/sparx5_main.h
drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c
drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c

index 5d026e1..1982ae0 100644 (file)
@@ -174,6 +174,7 @@ struct sparx5_port {
        struct phylink_config phylink_config;
        struct phylink *phylink;
        struct phylink_pcs phylink_pcs;
+       struct flow_stats mirror_stats;
        u16 portno;
        /* Ingress default VLAN (pvid) */
        u16 pvid;
@@ -562,6 +563,8 @@ void sparx5_new_base_time(struct sparx5 *sparx5, const u32 cycle_time,
 /* sparx5_mirror.c */
 int sparx5_mirror_add(struct sparx5_mall_entry *entry);
 void sparx5_mirror_del(struct sparx5_mall_entry *entry);
+void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
+                        struct flow_stats *fstats);
 
 /* Clock period in picoseconds */
 static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
index f029634..15db423 100644 (file)
@@ -196,3 +196,40 @@ void sparx5_mirror_del(struct sparx5_mall_entry *entry)
                                  mirror_idx,
                                  SPX5_MIRROR_MONITOR_PORT_DEFAULT);
 }
+
+void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
+                        struct flow_stats *fstats)
+{
+       struct sparx5_port *port = entry->port;
+       struct rtnl_link_stats64 new_stats;
+       struct flow_stats *old_stats;
+
+       old_stats = &entry->port->mirror_stats;
+       sparx5_get_stats64(port->ndev, &new_stats);
+
+       if (entry->ingress) {
+               flow_stats_update(fstats,
+                                 new_stats.rx_bytes - old_stats->bytes,
+                                 new_stats.rx_packets - old_stats->pkts,
+                                 new_stats.rx_dropped - old_stats->drops,
+                                 old_stats->lastused,
+                                 FLOW_ACTION_HW_STATS_IMMEDIATE);
+
+               old_stats->bytes = new_stats.rx_bytes;
+               old_stats->pkts = new_stats.rx_packets;
+               old_stats->drops = new_stats.rx_dropped;
+               old_stats->lastused = jiffies;
+       } else {
+               flow_stats_update(fstats,
+                                 new_stats.tx_bytes - old_stats->bytes,
+                                 new_stats.tx_packets - old_stats->pkts,
+                                 new_stats.tx_dropped - old_stats->drops,
+                                 old_stats->lastused,
+                                 FLOW_ACTION_HW_STATS_IMMEDIATE);
+
+               old_stats->bytes = new_stats.tx_bytes;
+               old_stats->pkts = new_stats.tx_packets;
+               old_stats->drops = new_stats.tx_dropped;
+               old_stats->lastused = jiffies;
+       }
+}
index 4f9ae02..6b4d1d7 100644 (file)
@@ -96,6 +96,8 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev,
                        }
                        return err;
                }
+               /* Get baseline stats for this port */
+               sparx5_mirror_stats(mall_entry, &tmo->stats);
                break;
        case FLOW_ACTION_GOTO:
                err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
@@ -162,6 +164,29 @@ static int sparx5_tc_matchall_destroy(struct net_device *ndev,
        return err;
 }
 
+static int sparx5_tc_matchall_stats(struct net_device *ndev,
+                                   struct tc_cls_matchall_offload *tmo,
+                                   bool ingress)
+{
+       struct sparx5_port *port = netdev_priv(ndev);
+       struct sparx5 *sparx5 = port->sparx5;
+       struct sparx5_mall_entry *entry;
+
+       entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,
+                                             tmo->cookie);
+       if (!entry)
+               return -ENOENT;
+
+       if (entry->type == FLOW_ACTION_MIRRED) {
+               sparx5_mirror_stats(entry, &tmo->stats);
+       } else {
+               NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
 int sparx5_tc_matchall(struct net_device *ndev,
                       struct tc_cls_matchall_offload *tmo,
                       bool ingress)
@@ -171,6 +196,8 @@ int sparx5_tc_matchall(struct net_device *ndev,
                return sparx5_tc_matchall_replace(ndev, tmo, ingress);
        case TC_CLSMATCHALL_DESTROY:
                return sparx5_tc_matchall_destroy(ndev, tmo, ingress);
+       case TC_CLSMATCHALL_STATS:
+               return sparx5_tc_matchall_stats(ndev, tmo, ingress);
        default:
                return -EOPNOTSUPP;
        }