aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa/switch.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-02-22 14:53:32 -0500
committerDavid S. Miller <davem@davemloft.net>2019-02-22 14:53:32 -0500
commit2fce40a592daa92f1565152cb68d4c4ca7e97d52 (patch)
treeeaa11fe77005b43a576b173c4bf9a54ae2135f35 /net/dsa/switch.c
parent6d20faecc5949a305946559a38c89578e7d68264 (diff)
parent061f6a505ac33659eab007731c0f6374df39ab55 (diff)
Merge branch 'dsa-vlan'
Florian Fainelli says: ==================== net: dsa: VLAN devices w/ filtering This patch series supports having VLAN devices on top of DSA/switch ports while the switch has VLAN filtering globally turned on (as is the case with Broadcom switches). Whether the switch does global or per-port VLAN filtering, having VLAN entries for these VLAN devices is beneficial. We take care of a few possibly problematic cases: - adding a VLAN device while there is an existing VLAN entry created by a VLAN aware bridge. The entire bridge's VLAN database and not just the specific bridge port is being checked to be safe and conserative - adding a bridge VLAN entry when there is an existing VLAN device created is also not possible because that would lead to the bridge being able to manipulate the VLAN device's VID/attributes under its feet - enslaving a VLAN device into a VLAN aware bridge since that duplicates functionality already offered by the VLAN aware bridge Here are the different test cases that were run to exercise this: ip addr flush dev gphy ip link add dev br0 type bridge echo 1 > /sys/class/net/br0/bridge/vlan_filtering ip link set dev gphy master br0 udhcpc -i br0 vconfig add rgmii_1 100 ifconfig rgmii_1.100 192.168.100.10 ping -c 2 192.168.100.1 vconfig add br0 42 bridge vlan add vid 42 dev gphy bridge vlan add vid 42 dev br0 self ifconfig br0.42 192.168.42.2 ping -c 2 192.168.42.1 ip link del rgmii_1.100 vconfig add rgmii_1 100 ifconfig rgmii_1.100 192.168.100.10 ping -c 2 192.168.100.1 echo 0 > /sys/class/net/br0/bridge/vlan_filtering ping -c 2 192.168.100.1 ip link del rgmii_1.100 echo 1 > /sys/class/net/br0/bridge/vlan_filtering vconfig add rgmii_1 100 brctl addif br0 rgmii_1 bridge vlan add vid 100 dev rgmii_1 vconfig rem rgmii_1.100 bridge vlan add vid 100 dev rgmii_1 vconfig add rgmii_1 100 bridge vlan del vid 100 dev rgmii_1 vconfig add rgmii_1 100 brctl addif br0 rgmii_1.100 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa/switch.c')
-rw-r--r--net/dsa/switch.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index 142b294d3446..e1fae969aa73 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -12,6 +12,7 @@
12 12
13#include <linux/netdevice.h> 13#include <linux/netdevice.h>
14#include <linux/notifier.h> 14#include <linux/notifier.h>
15#include <linux/if_vlan.h>
15#include <net/switchdev.h> 16#include <net/switchdev.h>
16 17
17#include "dsa_priv.h" 18#include "dsa_priv.h"
@@ -168,6 +169,43 @@ static int dsa_switch_mdb_del(struct dsa_switch *ds,
168 return 0; 169 return 0;
169} 170}
170 171
172static int dsa_port_vlan_device_check(struct net_device *vlan_dev,
173 int vlan_dev_vid,
174 void *arg)
175{
176 struct switchdev_obj_port_vlan *vlan = arg;
177 u16 vid;
178
179 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
180 if (vid == vlan_dev_vid)
181 return -EBUSY;
182 }
183
184 return 0;
185}
186
187static int dsa_port_vlan_check(struct dsa_switch *ds, int port,
188 const struct switchdev_obj_port_vlan *vlan)
189{
190 const struct dsa_port *dp = dsa_to_port(ds, port);
191 int err = 0;
192
193 /* Device is not bridged, let it proceed with the VLAN device
194 * creation.
195 */
196 if (!dp->bridge_dev)
197 return err;
198
199 /* dsa_slave_vlan_rx_{add,kill}_vid() cannot use the prepare pharse and
200 * already checks whether there is an overlapping bridge VLAN entry
201 * with the same VID, so here we only need to check that if we are
202 * adding a bridge VLAN entry there is not an overlapping VLAN device
203 * claiming that VID.
204 */
205 return vlan_for_each(dp->slave, dsa_port_vlan_device_check,
206 (void *)vlan);
207}
208
171static int 209static int
172dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds, 210dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds,
173 const struct switchdev_obj_port_vlan *vlan, 211 const struct switchdev_obj_port_vlan *vlan,
@@ -179,6 +217,10 @@ dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds,
179 return -EOPNOTSUPP; 217 return -EOPNOTSUPP;
180 218
181 for_each_set_bit(port, bitmap, ds->num_ports) { 219 for_each_set_bit(port, bitmap, ds->num_ports) {
220 err = dsa_port_vlan_check(ds, port, vlan);
221 if (err)
222 return err;
223
182 err = ds->ops->port_vlan_prepare(ds, port, vlan); 224 err = ds->ops->port_vlan_prepare(ds, port, vlan);
183 if (err) 225 if (err)
184 return err; 226 return err;