Skip to content

Commit 9dd15d5

Browse files
committedApr 24, 2024
Merge branch 'sparx5-port-mirroring'
Daniel Machon says: ==================== net: sparx5: add support for port mirroring This series adds support for port mirroring, and port mirroring stats, through tc matchall action FLOW_ACTION_MIRRED. The hardware has three independent mirroring probes. Each probe can be configured with a separate set of filtering conditions that must be fulfilled before traffic is mirrored. A mirror probe can have up to 64 source ports and a single monitor port. The direction of a mirror probe determines if rx or tx traffic is mirrored from the source port to the monitor port. To: David S. Miller <[email protected]> To: Eric Dumazet <[email protected]> To: Jakub Kicinski <[email protected]> To: Paolo Abeni <[email protected]> To: Lars Povlsen <[email protected]> To: Steen Hegelund <[email protected]> To: [email protected] To: Russell King <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: Horatiu Vultur <[email protected]> Cc: Russell King (Oracle) <[email protected]> Cc: Uwe Kleine-König <[email protected]> Cc: Vladimir Oltean <[email protected]> Cc: Yue Haibing <[email protected]> --- Changes in v3: - Ditch do_div() (patch #3) to fix warning on hexagon arch, reported by intel bot - Link to v2: https://lore.kernel.org/r/[email protected] Changes in v2: - Fix clang build warning about uninitialized variable 'err' - Link to v1: https://lore.kernel.org/r/[email protected] ==================== Signed-off-by: Daniel Machon <[email protected]> Signed-off-by: David S. Miller <[email protected]>
2 parents a2d2cad + 5af946f commit 9dd15d5

File tree

6 files changed

+449
-10
lines changed

6 files changed

+449
-10
lines changed
 

‎drivers/net/ethernet/microchip/sparx5/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \
1010
sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \
1111
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
1212
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o \
13-
sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o sparx5_psfp.o
13+
sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o \
14+
sparx5_psfp.o sparx5_mirror.o
1415

1516
sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o
1617
sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o

‎drivers/net/ethernet/microchip/sparx5/sparx5_main.c

+3
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,9 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
899899
dev_err(sparx5->dev, "PTP failed\n");
900900
goto cleanup_ports;
901901
}
902+
903+
INIT_LIST_HEAD(&sparx5->mall_entries);
904+
902905
goto cleanup_config;
903906

904907
cleanup_ports:

‎drivers/net/ethernet/microchip/sparx5/sparx5_main.h

+25
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/ptp_clock_kernel.h>
1919
#include <linux/hrtimer.h>
2020
#include <linux/debugfs.h>
21+
#include <net/flow_offload.h>
2122

2223
#include "sparx5_main_regs.h"
2324

