139 lines
3.3 KiB
C
139 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
#include "lan966x_main.h"
|
|
|
|
int lan966x_mirror_port_add(struct lan966x_port *port,
|
|
struct flow_action_entry *action,
|
|
unsigned long mirror_id,
|
|
bool ingress,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
struct lan966x *lan966x = port->lan966x;
|
|
struct lan966x_port *monitor_port;
|
|
|
|
if (!lan966x_netdevice_check(action->dev)) {
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"Destination not an lan966x port");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
monitor_port = netdev_priv(action->dev);
|
|
|
|
if (lan966x->mirror_mask[ingress] & BIT(port->chip_port)) {
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"Mirror already exists");
|
|
return -EEXIST;
|
|
}
|
|
|
|
if (lan966x->mirror_monitor &&
|
|
lan966x->mirror_monitor != monitor_port) {
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"Cannot change mirror port while in use");
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (port == monitor_port) {
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"Cannot mirror the monitor port");
|
|
return -EINVAL;
|
|
}
|
|
|
|
lan966x->mirror_mask[ingress] |= BIT(port->chip_port);
|
|
|
|
lan966x->mirror_monitor = monitor_port;
|
|
lan_wr(BIT(monitor_port->chip_port), lan966x, ANA_MIRRORPORTS);
|
|
|
|
if (ingress) {
|
|
lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(1),
|
|
ANA_PORT_CFG_SRC_MIRROR_ENA,
|
|
lan966x, ANA_PORT_CFG(port->chip_port));
|
|
} else {
|
|
lan_wr(lan966x->mirror_mask[0], lan966x,
|
|
ANA_EMIRRORPORTS);
|
|
}
|
|
|
|
lan966x->mirror_count++;
|
|
|
|
if (ingress)
|
|
port->tc.ingress_mirror_id = mirror_id;
|
|
else
|
|
port->tc.egress_mirror_id = mirror_id;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lan966x_mirror_port_del(struct lan966x_port *port,
|
|
bool ingress,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
struct lan966x *lan966x = port->lan966x;
|
|
|
|
if (!(lan966x->mirror_mask[ingress] & BIT(port->chip_port))) {
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"There is no mirroring for this port");
|
|
return -ENOENT;
|
|
}
|
|
|
|
lan966x->mirror_mask[ingress] &= ~BIT(port->chip_port);
|
|
|
|
if (ingress) {
|
|
lan_rmw(ANA_PORT_CFG_SRC_MIRROR_ENA_SET(0),
|
|
ANA_PORT_CFG_SRC_MIRROR_ENA,
|
|
lan966x, ANA_PORT_CFG(port->chip_port));
|
|
} else {
|
|
lan_wr(lan966x->mirror_mask[0], lan966x,
|
|
ANA_EMIRRORPORTS);
|
|
}
|
|
|
|
lan966x->mirror_count--;
|
|
|
|
if (lan966x->mirror_count == 0) {
|
|
lan966x->mirror_monitor = NULL;
|
|
lan_wr(0, lan966x, ANA_MIRRORPORTS);
|
|
}
|
|
|
|
if (ingress)
|
|
port->tc.ingress_mirror_id = 0;
|
|
else
|
|
port->tc.egress_mirror_id = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void lan966x_mirror_port_stats(struct lan966x_port *port,
|
|
struct flow_stats *stats,
|
|
bool ingress)
|
|
{
|
|
struct rtnl_link_stats64 new_stats;
|
|
struct flow_stats *old_stats;
|
|
|
|
old_stats = &port->tc.mirror_stat;
|
|
lan966x_stats_get(port->dev, &new_stats);
|
|
|
|
if (ingress) {
|
|
flow_stats_update(stats,
|
|
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(stats,
|
|
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;
|
|
}
|
|
}
|