Merge branch 'mirroring-for-ocelot-switches'
Vladimir Oltean says: ==================== Mirroring for Ocelot switches This series adds support for tc-matchall (port-based) and tc-flower (flow-based) offloading of the tc-mirred action. Support has been added for both the ocelot switchdev driver and felix DSA driver. ==================== Link: https://lore.kernel.org/r/20220316204144.2679277-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
3e66fd54ae
@ -2110,7 +2110,8 @@ out:
|
||||
EXPORT_SYMBOL(b53_get_tag_protocol);
|
||||
|
||||
int b53_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror, bool ingress)
|
||||
struct dsa_mall_mirror_tc_entry *mirror, bool ingress,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct b53_device *dev = ds->priv;
|
||||
u16 reg, loc;
|
||||
|
@ -373,7 +373,8 @@ int b53_mdb_del(struct dsa_switch *ds, int port,
|
||||
const struct switchdev_obj_port_mdb *mdb,
|
||||
struct dsa_db db);
|
||||
int b53_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror, bool ingress);
|
||||
struct dsa_mall_mirror_tc_entry *mirror, bool ingress,
|
||||
struct netlink_ext_ack *extack);
|
||||
enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,
|
||||
enum dsa_tag_protocol mprot);
|
||||
void b53_mirror_del(struct dsa_switch *ds, int port,
|
||||
|
@ -1233,7 +1233,7 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port,
|
||||
|
||||
static int ksz8_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress)
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
|
@ -1018,7 +1018,7 @@ exit:
|
||||
|
||||
static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress)
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ksz_device *dev = ds->priv;
|
||||
|
||||
|
@ -1714,7 +1714,7 @@ static int mt753x_mirror_port_set(unsigned int id, u32 val)
|
||||
|
||||
static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress)
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mt7530_priv *priv = ds->priv;
|
||||
int monitor_port;
|
||||
|
@ -6321,7 +6321,8 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
|
||||
static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress)
|
||||
bool ingress,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
enum mv88e6xxx_egress_direction direction = ingress ?
|
||||
MV88E6XXX_EGRESS_DIR_INGRESS :
|
||||
|
@ -1650,6 +1650,24 @@ static void felix_port_policer_del(struct dsa_switch *ds, int port)
|
||||
ocelot_port_policer_del(ocelot, port);
|
||||
}
|
||||
|
||||
static int felix_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot *ocelot = ds->priv;
|
||||
|
||||
return ocelot_port_mirror_add(ocelot, port, mirror->to_local_port,
|
||||
ingress, extack);
|
||||
}
|
||||
|
||||
static void felix_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror)
|
||||
{
|
||||
struct ocelot *ocelot = ds->priv;
|
||||
|
||||
ocelot_port_mirror_del(ocelot, port, mirror->ingress);
|
||||
}
|
||||
|
||||
static int felix_port_setup_tc(struct dsa_switch *ds, int port,
|
||||
enum tc_setup_type type,
|
||||
void *type_data)
|
||||
@ -1880,6 +1898,8 @@ const struct dsa_switch_ops felix_switch_ops = {
|
||||
.port_max_mtu = felix_get_max_mtu,
|
||||
.port_policer_add = felix_port_policer_add,
|
||||
.port_policer_del = felix_port_policer_del,
|
||||
.port_mirror_add = felix_port_mirror_add,
|
||||
.port_mirror_del = felix_port_mirror_del,
|
||||
.cls_flower_add = felix_cls_flower_add,
|
||||
.cls_flower_del = felix_cls_flower_del,
|
||||
.cls_flower_stats = felix_cls_flower_stats,
|
||||
|
@ -2473,7 +2473,7 @@ qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
static int
|
||||
qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress)
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
int monitor_port, ret;
|
||||
|
@ -2847,7 +2847,7 @@ static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to,
|
||||
|
||||
static int sja1105_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress)
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
return sja1105_mirror_apply(ds->priv, port, mirror->to_local_port,
|
||||
ingress, true);
|
||||
|
@ -3023,6 +3023,82 @@ int ocelot_port_del_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ocelot_port_del_dscp_prio);
|
||||
|
||||
struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot_mirror *m = ocelot->mirror;
|
||||
|
||||
if (m) {
|
||||
if (m->to != to) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Mirroring already configured towards different egress port");
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
refcount_inc(&m->refcount);
|
||||
return m;
|
||||
}
|
||||
|
||||
m = kzalloc(sizeof(*m), GFP_KERNEL);
|
||||
if (!m)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
m->to = to;
|
||||
refcount_set(&m->refcount, 1);
|
||||
ocelot->mirror = m;
|
||||
|
||||
/* Program the mirror port to hardware */
|
||||
ocelot_write(ocelot, BIT(to), ANA_MIRRORPORTS);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void ocelot_mirror_put(struct ocelot *ocelot)
|
||||
{
|
||||
struct ocelot_mirror *m = ocelot->mirror;
|
||||
|
||||
if (!refcount_dec_and_test(&m->refcount))
|
||||
return;
|
||||
|
||||
ocelot_write(ocelot, 0, ANA_MIRRORPORTS);
|
||||
ocelot->mirror = NULL;
|
||||
kfree(m);
|
||||
}
|
||||
|
||||
int ocelot_port_mirror_add(struct ocelot *ocelot, int from, int to,
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot_mirror *m = ocelot_mirror_get(ocelot, to, extack);
|
||||
|
||||
if (IS_ERR(m))
|
||||
return PTR_ERR(m);
|
||||
|
||||
if (ingress) {
|
||||
ocelot_rmw_gix(ocelot, ANA_PORT_PORT_CFG_SRC_MIRROR_ENA,
|
||||
ANA_PORT_PORT_CFG_SRC_MIRROR_ENA,
|
||||
ANA_PORT_PORT_CFG, from);
|
||||
} else {
|
||||
ocelot_rmw(ocelot, BIT(from), BIT(from),
|
||||
ANA_EMIRRORPORTS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ocelot_port_mirror_add);
|
||||
|
||||
void ocelot_port_mirror_del(struct ocelot *ocelot, int from, bool ingress)
|
||||
{
|
||||
if (ingress) {
|
||||
ocelot_rmw_gix(ocelot, 0, ANA_PORT_PORT_CFG_SRC_MIRROR_ENA,
|
||||
ANA_PORT_PORT_CFG, from);
|
||||
} else {
|
||||
ocelot_rmw(ocelot, 0, BIT(from), ANA_EMIRRORPORTS);
|
||||
}
|
||||
|
||||
ocelot_mirror_put(ocelot);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ocelot_port_mirror_del);
|
||||
|
||||
void ocelot_init_port(struct ocelot *ocelot, int port)
|
||||
{
|
||||
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
||||
|
@ -38,7 +38,8 @@
|
||||
struct ocelot_port_tc {
|
||||
bool block_shared;
|
||||
unsigned long offload_cnt;
|
||||
|
||||
unsigned long ingress_mirred_id;
|
||||
unsigned long egress_mirred_id;
|
||||
unsigned long police_id;
|
||||
};
|
||||
|
||||
@ -111,6 +112,10 @@ int ocelot_trap_add(struct ocelot *ocelot, int port,
|
||||
void (*populate)(struct ocelot_vcap_filter *f));
|
||||
int ocelot_trap_del(struct ocelot *ocelot, int port, unsigned long cookie);
|
||||
|
||||
struct ocelot_mirror *ocelot_mirror_get(struct ocelot *ocelot, int to,
|
||||
struct netlink_ext_ack *extack);
|
||||
void ocelot_mirror_put(struct ocelot *ocelot);
|
||||
|
||||
extern struct notifier_block ocelot_netdevice_nb;
|
||||
extern struct notifier_block ocelot_switchdev_nb;
|
||||
extern struct notifier_block ocelot_switchdev_blocking_nb;
|
||||
|
@ -359,6 +359,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
|
||||
filter->action.port_mask = BIT(egress_port);
|
||||
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
|
||||
break;
|
||||
case FLOW_ACTION_MIRRED:
|
||||
if (filter->block_id != VCAP_IS2) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Mirror action can only be offloaded to VCAP IS2");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (filter->goto_target != -1) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Last action must be GOTO");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
egress_port = ocelot->ops->netdev_to_port(a->dev);
|
||||
if (egress_port < 0) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Destination not an ocelot port");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
filter->egress_port.value = egress_port;
|
||||
filter->action.mirror_ena = true;
|
||||
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
|
||||
break;
|
||||
case FLOW_ACTION_VLAN_POP:
|
||||
if (filter->block_id != VCAP_IS1) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#define OCELOT_MAC_QUIRKS OCELOT_QUIRK_QSGMII_PORTS_MUST_BE_UP
|
||||
|
||||
static bool ocelot_netdevice_dev_check(const struct net_device *dev);
|
||||
|
||||
static struct ocelot *devlink_port_to_ocelot(struct devlink_port *dlp)
|
||||
{
|
||||
return devlink_priv(dlp->devlink);
|
||||
@ -216,14 +218,14 @@ int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
|
||||
}
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
|
||||
struct tc_cls_matchall_offload *f,
|
||||
bool ingress)
|
||||
static int ocelot_setup_tc_cls_matchall_police(struct ocelot_port_private *priv,
|
||||
struct tc_cls_matchall_offload *f,
|
||||
bool ingress,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
struct flow_action_entry *action = &f->rule->action.entries[0];
|
||||
struct ocelot *ocelot = priv->port.ocelot;
|
||||
struct ocelot_policer pol = { 0 };
|
||||
struct flow_action_entry *action;
|
||||
int port = priv->chip_port;
|
||||
int err;
|
||||
|
||||
@ -232,6 +234,119 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (priv->tc.police_id && priv->tc.police_id != f->cookie) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Only one policer per port is supported");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
err = ocelot_policer_validate(&f->rule->action, action, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
|
||||
pol.burst = action->police.burst;
|
||||
|
||||
err = ocelot_port_policer_add(ocelot, port, &pol);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Could not add policer");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc.police_id = f->cookie;
|
||||
priv->tc.offload_cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_cls_matchall_mirred(struct ocelot_port_private *priv,
|
||||
struct tc_cls_matchall_offload *f,
|
||||
bool ingress,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct flow_action *action = &f->rule->action;
|
||||
struct ocelot *ocelot = priv->port.ocelot;
|
||||
struct ocelot_port_private *other_priv;
|
||||
const struct flow_action_entry *a;
|
||||
int err;
|
||||
|
||||
if (f->common.protocol != htons(ETH_P_ALL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!flow_action_basic_hw_stats_check(action, extack))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
a = &action->entries[0];
|
||||
if (!a->dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ocelot_netdevice_dev_check(a->dev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Destination not an ocelot port");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
other_priv = netdev_priv(a->dev);
|
||||
|
||||
err = ocelot_port_mirror_add(ocelot, priv->chip_port,
|
||||
other_priv->chip_port, ingress, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ingress)
|
||||
priv->tc.ingress_mirred_id = f->cookie;
|
||||
else
|
||||
priv->tc.egress_mirred_id = f->cookie;
|
||||
priv->tc.offload_cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocelot_del_tc_cls_matchall_police(struct ocelot_port_private *priv,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot *ocelot = priv->port.ocelot;
|
||||
int port = priv->chip_port;
|
||||
int err;
|
||||
|
||||
err = ocelot_port_policer_del(ocelot, port);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Could not delete policer");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc.police_id = 0;
|
||||
priv->tc.offload_cnt--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocelot_del_tc_cls_matchall_mirred(struct ocelot_port_private *priv,
|
||||
bool ingress,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot *ocelot = priv->port.ocelot;
|
||||
int port = priv->chip_port;
|
||||
|
||||
ocelot_port_mirror_del(ocelot, port, ingress);
|
||||
|
||||
if (ingress)
|
||||
priv->tc.ingress_mirred_id = 0;
|
||||
else
|
||||
priv->tc.egress_mirred_id = 0;
|
||||
priv->tc.offload_cnt--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
|
||||
struct tc_cls_matchall_offload *f,
|
||||
bool ingress)
|
||||
{
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
struct flow_action_entry *action;
|
||||
|
||||
switch (f->command) {
|
||||
case TC_CLSMATCHALL_REPLACE:
|
||||
if (!flow_offload_has_one_action(&f->rule->action)) {
|
||||
@ -242,53 +357,41 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
|
||||
|
||||
if (priv->tc.block_shared) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Rate limit is not supported on shared blocks");
|
||||
"Matchall offloads not supported on shared blocks");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
action = &f->rule->action.entries[0];
|
||||
|
||||
if (action->id != FLOW_ACTION_POLICE) {
|
||||
switch (action->id) {
|
||||
case FLOW_ACTION_POLICE:
|
||||
return ocelot_setup_tc_cls_matchall_police(priv, f,
|
||||
ingress,
|
||||
extack);
|
||||
break;
|
||||
case FLOW_ACTION_MIRRED:
|
||||
return ocelot_setup_tc_cls_matchall_mirred(priv, f,
|
||||
ingress,
|
||||
extack);
|
||||
default:
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (priv->tc.police_id && priv->tc.police_id != f->cookie) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Only one policer per port is supported");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
err = ocelot_policer_validate(&f->rule->action, action,
|
||||
extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
|
||||
pol.burst = action->police.burst;
|
||||
|
||||
err = ocelot_port_policer_add(ocelot, port, &pol);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Could not add policer");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc.police_id = f->cookie;
|
||||
priv->tc.offload_cnt++;
|
||||
return 0;
|
||||
break;
|
||||
case TC_CLSMATCHALL_DESTROY:
|
||||
if (priv->tc.police_id != f->cookie)
|
||||
action = &f->rule->action.entries[0];
|
||||
|
||||
if (f->cookie == priv->tc.police_id)
|
||||
return ocelot_del_tc_cls_matchall_police(priv, extack);
|
||||
else if (f->cookie == priv->tc.ingress_mirred_id ||
|
||||
f->cookie == priv->tc.egress_mirred_id)
|
||||
return ocelot_del_tc_cls_matchall_mirred(priv, ingress,
|
||||
extack);
|
||||
else
|
||||
return -ENOENT;
|
||||
|
||||
err = ocelot_port_policer_del(ocelot, port);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Could not delete policer");
|
||||
return err;
|
||||
}
|
||||
priv->tc.police_id = 0;
|
||||
priv->tc.offload_cnt--;
|
||||
return 0;
|
||||
break;
|
||||
case TC_CLSMATCHALL_STATS:
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -335,6 +335,7 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
||||
|
||||
vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode);
|
||||
vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask);
|
||||
vcap_action_set(vcap, data, VCAP_IS2_ACT_MIRROR_ENA, a->mirror_ena);
|
||||
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena);
|
||||
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix);
|
||||
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num);
|
||||
@ -955,14 +956,21 @@ int ocelot_vcap_policer_del(struct ocelot *ocelot, u32 pol_ix)
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_vcap_policer_del);
|
||||
|
||||
static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
|
||||
struct ocelot_vcap_block *block,
|
||||
struct ocelot_vcap_filter *filter)
|
||||
static int
|
||||
ocelot_vcap_filter_add_aux_resources(struct ocelot *ocelot,
|
||||
struct ocelot_vcap_filter *filter,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot_vcap_filter *tmp;
|
||||
struct list_head *pos, *n;
|
||||
struct ocelot_mirror *m;
|
||||
int ret;
|
||||
|
||||
if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena) {
|
||||
m = ocelot_mirror_get(ocelot, filter->egress_port.value,
|
||||
extack);
|
||||
if (IS_ERR(m))
|
||||
return PTR_ERR(m);
|
||||
}
|
||||
|
||||
if (filter->block_id == VCAP_IS2 && filter->action.police_ena) {
|
||||
ret = ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
|
||||
&filter->action.pol);
|
||||
@ -970,6 +978,33 @@ static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ocelot_vcap_filter_del_aux_resources(struct ocelot *ocelot,
|
||||
struct ocelot_vcap_filter *filter)
|
||||
{
|
||||
if (filter->block_id == VCAP_IS2 && filter->action.police_ena)
|
||||
ocelot_vcap_policer_del(ocelot, filter->action.pol_ix);
|
||||
|
||||
if (filter->block_id == VCAP_IS2 && filter->action.mirror_ena)
|
||||
ocelot_mirror_put(ocelot);
|
||||
}
|
||||
|
||||
static int ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
|
||||
struct ocelot_vcap_block *block,
|
||||
struct ocelot_vcap_filter *filter,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot_vcap_filter *tmp;
|
||||
struct list_head *pos, *n;
|
||||
int ret;
|
||||
|
||||
ret = ocelot_vcap_filter_add_aux_resources(ocelot, filter, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
block->count++;
|
||||
|
||||
if (list_empty(&block->rules)) {
|
||||
@ -1168,7 +1203,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
|
||||
}
|
||||
|
||||
/* Add filter to the linked list */
|
||||
ret = ocelot_vcap_filter_add_to_block(ocelot, block, filter);
|
||||
ret = ocelot_vcap_filter_add_to_block(ocelot, block, filter, extack);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1199,11 +1234,7 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot,
|
||||
|
||||
list_for_each_entry_safe(tmp, n, &block->rules, list) {
|
||||
if (ocelot_vcap_filter_equal(filter, tmp)) {
|
||||
if (tmp->block_id == VCAP_IS2 &&
|
||||
tmp->action.police_ena)
|
||||
ocelot_vcap_policer_del(ocelot,
|
||||
tmp->action.pol_ix);
|
||||
|
||||
ocelot_vcap_filter_del_aux_resources(ocelot, tmp);
|
||||
list_del(&tmp->list);
|
||||
kfree(tmp);
|
||||
}
|
||||
|
@ -1028,7 +1028,7 @@ struct dsa_switch_ops {
|
||||
struct flow_cls_offload *cls, bool ingress);
|
||||
int (*port_mirror_add)(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress);
|
||||
bool ingress, struct netlink_ext_ack *extack);
|
||||
void (*port_mirror_del)(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror);
|
||||
int (*port_policer_add)(struct dsa_switch *ds, int port,
|
||||
|
@ -642,6 +642,11 @@ struct ocelot_lag_fdb {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct ocelot_mirror {
|
||||
refcount_t refcount;
|
||||
int to;
|
||||
};
|
||||
|
||||
struct ocelot_port {
|
||||
struct ocelot *ocelot;
|
||||
|
||||
@ -723,6 +728,7 @@ struct ocelot {
|
||||
struct ocelot_vcap_block block[3];
|
||||
struct ocelot_vcap_policer vcap_pol;
|
||||
struct vcap_props *vcap;
|
||||
struct ocelot_mirror *mirror;
|
||||
|
||||
struct ocelot_psfp_list psfp;
|
||||
|
||||
@ -908,6 +914,9 @@ int ocelot_get_max_mtu(struct ocelot *ocelot, int port);
|
||||
int ocelot_port_policer_add(struct ocelot *ocelot, int port,
|
||||
struct ocelot_policer *pol);
|
||||
int ocelot_port_policer_del(struct ocelot *ocelot, int port);
|
||||
int ocelot_port_mirror_add(struct ocelot *ocelot, int from, int to,
|
||||
bool ingress, struct netlink_ext_ack *extack);
|
||||
void ocelot_port_mirror_del(struct ocelot *ocelot, int from, bool ingress);
|
||||
int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
|
||||
struct flow_cls_offload *f, bool ingress);
|
||||
int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
|
||||
|
@ -654,6 +654,7 @@ struct ocelot_vcap_action {
|
||||
enum ocelot_mask_mode mask_mode;
|
||||
unsigned long port_mask;
|
||||
bool police_ena;
|
||||
bool mirror_ena;
|
||||
struct ocelot_policer pol;
|
||||
u32 pol_ix;
|
||||
};
|
||||
@ -697,6 +698,7 @@ struct ocelot_vcap_filter {
|
||||
unsigned long ingress_port_mask;
|
||||
/* For VCAP ES0 */
|
||||
struct ocelot_vcap_port ingress_port;
|
||||
/* For VCAP IS2 mirrors and ES0 */
|
||||
struct ocelot_vcap_port egress_port;
|
||||
|
||||
enum ocelot_vcap_bit dmac_mc;
|
||||
|
@ -1173,6 +1173,7 @@ dsa_slave_add_cls_matchall_mirred(struct net_device *dev,
|
||||
struct tc_cls_matchall_offload *cls,
|
||||
bool ingress)
|
||||
{
|
||||
struct netlink_ext_ack *extack = cls->common.extack;
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
struct dsa_slave_priv *p = netdev_priv(dev);
|
||||
struct dsa_mall_mirror_tc_entry *mirror;
|
||||
@ -1210,7 +1211,7 @@ dsa_slave_add_cls_matchall_mirred(struct net_device *dev,
|
||||
mirror->to_local_port = to_dp->index;
|
||||
mirror->ingress = ingress;
|
||||
|
||||
err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress);
|
||||
err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress, extack);
|
||||
if (err) {
|
||||
kfree(mall_tc_entry);
|
||||
return err;
|
||||
|
Loading…
x
Reference in New Issue
Block a user