@@ -173,6 +174,7 @@ struct sparx5_port {
173174
struct phylink_config phylink_config;
174175
struct phylink *phylink;
175176
struct phylink_pcs phylink_pcs;
177+
struct flow_stats mirror_stats;
176178
u16 portno;
177179
/* Ingress default VLAN (pvid) */
178180
u16 pvid;
@@ -227,6 +229,22 @@ struct sparx5_mdb_entry {
227229
u16 pgid_idx;
228230
};
229231

232+
struct sparx5_mall_mirror_entry {
233+
u32 idx;
234+
struct sparx5_port *port;
235+
};
236+
237+
struct sparx5_mall_entry {
238+
struct list_head list;
239+
struct sparx5_port *port;
240+
unsigned long cookie;
241+
enum flow_action_id type;
242+
bool ingress;
243+
union {
244+
struct sparx5_mall_mirror_entry mirror;
245+
};
246+
};
247+
230248
#define SPARX5_PTP_TIMEOUT msecs_to_jiffies(10)
231249
#define SPARX5_SKB_CB(skb) \
232250
((struct sparx5_skb_cb *)((skb)->cb))
@@ -295,6 +313,7 @@ struct sparx5 {
295313
struct vcap_control *vcap_ctrl;
296314
/* PGID allocation map */
297315
u8 pgid_map[PGID_TABLE_SIZE];
316+
struct list_head mall_entries;
298317
/* Common root for debugfs */
299318
struct dentry *debugfs_root;
300319
};
@@ -541,6 +560,12 @@ void sparx5_psfp_init(struct sparx5 *sparx5);
541560
void sparx5_new_base_time(struct sparx5 *sparx5, const u32 cycle_time,
542561
const ktime_t org_base_time, ktime_t *new_base_time);
543562

563+
/* sparx5_mirror.c */
564+
int sparx5_mirror_add(struct sparx5_mall_entry *entry);
565+
void sparx5_mirror_del(struct sparx5_mall_entry *entry);
566+
void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
567+
struct flow_stats *fstats);
568+
544569
/* Clock period in picoseconds */
545570
static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
546571
{

‎drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h

+68
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,64 @@ enum sparx5_target {
8383
#define ANA_AC_OWN_UPSID_OWN_UPSID_GET(x)\
8484
FIELD_GET(ANA_AC_OWN_UPSID_OWN_UPSID, x)
8585

86+
/* ANA_AC:MIRROR_PROBE:PROBE_CFG */
87+
#define ANA_AC_PROBE_CFG(g) \
88+
__REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 0, 0, 1, 4)
89+
90+
#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD GENMASK(31, 27)
91+
#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD_SET(x)\
92+
FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD, x)
93+
#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD_GET(x)\
94+
FIELD_GET(ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD, x)
95+
96+
#define ANA_AC_PROBE_CFG_PROBE_CPU_SET GENMASK(26, 19)
97+
#define ANA_AC_PROBE_CFG_PROBE_CPU_SET_SET(x)\
98+
FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_CPU_SET, x)
99+
#define ANA_AC_PROBE_CFG_PROBE_CPU_SET_GET(x)\
100+
FIELD_GET(ANA_AC_PROBE_CFG_PROBE_CPU_SET, x)
101+
102+
#define ANA_AC_PROBE_CFG_PROBE_VID GENMASK(18, 6)
103+
#define ANA_AC_PROBE_CFG_PROBE_VID_SET(x)\
104+
FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_VID, x)
105+
#define ANA_AC_PROBE_CFG_PROBE_VID_GET(x)\
106+
FIELD_GET(ANA_AC_PROBE_CFG_PROBE_VID, x)
107+
108+
#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE GENMASK(5, 4)
109+
#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE_SET(x)\
110+
FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_VLAN_MODE, x)
111+
#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE_GET(x)\
112+
FIELD_GET(ANA_AC_PROBE_CFG_PROBE_VLAN_MODE, x)
113+
114+
#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE GENMASK(3, 2)
115+
#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE_SET(x)\
116+
FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_MAC_MODE, x)
117+
#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE_GET(x)\
118+
FIELD_GET(ANA_AC_PROBE_CFG_PROBE_MAC_MODE, x)
119+
120+
#define ANA_AC_PROBE_CFG_PROBE_DIRECTION GENMASK(1, 0)
121+
#define ANA_AC_PROBE_CFG_PROBE_DIRECTION_SET(x)\
122+
FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_DIRECTION, x)
123+
#define ANA_AC_PROBE_CFG_PROBE_DIRECTION_GET(x)\
124+
FIELD_GET(ANA_AC_PROBE_CFG_PROBE_DIRECTION, x)
125+
126+
/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG */
127+
#define ANA_AC_PROBE_PORT_CFG(g) \
128+
__REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 8, 0, 1, 4)
129+
130+
/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG1 */
131+
#define ANA_AC_PROBE_PORT_CFG1(g) \
132+
__REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 12, 0, 1, 4)
133+
134+
/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG2 */
135+
#define ANA_AC_PROBE_PORT_CFG2(g) \
136+
__REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 16, 0, 1, 4)
137+
138+
#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2 BIT(0)
139+
#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2_SET(x)\
140+
FIELD_PREP(ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2, x)
141+
#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2_GET(x)\
142+
FIELD_GET(ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2, x)
143+
86144
/* ANA_AC:SRC:SRC_CFG */
87145
#define ANA_AC_SRC_CFG(g) __REG(TARGET_ANA_AC,\
88146
0, 1, 849920, g, 102, 16, 0, 0, 1, 4)
@@ -6203,6 +6261,16 @@ enum sparx5_target {
62036261
#define QFWD_SWITCH_PORT_MODE_LEARNALL_MORE_GET(x)\
62046262
FIELD_GET(QFWD_SWITCH_PORT_MODE_LEARNALL_MORE, x)
62056263

6264+
/* QFWD:SYSTEM:FRAME_COPY_CFG */
6265+
#define QFWD_FRAME_COPY_CFG(r)\
6266+
__REG(TARGET_QFWD, 0, 1, 0, 0, 1, 340, 284, r, 12, 4)
6267+
6268+
#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL GENMASK(12, 6)
6269+
#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_SET(x)\
6270+
FIELD_PREP(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x)
6271+
#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_GET(x)\
6272+
FIELD_GET(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x)
6273+
62066274
/* QRES:RES_CTRL:RES_CFG */
62076275
#define QRES_RES_CFG(g) __REG(TARGET_QRES,\
62086276
0, 1, 0, g, 5120, 16, 0, 0, 1, 4)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/* Microchip Sparx5 Switch driver
3+
*
4+
* Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
5+
*/
6+
7+
#include "sparx5_main.h"
8+
#include "sparx5_main_regs.h"
9+
#include "sparx5_tc.h"
10+
11+
#define SPX5_MIRROR_PROBE_MAX 3
12+
#define SPX5_MIRROR_DISABLED 0
13+
#define SPX5_MIRROR_EGRESS 1
14+
#define SPX5_MIRROR_INGRESS 2
15+
#define SPX5_MIRROR_MONITOR_PORT_DEFAULT 65
16+
#define SPX5_QFWD_MP_OFFSET 9 /* Mirror port offset in the QFWD register */
17+
18+
/* Convert from bool ingress/egress to mirror direction */
19+
static u32 sparx5_mirror_to_dir(bool ingress)
20+
{
21+
return ingress ? SPX5_MIRROR_INGRESS : SPX5_MIRROR_EGRESS;
22+
}
23+
24+
/* Get ports belonging to this mirror */
25+
static u64 sparx5_mirror_port_get(struct sparx5 *sparx5, u32 idx)
26+
{
27+
return (u64)spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG1(idx)) << 32 |
28+
spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG(idx));
29+
}
30+
31+
/* Add port to mirror (only front ports) */
32+
static void sparx5_mirror_port_add(struct sparx5 *sparx5, u32 idx, u32 portno)
33+
{
34+
u32 val, reg = portno;
35+
36+
reg = portno / BITS_PER_BYTE;
37+
val = BIT(portno % BITS_PER_BYTE);
38+
39+
if (reg == 0)
40+
return spx5_rmw(val, val, sparx5, ANA_AC_PROBE_PORT_CFG(idx));
41+
else
42+
return spx5_rmw(val, val, sparx5, ANA_AC_PROBE_PORT_CFG1(idx));
43+
}
44+
45+
/* Delete port from mirror (only front ports) */
46+
static void sparx5_mirror_port_del(struct sparx5 *sparx5, u32 idx, u32 portno)
47+
{
48+
u32 val, reg = portno;
49+
50+
reg = portno / BITS_PER_BYTE;
51+
val = BIT(portno % BITS_PER_BYTE);
52+
53+
if (reg == 0)
54+
return spx5_rmw(0, val, sparx5, ANA_AC_PROBE_PORT_CFG(idx));
55+
else
56+
return spx5_rmw(0, val, sparx5, ANA_AC_PROBE_PORT_CFG1(idx));
57+
}
58+
59+
/* Check if mirror contains port */
60+
static bool sparx5_mirror_contains(struct sparx5 *sparx5, u32 idx, u32 portno)
61+
{
62+
return (sparx5_mirror_port_get(sparx5, idx) & BIT_ULL(portno)) != 0;
63+
}
64+
65+
/* Check if mirror is empty */
66+
static bool sparx5_mirror_is_empty(struct sparx5 *sparx5, u32 idx)
67+
{
68+
return sparx5_mirror_port_get(sparx5, idx) == 0;
69+
}
70+
71+
/* Get direction of mirror */
72+
static u32 sparx5_mirror_dir_get(struct sparx5 *sparx5, u32 idx)
73+
{
74+
u32 val = spx5_rd(sparx5, ANA_AC_PROBE_CFG(idx));
75+
76+
return ANA_AC_PROBE_CFG_PROBE_DIRECTION_GET(val);
77+
}
78+
79+
/* Set direction of mirror */
80+
static void sparx5_mirror_dir_set(struct sparx5 *sparx5, u32 idx, u32 dir)
81+
{
82+
spx5_rmw(ANA_AC_PROBE_CFG_PROBE_DIRECTION_SET(dir),
83+
ANA_AC_PROBE_CFG_PROBE_DIRECTION, sparx5,
84+
ANA_AC_PROBE_CFG(idx));
85+
}
86+
87+
/* Set the monitor port for this mirror */
88+
static void sparx5_mirror_monitor_set(struct sparx5 *sparx5, u32 idx,
89+
u32 portno)
90+
{
91+
spx5_rmw(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_SET(portno),
92+
QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, sparx5,
93+
QFWD_FRAME_COPY_CFG(idx + SPX5_QFWD_MP_OFFSET));
94+
}
95+
96+
/* Get the monitor port of this mirror */
97+
static u32 sparx5_mirror_monitor_get(struct sparx5 *sparx5, u32 idx)
98+
{
99+
u32 val = spx5_rd(sparx5,
100+
QFWD_FRAME_COPY_CFG(idx + SPX5_QFWD_MP_OFFSET));
101+
102+
return QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_GET(val);
103+
}
104+
105+
/* Check if port is the monitor port of this mirror */
106+
static bool sparx5_mirror_has_monitor(struct sparx5 *sparx5, u32 idx,
107+
u32 portno)
108+
{
109+
return sparx5_mirror_monitor_get(sparx5, idx) == portno;
110+
}
111+
112+
/* Get a suitable mirror for this port */
113+
static int sparx5_mirror_get(struct sparx5_port *sport,
114+
struct sparx5_port *mport, u32 dir, u32 *idx)
115+
{
116+
struct sparx5 *sparx5 = sport->sparx5;
117+
u32 i;
118+
119+
/* Check if this port is already used as a monitor port */
120+
for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++)
121+
if (sparx5_mirror_has_monitor(sparx5, i, sport->portno))
122+
return -EINVAL;
123+
124+
/* Check if existing mirror can be reused
125+
* (same direction and monitor port).
126+
*/
127+
for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++) {
128+
if (sparx5_mirror_dir_get(sparx5, i) == dir &&
129+
sparx5_mirror_has_monitor(sparx5, i, mport->portno)) {
130+
*idx = i;
131+
return 0;
132+
}
133+
}
134+
135+
/* Return free mirror */
136+
for (i = 0; i < SPX5_MIRROR_PROBE_MAX; i++) {
137+
if (sparx5_mirror_is_empty(sparx5, i)) {
138+
*idx = i;
139+
return 0;
140+
}
141+
}
142+
143+
return -ENOENT;
144+
}
145+
146+
int sparx5_mirror_add(struct sparx5_mall_entry *entry)
147+
{
148+
u32 mirror_idx, dir = sparx5_mirror_to_dir(entry->ingress);
149+
struct sparx5_port *sport, *mport;
150+
struct sparx5 *sparx5;
151+
int err;
152+
153+
/* Source port */
154+
sport = entry->port;
155+
/* monitor port */
156+
mport = entry->mirror.port;
157+
sparx5 = sport->sparx5;
158+
159+
if (sport->portno == mport->portno)
160+
return -EINVAL;
161+
162+
err = sparx5_mirror_get(sport, mport, dir, &mirror_idx);
163+
if (err)
164+
return err;
165+
166+
if (sparx5_mirror_contains(sparx5, mirror_idx, sport->portno))
167+
return -EEXIST;
168+
169+
/* Add port to mirror */
170+
sparx5_mirror_port_add(sparx5, mirror_idx, sport->portno);
171+
172+
/* Set direction of mirror */
173+
sparx5_mirror_dir_set(sparx5, mirror_idx, dir);
174+
175+
/* Set monitor port for mirror */
176+
sparx5_mirror_monitor_set(sparx5, mirror_idx, mport->portno);
177+
178+
entry->mirror.idx = mirror_idx;
179+
180+
return 0;
181+
}
182+
183+
void sparx5_mirror_del(struct sparx5_mall_entry *entry)
184+
{
185+
struct sparx5_port *port = entry->port;
186+
struct sparx5 *sparx5 = port->sparx5;
187+
u32 mirror_idx = entry->mirror.idx;
188+
189+
sparx5_mirror_port_del(sparx5, mirror_idx, port->portno);
190+
if (!sparx5_mirror_is_empty(sparx5, mirror_idx))
191+
return;
192+
193+
sparx5_mirror_dir_set(sparx5, mirror_idx, SPX5_MIRROR_DISABLED);
194+
195+
sparx5_mirror_monitor_set(sparx5,
196+
mirror_idx,
197+
SPX5_MIRROR_MONITOR_PORT_DEFAULT);
198+
}
199+
200+
void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
201+
struct flow_stats *fstats)
202+
{
203+
struct sparx5_port *port = entry->port;
204+
struct rtnl_link_stats64 new_stats;
205+
struct flow_stats *old_stats;
206+
207+
old_stats = &entry->port->mirror_stats;
208+
sparx5_get_stats64(port->ndev, &new_stats);
209+
210+
if (entry->ingress) {
211+
flow_stats_update(fstats,
212+
new_stats.rx_bytes - old_stats->bytes,
213+
new_stats.rx_packets - old_stats->pkts,
214+
new_stats.rx_dropped - old_stats->drops,
215+
old_stats->lastused,
216+
FLOW_ACTION_HW_STATS_IMMEDIATE);
217+
218+
old_stats->bytes = new_stats.rx_bytes;
219+
old_stats->pkts = new_stats.rx_packets;
220+
old_stats->drops = new_stats.rx_dropped;
221+
old_stats->lastused = jiffies;
222+
} else {
223+
flow_stats_update(fstats,
224+
new_stats.tx_bytes - old_stats->bytes,
225+
new_stats.tx_packets - old_stats->pkts,
226+
new_stats.tx_dropped - old_stats->drops,
227+
old_stats->lastused,
228+
FLOW_ACTION_HW_STATS_IMMEDIATE);
229+
230+
old_stats->bytes = new_stats.tx_bytes;
231+
old_stats->pkts = new_stats.tx_packets;
232+
old_stats->drops = new_stats.tx_dropped;
233+
old_stats->lastused = jiffies;
234+
}
235+
}

