Skip to content

Commit f0942e0

Browse files
irtimmerdavem330
authored andcommitted
net: dsa: mv88e6xxx: Add support for port mirroring
Add support for configuring port mirroring through the cls_matchall classifier. We do a full ingress and/or egress capture towards a capture port. It allows setting a different capture port for ingress and egress traffic. It keeps track of the mirrored ports and the destination ports to prevent changes to the capture port while other ports are being mirrored. Signed-off-by: Iwan R Timmer <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5c74c54 commit f0942e0

File tree

5 files changed

+136
-4
lines changed

5 files changed

+136
-4
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5250,6 +5250,80 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
52505250
return err;
52515251
}
52525252

5253+
static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
5254+
struct dsa_mall_mirror_tc_entry *mirror,
5255+
bool ingress)
5256+
{
5257+
enum mv88e6xxx_egress_direction direction = ingress ?
5258+
MV88E6XXX_EGRESS_DIR_INGRESS :
5259+
MV88E6XXX_EGRESS_DIR_EGRESS;
5260+
struct mv88e6xxx_chip *chip = ds->priv;
5261+
bool other_mirrors = false;
5262+
int i;
5263+
int err;
5264+
5265+
if (!chip->info->ops->set_egress_port)
5266+
return -EOPNOTSUPP;
5267+
5268+
mutex_lock(&chip->reg_lock);
5269+
if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
5270+
mirror->to_local_port) {
5271+
for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5272+
other_mirrors |= ingress ?
5273+
chip->ports[i].mirror_ingress :
5274+
chip->ports[i].mirror_egress;
5275+
5276+
/* Can't change egress port when other mirror is active */
5277+
if (other_mirrors) {
5278+
err = -EBUSY;
5279+
goto out;
5280+
}
5281+
5282+
err = chip->info->ops->set_egress_port(chip,
5283+
direction,
5284+
mirror->to_local_port);
5285+
if (err)
5286+
goto out;
5287+
}
5288+
5289+
err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
5290+
out:
5291+
mutex_unlock(&chip->reg_lock);
5292+
5293+
return err;
5294+
}
5295+
5296+
static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
5297+
struct dsa_mall_mirror_tc_entry *mirror)
5298+
{
5299+
enum mv88e6xxx_egress_direction direction = mirror->ingress ?
5300+
MV88E6XXX_EGRESS_DIR_INGRESS :
5301+
MV88E6XXX_EGRESS_DIR_EGRESS;
5302+
struct mv88e6xxx_chip *chip = ds->priv;
5303+
bool other_mirrors = false;
5304+
int i;
5305+
5306+
mutex_lock(&chip->reg_lock);
5307+
if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
5308+
dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
5309+
5310+
for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
5311+
other_mirrors |= mirror->ingress ?
5312+
chip->ports[i].mirror_ingress :
5313+
chip->ports[i].mirror_egress;
5314+
5315+
/* Reset egress port when no other mirror is active */
5316+
if (!other_mirrors) {
5317+
if (chip->info->ops->set_egress_port(chip,
5318+
direction,
5319+
dsa_upstream_port(ds,
5320+
port)));
5321+
dev_err(ds->dev, "failed to set egress port\n");
5322+
}
5323+
5324+
mutex_unlock(&chip->reg_lock);
5325+
}
5326+
52535327
static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
52545328
bool unicast, bool multicast)
52555329
{
@@ -5305,6 +5379,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
53055379
.port_mdb_prepare = mv88e6xxx_port_mdb_prepare,
53065380
.port_mdb_add = mv88e6xxx_port_mdb_add,
53075381
.port_mdb_del = mv88e6xxx_port_mdb_del,
5382+
.port_mirror_add = mv88e6xxx_port_mirror_add,
5383+
.port_mirror_del = mv88e6xxx_port_mirror_del,
53085384
.crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join,
53095385
.crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave,
53105386
.port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set,

drivers/net/dsa/mv88e6xxx/chip.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ struct mv88e6xxx_port {
233233
u64 vtu_member_violation;
234234
u64 vtu_miss_violation;
235235
u8 cmode;
236+
bool mirror_ingress;
237+
bool mirror_egress;
236238
unsigned int serdes_irq;
237239
};
238240

@@ -316,6 +318,10 @@ struct mv88e6xxx_chip {
316318
u16 evcap_config;
317319
u16 enable_count;
318320

321+
/* Current ingress and egress monitor ports */
322+
int egress_dest_port;
323+
int ingress_dest_port;
324+
319325
/* Per-port timestamping resources. */
320326
struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
321327

drivers/net/dsa/mv88e6xxx/global1.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
267267
enum mv88e6xxx_egress_direction direction,
268268
int port)
269269
{
270+
int *dest_port_chip;
270271
u16 reg;
271272
int err;
272273

@@ -276,11 +277,13 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
276277

277278
switch (direction) {
278279
case MV88E6XXX_EGRESS_DIR_INGRESS:
280+
dest_port_chip = &chip->ingress_dest_port;
279281
reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
280282
reg |= port <<
281283
__bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
282284
break;
283285
case MV88E6XXX_EGRESS_DIR_EGRESS:
286+
dest_port_chip = &chip->egress_dest_port;
284287
reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
285288
reg |= port <<
286289
__bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
@@ -289,7 +292,11 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
289292
return -EINVAL;
290293
}
291294

292-
return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
295+
err = mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
296+
if (!err)
297+
*dest_port_chip = port;
298+
299+
return err;
293300
}
294301

295302
/* Older generations also call this the ARP destination. It has been
@@ -325,25 +332,28 @@ int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip,
325332
enum mv88e6xxx_egress_direction direction,
326333
int port)
327334
{
335+
int *dest_port_chip;
328336
u16 ptr;
329337
int err;
330338

331339
switch (direction) {
332340
case MV88E6XXX_EGRESS_DIR_INGRESS:
341+
dest_port_chip = &chip->ingress_dest_port;
333342
ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
334343
break;
335344
case MV88E6XXX_EGRESS_DIR_EGRESS:
345+
dest_port_chip = &chip->egress_dest_port;
336346
ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
337347
break;
338348
default:
339349
return -EINVAL;
340350
}
341351

342352
err = mv88e6390_g1_monitor_write(chip, ptr, port);
343-
if (err)
344-
return err;
353+
if (!err)
354+
*dest_port_chip = port;
345355

346-
return 0;
356+
return err;
347357
}
348358

349359
int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)

drivers/net/dsa/mv88e6xxx/port.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,43 @@ int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
11811181
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
11821182
}
11831183

1184+
int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
1185+
enum mv88e6xxx_egress_direction direction,
1186+
bool mirror)
1187+
{
1188+
bool *mirror_port;
1189+
u16 reg;
1190+
u16 bit;
1191+
int err;
1192+
1193+
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
1194+
if (err)
1195+
return err;
1196+
1197+
switch (direction) {
1198+
case MV88E6XXX_EGRESS_DIR_INGRESS:
1199+
bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
1200+
mirror_port = &chip->ports[port].mirror_ingress;
1201+
break;
1202+
case MV88E6XXX_EGRESS_DIR_EGRESS:
1203+
bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
1204+
mirror_port = &chip->ports[port].mirror_egress;
1205+
break;
1206+
default:
1207+
return -EINVAL;
1208+
}
1209+
1210+
reg &= ~bit;
1211+
if (mirror)
1212+
reg |= bit;
1213+
1214+
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
1215+
if (!err)
1216+
*mirror_port = mirror;
1217+
1218+
return err;
1219+
}
1220+
11841221
int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
11851222
u16 mode)
11861223
{

drivers/net/dsa/mv88e6xxx/port.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
368368
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
369369
int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
370370
int upstream_port);
371+
int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
372+
enum mv88e6xxx_egress_direction direction,
373+
bool mirror);
371374

372375
int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port);
373376
int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port);

0 commit comments

Comments
 (0)