Skip to content

Commit b69e953

Browse files
HoratiuVulturdavem330
authored andcommitted
net: lan966x: Add port mirroring support using tc-matchall
Add support for port mirroring. It is possible to mirror only one port at a time and it is possible to have both ingress and egress mirroring. Frames injected by the CPU don't get egress mirrored because they are bypassing the analyzer module. Signed-off-by: Horatiu Vultur <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5390334 commit b69e953

File tree

5 files changed

+193
-1
lines changed

5 files changed

+193
-1
lines changed

drivers/net/ethernet/microchip/lan966x/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
1111
lan966x_ptp.o lan966x_fdma.o lan966x_lag.o \
1212
lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \
1313
lan966x_tbf.o lan966x_cbs.o lan966x_ets.o \
14-
lan966x_tc_matchall.o lan966x_police.o
14+
lan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o

drivers/net/ethernet/microchip/lan966x/lan966x_main.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ struct lan966x {
264264
struct lan966x_rx rx;
265265
struct lan966x_tx tx;
266266
struct napi_struct napi;
267+
268+
/* Mirror */
269+
struct lan966x_port *mirror_monitor;
270+
u32 mirror_mask[2];
271+
u32 mirror_count;
267272
};
268273

269274
struct lan966x_port_config {
@@ -279,7 +284,10 @@ struct lan966x_port_config {
279284
struct lan966x_port_tc {
280285
bool ingress_shared_block;
281286
unsigned long police_id;
287+
unsigned long ingress_mirror_id;
288+
unsigned long egress_mirror_id;
282289
struct flow_stats police_stat;
290+
struct flow_stats mirror_stat;
283291
};
284292

285293
struct lan966x_port {
@@ -505,6 +513,18 @@ int lan966x_police_port_del(struct lan966x_port *port,
505513
void lan966x_police_port_stats(struct lan966x_port *port,
506514
struct flow_stats *stats);
507515

516+
int lan966x_mirror_port_add(struct lan966x_port *port,
517+
struct flow_action_entry *action,
518+
unsigned long mirror_id,
519+
bool ingress,
520+
struct netlink_ext_ack *extack);
521+
int lan966x_mirror_port_del(struct lan966x_port *port,
522+
bool ingress,
523+
struct netlink_ext_ack *extack);
524+
void lan966x_mirror_port_stats(struct lan966x_port *port,
525+
struct flow_stats *stats,
526+
bool ingress);
527+
508528
static inline void __iomem *lan_addr(void __iomem *base[],
509529
int id, int tinst, int tcnt,
510530
int gbase, int ginst,
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
3+
#include "lan966x_main.h"
4+
5+
int lan966x_mirror_port_add(struct lan966x_port *port,
6+
struct flow_action_entry *action,
7+
unsigned long mirror_id,
8+
bool ingress,
9+
struct netlink_ext_ack *extack)
10+
{
11+
struct lan966x *lan966x = port->lan966x;
12+
struct lan966x_port *monitor_port;
13+
14+
if (!lan966x_netdevice_check(action->dev)) {
15+
NL_SET_ERR_MSG_MOD(extack,
16+
"Destination not an lan966x port");
17+
return -EOPNOTSUPP;
18+
}
19+
20+
monitor_port = netdev_priv(action->dev);
21+
22+
if (lan966x->mirror_mask[ingress] & BIT(port->chip_port)) {
23+
NL_SET_ERR_MSG_MOD(extack,
24+
"Mirror already exists");
25+
return -EEXIST;
26+
}
27+
28+
if (lan966x->mirror_monitor &&
29+
lan966x->mirror_monitor != monitor_port) {
30+
NL_SET_ERR_MSG_MOD(extack,
31+
"Cannot change mirror port while in use");
32+
return -EBUSY;
33+
}
34+
35+
if (port == monitor_port) {
36+
NL_SET_ERR_MSG_MOD(extack,
37+
"Cannot mirror the monitor port");
38+
return -EINVAL;
39+
}
40+
41+
lan966x->mirror_mask[ingress] |= BIT(port->chip_port);
42+
43+
lan966x->mirror_monitor = monitor_port;
44+
lan_wr(BIT(monitor_port->chip_port), lan966x, ANA_MIRRORPORTS);
45+
46+
if (ingress) {
47+
lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(1),
48+
ANA_PORT_CFG_SRC_MIRROR_ENA,
49+
lan966x, ANA_PORT_CFG(port->chip_port));
50+
} else {
51+
lan_wr(lan966x->mirror_mask[0], lan966x,
52+
ANA_EMIRRORPORTS);
53+
}
54+
55+
lan966x->mirror_count++;
56+
57+
if (ingress)
58+
port->tc.ingress_mirror_id = mirror_id;
59+
else
60+
port->tc.egress_mirror_id = mirror_id;
61+
62+
return 0;
63+
}
64+
65+
int lan966x_mirror_port_del(struct lan966x_port *port,
66+
bool ingress,
67+
struct netlink_ext_ack *extack)
68+
{
69+
struct lan966x *lan966x = port->lan966x;
70+
71+
if (!(lan966x->mirror_mask[ingress] & BIT(port->chip_port))) {
72+
NL_SET_ERR_MSG_MOD(extack,
73+
"There is no mirroring for this port");
74+
return -ENOENT;
75+
}
76+
77+
lan966x->mirror_mask[ingress] &= ~BIT(port->chip_port);
78+
79+
if (ingress) {
80+
lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(0),
81+
ANA_PORT_CFG_SRC_MIRROR_ENA,
82+
lan966x, ANA_PORT_CFG(port->chip_port));
83+
} else {
84+
lan_wr(lan966x->mirror_mask[0], lan966x,
85+
ANA_EMIRRORPORTS);
86+
}
87+
88+
lan966x->mirror_count--;
89+
90+
if (lan966x->mirror_count == 0) {
91+
lan966x->mirror_monitor = NULL;
92+
lan_wr(0, lan966x, ANA_MIRRORPORTS);
93+
}
94+
95+
if (ingress)
96+
port->tc.ingress_mirror_id = 0;
97+
else
98+
port->tc.egress_mirror_id = 0;
99+
100+
return 0;
101+
}
102+
103+
void lan966x_mirror_port_stats(struct lan966x_port *port,
104+
struct flow_stats *stats,
105+
bool ingress)
106+
{
107+
struct rtnl_link_stats64 new_stats;
108+
struct flow_stats *old_stats;
109+
110+
old_stats = &port->tc.mirror_stat;
111+
lan966x_stats_get(port->dev, &new_stats);
112+
113+
if (ingress) {
114+
flow_stats_update(stats,
115+
new_stats.rx_bytes - old_stats->bytes,
116+
new_stats.rx_packets - old_stats->pkts,
117+
new_stats.rx_dropped - old_stats->drops,
118+
old_stats->lastused,
119+
FLOW_ACTION_HW_STATS_IMMEDIATE);
120+
121+
old_stats->bytes = new_stats.rx_bytes;
122+
old_stats->pkts = new_stats.rx_packets;
123+
old_stats->drops = new_stats.rx_dropped;
124+
old_stats->lastused = jiffies;
125+
} else {
126+
flow_stats_update(stats,
127+
new_stats.tx_bytes - old_stats->bytes,
128+
new_stats.tx_packets - old_stats->pkts,
129+
new_stats.tx_dropped - old_stats->drops,
130+
old_stats->lastused,
131+
FLOW_ACTION_HW_STATS_IMMEDIATE);
132+
133+
old_stats->bytes = new_stats.tx_bytes;
134+
old_stats->pkts = new_stats.tx_packets;
135+
old_stats->drops = new_stats.tx_dropped;
136+
old_stats->lastused = jiffies;
137+
}
138+
}

drivers/net/ethernet/microchip/lan966x/lan966x_regs.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,24 @@ enum lan966x_target {
9090
#define ANA_AUTOAGE_AGE_PERIOD_GET(x)\
9191
FIELD_GET(ANA_AUTOAGE_AGE_PERIOD, x)
9292

93+
/* ANA:ANA:MIRRORPORTS */
94+
#define ANA_MIRRORPORTS __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 60, 0, 1, 4)
95+
96+
#define ANA_MIRRORPORTS_MIRRORPORTS GENMASK(8, 0)
97+
#define ANA_MIRRORPORTS_MIRRORPORTS_SET(x)\
98+
FIELD_PREP(ANA_MIRRORPORTS_MIRRORPORTS, x)
99+
#define ANA_MIRRORPORTS_MIRRORPORTS_GET(x)\
100+
FIELD_GET(ANA_MIRRORPORTS_MIRRORPORTS, x)
101+
102+
/* ANA:ANA:EMIRRORPORTS */
103+
#define ANA_EMIRRORPORTS __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 64, 0, 1, 4)
104+
105+
#define ANA_EMIRRORPORTS_EMIRRORPORTS GENMASK(8, 0)
106+
#define ANA_EMIRRORPORTS_EMIRRORPORTS_SET(x)\
107+
FIELD_PREP(ANA_EMIRRORPORTS_EMIRRORPORTS, x)
108+
#define ANA_EMIRRORPORTS_EMIRRORPORTS_GET(x)\
109+
FIELD_GET(ANA_EMIRRORPORTS_EMIRRORPORTS, x)
110+
93111
/* ANA:ANA:FLOODING */
94112
#define ANA_FLOODING(r) __REG(TARGET_ANA, 0, 1, 29824, 0, 1, 244, 68, r, 8, 4)
95113

@@ -330,6 +348,12 @@ enum lan966x_target {
330348
/* ANA:PORT:PORT_CFG */
331349
#define ANA_PORT_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 112, 0, 1, 4)
332350

351+
#define ANA_PORT_CFG_SRC_MIRROR_ENA BIT(13)
352+
#define ANA_PORT_CFG_SRC_MIRROR_ENA_SET(x)\
353+
FIELD_PREP(ANA_PORT_CFG_SRC_MIRROR_ENA, x)
354+
#define ANA_PORT_CFG_SRC_MIRROR_ENA_GET(x)\
355+
FIELD_GET(ANA_PORT_CFG_SRC_MIRROR_ENA, x)
356+
333357
#define ANA_PORT_CFG_LEARNAUTO BIT(6)
334358
#define ANA_PORT_CFG_LEARNAUTO_SET(x)\
335359
FIELD_PREP(ANA_PORT_CFG_LEARNAUTO, x)

drivers/net/ethernet/microchip/lan966x/lan966x_tc_matchall.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ static int lan966x_tc_matchall_add(struct lan966x_port *port,
2020
return lan966x_police_port_add(port, &f->rule->action, act,
2121
f->cookie, ingress,
2222
f->common.extack);
23+
case FLOW_ACTION_MIRRED:
24+
return lan966x_mirror_port_add(port, act, f->cookie,
25+
ingress, f->common.extack);
2326
default:
2427
NL_SET_ERR_MSG_MOD(f->common.extack,
2528
"Unsupported action");
@@ -36,6 +39,10 @@ static int lan966x_tc_matchall_del(struct lan966x_port *port,
3639
if (f->cookie == port->tc.police_id) {
3740
return lan966x_police_port_del(port, f->cookie,
3841
f->common.extack);
42+
} else if (f->cookie == port->tc.ingress_mirror_id ||
43+
f->cookie == port->tc.egress_mirror_id) {
44+
return lan966x_mirror_port_del(port, ingress,
45+
f->common.extack);
3946
} else {
4047
NL_SET_ERR_MSG_MOD(f->common.extack,
4148
"Unsupported action");
@@ -51,6 +58,9 @@ static int lan966x_tc_matchall_stats(struct lan966x_port *port,
5158
{
5259
if (f->cookie == port->tc.police_id) {
5360
lan966x_police_port_stats(port, &f->stats);
61+
} else if (f->cookie == port->tc.ingress_mirror_id ||
62+
f->cookie == port->tc.egress_mirror_id) {
63+
lan966x_mirror_port_stats(port, &f->stats, ingress);
5464
} else {
5565
NL_SET_ERR_MSG_MOD(f->common.extack,
5666
"Unsupported action");

0 commit comments

Comments
 (0)