‎drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c

+116-9
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,44 @@
1111
#include "sparx5_main.h"
1212
#include "sparx5_vcap_impl.h"
1313

14+
static struct sparx5_mall_entry *
15+
sparx5_tc_matchall_entry_find(struct list_head *entries, unsigned long cookie)
16+
{
17+
struct sparx5_mall_entry *entry;
18+
19+
list_for_each_entry(entry, entries, list) {
20+
if (entry->cookie == cookie)
21+
return entry;
22+
}
23+
24+
return NULL;
25+
}
26+
27+
static void sparx5_tc_matchall_parse_action(struct sparx5_port *port,
28+
struct sparx5_mall_entry *entry,
29+
struct flow_action_entry *action,
30+
bool ingress,
31+
unsigned long cookie)
32+
{
33+
entry->port = port;
34+
entry->type = action->id;
35+
entry->ingress = ingress;
36+
entry->cookie = cookie;
37+
}
38+
39+
static void
40+
sparx5_tc_matchall_parse_mirror_action(struct sparx5_mall_entry *entry,
41+
struct flow_action_entry *action)
42+
{
43+
entry->mirror.port = netdev_priv(action->dev);
44+
}
45+
1446
static int sparx5_tc_matchall_replace(struct net_device *ndev,
1547
struct tc_cls_matchall_offload *tmo,
1648
bool ingress)
1749
{
1850
struct sparx5_port *port = netdev_priv(ndev);
51+
struct sparx5_mall_entry *mall_entry;
1952
struct flow_action_entry *action;
2053
struct sparx5 *sparx5;
2154
int err;
@@ -27,8 +60,45 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev,
2760
}
2861
action = &tmo->rule->action.entries[0];
2962

