|
@@ -1161,8 +1161,8 @@ static int mlxsw_sp_port_get_phys_port_name(struct net_device *dev, char *name,
|
|
|
}
|
|
|
|
|
|
static struct mlxsw_sp_port_mall_tc_entry *
|
|
|
-mlxsw_sp_port_mirror_entry_find(struct mlxsw_sp_port *port,
|
|
|
- unsigned long cookie) {
|
|
|
+mlxsw_sp_port_mall_tc_entry_find(struct mlxsw_sp_port *port,
|
|
|
+ unsigned long cookie) {
|
|
|
struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
|
|
|
|
|
|
list_for_each_entry(mall_tc_entry, &port->mall_tc_list, list)
|
|
@@ -1174,17 +1174,15 @@ mlxsw_sp_port_mirror_entry_find(struct mlxsw_sp_port *port,
|
|
|
|
|
|
static int
|
|
|
mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
- struct tc_cls_matchall_offload *cls,
|
|
|
+ struct mlxsw_sp_port_mall_mirror_tc_entry *mirror,
|
|
|
const struct tc_action *a,
|
|
|
bool ingress)
|
|
|
{
|
|
|
- struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
|
|
|
struct net *net = dev_net(mlxsw_sp_port->dev);
|
|
|
enum mlxsw_sp_span_type span_type;
|
|
|
struct mlxsw_sp_port *to_port;
|
|
|
struct net_device *to_dev;
|
|
|
int ifindex;
|
|
|
- int err;
|
|
|
|
|
|
ifindex = tcf_mirred_ifindex(a);
|
|
|
to_dev = __dev_get_by_index(net, ifindex);
|
|
@@ -1195,30 +1193,28 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
|
|
|
if (!mlxsw_sp_port_dev_check(to_dev)) {
|
|
|
netdev_err(mlxsw_sp_port->dev, "Cannot mirror to a non-spectrum port");
|
|
|
- return -ENOTSUPP;
|
|
|
+ return -EOPNOTSUPP;
|
|
|
}
|
|
|
to_port = netdev_priv(to_dev);
|
|
|
|
|
|
- mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
|
|
|
- if (!mall_tc_entry)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- mall_tc_entry->cookie = cls->cookie;
|
|
|
- mall_tc_entry->type = MLXSW_SP_PORT_MALL_MIRROR;
|
|
|
- mall_tc_entry->mirror.to_local_port = to_port->local_port;
|
|
|
- mall_tc_entry->mirror.ingress = ingress;
|
|
|
- list_add_tail(&mall_tc_entry->list, &mlxsw_sp_port->mall_tc_list);
|
|
|
-
|
|
|
+ mirror->to_local_port = to_port->local_port;
|
|
|
+ mirror->ingress = ingress;
|
|
|
span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
|
|
|
- err = mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type);
|
|
|
- if (err)
|
|
|
- goto err_mirror_add;
|
|
|
- return 0;
|
|
|
+ return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type);
|
|
|
+}
|
|
|
|
|
|
-err_mirror_add:
|
|
|
- list_del(&mall_tc_entry->list);
|
|
|
- kfree(mall_tc_entry);
|
|
|
- return err;
|
|
|
+static void
|
|
|
+mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
+ struct mlxsw_sp_port_mall_mirror_tc_entry *mirror)
|
|
|
+{
|
|
|
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
|
|
+ enum mlxsw_sp_span_type span_type;
|
|
|
+ struct mlxsw_sp_port *to_port;
|
|
|
+
|
|
|
+ to_port = mlxsw_sp->ports[mirror->to_local_port];
|
|
|
+ span_type = mirror->ingress ?
|
|
|
+ MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
|
|
|
+ mlxsw_sp_span_mirror_remove(mlxsw_sp_port, to_port, span_type);
|
|
|
}
|
|
|
|
|
|
static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
@@ -1226,59 +1222,68 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
struct tc_cls_matchall_offload *cls,
|
|
|
bool ingress)
|
|
|
{
|
|
|
+ struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
|
|
|
const struct tc_action *a;
|
|
|
LIST_HEAD(actions);
|
|
|
int err;
|
|
|
|
|
|
if (!tc_single_action(cls->exts)) {
|
|
|
netdev_err(mlxsw_sp_port->dev, "only singular actions are supported\n");
|
|
|
- return -ENOTSUPP;
|
|
|
+ return -EOPNOTSUPP;
|
|
|
}
|
|
|
|
|
|
+ mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
|
|
|
+ if (!mall_tc_entry)
|
|
|
+ return -ENOMEM;
|
|
|
+ mall_tc_entry->cookie = cls->cookie;
|
|
|
+
|
|
|
tcf_exts_to_list(cls->exts, &actions);
|
|
|
- list_for_each_entry(a, &actions, list) {
|
|
|
- if (!is_tcf_mirred_egress_mirror(a) ||
|
|
|
- protocol != htons(ETH_P_ALL)) {
|
|
|
- return -ENOTSUPP;
|
|
|
- }
|
|
|
+ a = list_first_entry(&actions, struct tc_action, list);
|
|
|
|
|
|
- err = mlxsw_sp_port_add_cls_matchall_mirror(mlxsw_sp_port, cls,
|
|
|
- a, ingress);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
+ if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) {
|
|
|
+ struct mlxsw_sp_port_mall_mirror_tc_entry *mirror;
|
|
|
+
|
|
|
+ mall_tc_entry->type = MLXSW_SP_PORT_MALL_MIRROR;
|
|
|
+ mirror = &mall_tc_entry->mirror;
|
|
|
+ err = mlxsw_sp_port_add_cls_matchall_mirror(mlxsw_sp_port,
|
|
|
+ mirror, a, ingress);
|
|
|
+ } else {
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
}
|
|
|
|
|
|
+ if (err)
|
|
|
+ goto err_add_action;
|
|
|
+
|
|
|
+ list_add_tail(&mall_tc_entry->list, &mlxsw_sp_port->mall_tc_list);
|
|
|
return 0;
|
|
|
+
|
|
|
+err_add_action:
|
|
|
+ kfree(mall_tc_entry);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static void mlxsw_sp_port_del_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
|
|
|
struct tc_cls_matchall_offload *cls)
|
|
|
{
|
|
|
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
|
|
struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
|
|
|
- enum mlxsw_sp_span_type span_type;
|
|
|
- struct mlxsw_sp_port *to_port;
|
|
|
|
|
|
- mall_tc_entry = mlxsw_sp_port_mirror_entry_find(mlxsw_sp_port,
|
|
|
- cls->cookie);
|
|
|
+ mall_tc_entry = mlxsw_sp_port_mall_tc_entry_find(mlxsw_sp_port,
|
|
|
+ cls->cookie);
|
|
|
if (!mall_tc_entry) {
|
|
|
netdev_dbg(mlxsw_sp_port->dev, "tc entry not found on port\n");
|
|
|
return;
|
|
|
}
|
|
|
+ list_del(&mall_tc_entry->list);
|
|
|
|
|
|
switch (mall_tc_entry->type) {
|
|
|
case MLXSW_SP_PORT_MALL_MIRROR:
|
|
|
- to_port = mlxsw_sp->ports[mall_tc_entry->mirror.to_local_port];
|
|
|
- span_type = mall_tc_entry->mirror.ingress ?
|
|
|
- MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
|
|
|
-
|
|
|
- mlxsw_sp_span_mirror_remove(mlxsw_sp_port, to_port, span_type);
|
|
|
+ mlxsw_sp_port_del_cls_matchall_mirror(mlxsw_sp_port,
|
|
|
+ &mall_tc_entry->mirror);
|
|
|
break;
|
|
|
default:
|
|
|
WARN_ON(1);
|
|
|
}
|
|
|
|
|
|
- list_del(&mall_tc_entry->list);
|
|
|
kfree(mall_tc_entry);
|
|
|
}
|
|
|
|
|
@@ -1304,7 +1309,7 @@ static int mlxsw_sp_setup_tc(struct net_device *dev, u32 handle,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return -ENOTSUPP;
|
|
|
+ return -EOPNOTSUPP;
|
|
|
}
|
|
|
|
|
|
static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
|
|
@@ -1647,7 +1652,7 @@ mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats,
|
|
|
break;
|
|
|
default:
|
|
|
WARN_ON(1);
|
|
|
- return -ENOTSUPP;
|
|
|
+ return -EOPNOTSUPP;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
@@ -2426,8 +2431,8 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
|
|
|
mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
|
|
|
mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
|
|
|
mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
|
|
|
- free_percpu(mlxsw_sp_port->pcpu_stats);
|
|
|
kfree(mlxsw_sp_port->hw_stats.cache);
|
|
|
+ free_percpu(mlxsw_sp_port->pcpu_stats);
|
|
|
kfree(mlxsw_sp_port->untagged_vlans);
|
|
|
kfree(mlxsw_sp_port->active_vlans);
|
|
|
WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list));
|