Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f637941b authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 00ce3a15 fc1273af
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
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);
}
+1 −0
Original line number Diff line number Diff line
@@ -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;
};
+34 −5
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ enum switchdev_attr_id {
	SWITCHDEV_ATTR_ID_PORT_STP_STATE,
	SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS,
	SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
	SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING,
};

struct switchdev_attr {
@@ -58,6 +59,7 @@ struct switchdev_attr {
		u8 stp_state;				/* PORT_STP_STATE */
		unsigned long brport_flags;		/* PORT_BRIDGE_FLAGS */
		u32 ageing_time;			/* BRIDGE_AGEING_TIME */
		bool vlan_filtering;			/* BRIDGE_VLAN_FILTERING */
	} u;
};

+10 −1
Original line number Diff line number Diff line
@@ -511,8 +511,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
	if (br_fdb_insert(br, p, dev->dev_addr, 0))
		netdev_err(dev, "failed insert local address bridge forwarding table\n");

	if (nbp_vlan_init(p))
	err = nbp_vlan_init(p);
	if (err) {
		netdev_err(dev, "failed to initialize vlan filtering on this port\n");
		goto err6;
	}

	spin_lock_bh(&br->lock);
	changed_addr = br_stp_recalculate_bridge_id(br);
@@ -533,6 +536,12 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)

	return 0;

err6:
	list_del_rcu(&p->list);
	br_fdb_delete_by_port(br, p, 0, 1);
	nbp_update_port_count(br);
	netdev_upper_dev_unlink(dev, br->dev);

err5:
	dev->priv_flags &= ~IFF_BRIDGE_PORT;
	netdev_rx_handler_unregister(dev);
Loading