63+
mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL);
64+
if (!mall_entry)
65+
return -ENOMEM;
66+
67+
sparx5_tc_matchall_parse_action(port,
68+
mall_entry,
69+
action,
70+
ingress,
71+
tmo->cookie);
72+
3073
sparx5 = port->sparx5;
3174
switch (action->id) {
75+
case FLOW_ACTION_MIRRED:
76+
sparx5_tc_matchall_parse_mirror_action(mall_entry, action);
77+
err = sparx5_mirror_add(mall_entry);
78+
if (err) {
79+
switch (err) {
80+
case -EEXIST:
81+
NL_SET_ERR_MSG_MOD(tmo->common.extack,
82+
"Mirroring already exists");
83+
break;
84+
case -EINVAL:
85+
NL_SET_ERR_MSG_MOD(tmo->common.extack,
86+
"Cannot mirror a monitor port");
87+
break;
88+
case -ENOENT:
89+
NL_SET_ERR_MSG_MOD(tmo->common.extack,
90+
"No more mirror probes available");
91+
break;
92+
default:
93+
NL_SET_ERR_MSG_MOD(tmo->common.extack,
94+
"Unknown error");
95+
break;
96+
}
97+
return err;
98+
}
99+
/* Get baseline stats for this port */
100+
sparx5_mirror_stats(mall_entry, &tmo->stats);
101+
break;
32102
case FLOW_ACTION_GOTO:
33103
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
34104
tmo->common.chain_index,
@@ -59,6 +129,9 @@ static int sparx5_tc_matchall_replace(struct net_device *ndev,
59129
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
60130
return -EOPNOTSUPP;
61131
}
132+
133+
list_add_tail(&mall_entry->list, &sparx5->mall_entries);
134+
62135
return 0;
63136
}
64137

