1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
// 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;
}
}
|