summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-01-06 14:42:42 -0500
committerDavid S. Miller <davem@davemloft.net>2016-01-06 14:42:42 -0500
commitf637941b14055d5479bb43fc776e88a52cad33c9 (patch)
tree07f656c8413f9bb56d1fb4f566890f8df23c134f /drivers/net/ethernet
parent00ce3a15d811978fcb204a1a3f5f8c059096fa5e (diff)
parentfc1273afb257663de034260f5b5fbbd8d79d6308 (diff)
Merge branch 'mlxsw-vlan_filtering-offload'
Jiri Pirko says: ==================== mlxsw: add offload support for vlan_filtering option Elad says: This patch adds SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING port attribute. When a bridge is offloaded to hardware, the hardware can learn if the bridge is .1Q bridge (VLAN-aware) or not VLAN aware bridge. In order to toggle the mode a user can use sysfs: $ echo 1 > /sys/devices/virtual/net/br0/bridge/vlan_filtering or via iproute2: $ ip link set dev br0 type bridge vlan_filtering 1 --- v1->v2: small fix in patch #1 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c39
3 files changed, 43 insertions, 5 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 74ff0110e899..b6f365060dd7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1370,6 +1370,11 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
err = -ENOMEM;
goto err_port_active_vlans_alloc;
}
+ mlxsw_sp_port->untagged_vlans = kzalloc(bytes, GFP_KERNEL);
+ if (!mlxsw_sp_port->untagged_vlans) {
+ err = -ENOMEM;
+ goto err_port_untagged_vlans_alloc;
+ }
INIT_LIST_HEAD(&mlxsw_sp_port->vports_list);
mlxsw_sp_port->pcpu_stats =
@@ -1472,6 +1477,8 @@ err_port_module_check:
err_dev_addr_init:
free_percpu(mlxsw_sp_port->pcpu_stats);
err_alloc_stats:
+ kfree(mlxsw_sp_port->untagged_vlans);
+err_port_untagged_vlans_alloc:
kfree(mlxsw_sp_port->active_vlans);
err_port_active_vlans_alloc:
free_netdev(dev);
@@ -1505,6 +1512,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
mlxsw_sp_port_vports_fini(mlxsw_sp_port);
mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
free_percpu(mlxsw_sp_port->pcpu_stats);
+ kfree(mlxsw_sp_port->untagged_vlans);
kfree(mlxsw_sp_port->active_vlans);
free_netdev(mlxsw_sp_port->dev);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 463ed6dcc709..7601789dd522 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -144,6 +144,7 @@ struct mlxsw_sp_port {
} vport;
/* 802.1Q bridge VLANs */
unsigned long *active_vlans;
+ unsigned long *untagged_vlans;
/* VLAN interfaces */
struct list_head vports_list;
};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 62159547ebf9..614ef57ceefa 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -299,6 +299,22 @@ static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
}
+static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
+ struct switchdev_trans *trans,
+ struct net_device *orig_dev,
+ bool vlan_enabled)
+{
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+
+ /* SWITCHDEV_TRANS_PREPARE phase */
+ if ((!vlan_enabled) && (mlxsw_sp->master_bridge.dev == orig_dev)) {
+ netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mlxsw_sp_port_attr_set(struct net_device *dev,
const struct switchdev_attr *attr,
struct switchdev_trans *trans)
@@ -323,6 +339,11 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans,
attr->u.ageing_time);
break;
+ case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+ err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans,
+ attr->orig_dev,
+ attr->u.vlan_filtering);
+ break;
default:
err = -EOPNOTSUPP;
break;
@@ -505,8 +526,13 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
}
/* Changing activity bits only if HW operation succeded */
- for (vid = vid_begin; vid <= vid_end; vid++)
+ for (vid = vid_begin; vid <= vid_end; vid++) {
set_bit(vid, mlxsw_sp_port->active_vlans);
+ if (flag_untagged)
+ set_bit(vid, mlxsw_sp_port->untagged_vlans);
+ else
+ clear_bit(vid, mlxsw_sp_port->untagged_vlans);
+ }
/* STP state change must be done after we set active VLANs */
err = mlxsw_sp_port_stp_state_set(mlxsw_sp_port,
@@ -545,15 +571,15 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
- bool untagged_flag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
- bool pvid_flag = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+ bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+ bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
if (switchdev_trans_ph_prepare(trans))
return 0;
return __mlxsw_sp_port_vlans_add(mlxsw_sp_port,
vlan->vid_begin, vlan->vid_end,
- untagged_flag, pvid_flag);
+ flag_untagged, flag_pvid);
}
static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
@@ -933,6 +959,8 @@ static int mlxsw_sp_port_vlan_dump(struct mlxsw_sp_port *mlxsw_sp_port,
vlan->flags = 0;
if (vid == mlxsw_sp_port->pvid)
vlan->flags |= BRIDGE_VLAN_INFO_PVID;
+ if (test_bit(vid, mlxsw_sp_port->untagged_vlans))
+ vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
vlan->vid_begin = vid;
vlan->vid_end = vid;
err = cb(&vlan->obj);
@@ -1201,7 +1229,8 @@ int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port)
* with VID 1.
*/
mlxsw_sp_port->pvid = 1;
- err = __mlxsw_sp_port_vlans_del(mlxsw_sp_port, 0, VLAN_N_VID, true);
+ err = __mlxsw_sp_port_vlans_del(mlxsw_sp_port, 0, VLAN_N_VID - 1,
+ true);
if (err) {
netdev_err(dev, "Unable to init VLANs\n");
return err;