@@ -67,19 +140,51 @@ static int sparx5_tc_matchall_destroy(struct net_device *ndev,
67140
bool ingress)
68141
{
69142
struct sparx5_port *port = netdev_priv(ndev);
70-
struct sparx5 *sparx5;
71-
int err;
143+
struct sparx5 *sparx5 = port->sparx5;
144+
struct sparx5_mall_entry *entry;
145+
int err = 0;
72146

73-
sparx5 = port->sparx5;
74-
if (!tmo->rule && tmo->cookie) {
147+
entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,
148+
tmo->cookie);
149+
if (!entry)
150+
return -ENOENT;
151+
152+
if (entry->type == FLOW_ACTION_MIRRED) {
153+
sparx5_mirror_del(entry);
154+
} else if (entry->type == FLOW_ACTION_GOTO) {
75155
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
76156
0, 0, tmo->cookie, false);
77-
if (err)
78-
return err;
79-
return 0;
157+
} else {
158+
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
159+
err = -EOPNOTSUPP;
80160
}
81-
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
82-
return -EOPNOTSUPP;
161+
162+
list_del(&entry->list);
163+
164+
return err;
165+
}
166+
167+
static int sparx5_tc_matchall_stats(struct net_device *ndev,
168+
struct tc_cls_matchall_offload *tmo,
169+
bool ingress)
170+
{
171+
struct sparx5_port *port = netdev_priv(ndev);
172+
struct sparx5 *sparx5 = port->sparx5;
173+
struct sparx5_mall_entry *entry;
174+
175+
entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,
176+
tmo->cookie);
177+
if (!entry)
178+
return -ENOENT;
179+
180+
if (entry->type == FLOW_ACTION_MIRRED) {
181+
sparx5_mirror_stats(entry, &tmo->stats);
182+
} else {
183+
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
184+
return -EOPNOTSUPP;
185+
}
186+
187+
return 0;
83188
}
84189

85190
int sparx5_tc_matchall(struct net_device *ndev,
@@ -91,6 +196,8 @@ int sparx5_tc_matchall(struct net_device *ndev,
91196
return sparx5_tc_matchall_replace(ndev, tmo, ingress);
92197
case TC_CLSMATCHALL_DESTROY:
93198
return sparx5_tc_matchall_destroy(ndev, tmo, ingress);
199+
case TC_CLSMATCHALL_STATS:
200+
return sparx5_tc_matchall_stats(ndev, tmo, ingress);
94201
default:
95202
return -EOPNOTSUPP;
96203
}

0 commit comments

Comments
 (0)
Please sign in to comment.