aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dsa/port.c12
-rw-r--r--net/dsa/slave.c110
-rw-r--r--net/dsa/switch.c42
3 files changed, 157 insertions, 7 deletions
diff --git a/net/dsa/port.c b/net/dsa/port.c
index e9b5b50f8cf1..c011dff523d0 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -291,7 +291,10 @@ int dsa_port_vlan_add(struct dsa_port *dp,
291 .vlan = vlan, 291 .vlan = vlan,
292 }; 292 };
293 293
294 if (br_vlan_enabled(dp->bridge_dev)) 294 /* Can be called from dsa_slave_port_obj_add() or
295 * dsa_slave_vlan_rx_add_vid()
296 */
297 if (!dp->bridge_dev || br_vlan_enabled(dp->bridge_dev))
295 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); 298 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info);
296 299
297 return 0; 300 return 0;
@@ -306,10 +309,13 @@ int dsa_port_vlan_del(struct dsa_port *dp,
306 .vlan = vlan, 309 .vlan = vlan,
307 }; 310 };
308 311
309 if (netif_is_bridge_master(vlan->obj.orig_dev)) 312 if (vlan->obj.orig_dev && netif_is_bridge_master(vlan->obj.orig_dev))
310 return -EOPNOTSUPP; 313 return -EOPNOTSUPP;
311 314
312 if (br_vlan_enabled(dp->bridge_dev)) 315 /* Can be called from dsa_slave_port_obj_del() or
316 * dsa_slave_vlan_rx_kill_vid()
317 */
318 if (!dp->bridge_dev || br_vlan_enabled(dp->bridge_dev))
313 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); 319 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
314 320
315 return 0; 321 return 0;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index a78b2bba0332..90629b12beaf 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -983,6 +983,72 @@ static int dsa_slave_get_ts_info(struct net_device *dev,
983 return ds->ops->get_ts_info(ds, p->dp->index, ts); 983 return ds->ops->get_ts_info(ds, p->dp->index, ts);
984} 984}
985 985
986static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
987 u16 vid)
988{
989 struct dsa_port *dp = dsa_slave_to_port(dev);
990 struct switchdev_obj_port_vlan vlan = {
991 .vid_begin = vid,
992 .vid_end = vid,
993 /* This API only allows programming tagged, non-PVID VIDs */
994 .flags = 0,
995 };
996 struct bridge_vlan_info info;
997 int ret;
998
999 /* Check for a possible bridge VLAN entry now since there is no
1000 * need to emulate the switchdev prepare + commit phase.
1001 */
1002 if (dp->bridge_dev) {
1003 /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
1004 * device, respectively the VID is not found, returning
1005 * 0 means success, which is a failure for us here.
1006 */
1007 ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
1008 if (ret == 0)
1009 return -EBUSY;
1010 }
1011
1012 ret = dsa_port_vlan_add(dp, &vlan, NULL);
1013 if (ret == -EOPNOTSUPP)
1014 ret = 0;
1015
1016 return ret;
1017}
1018
1019static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
1020 u16 vid)
1021{
1022 struct dsa_port *dp = dsa_slave_to_port(dev);
1023 struct switchdev_obj_port_vlan vlan = {
1024 .vid_begin = vid,
1025 .vid_end = vid,
1026 /* This API only allows programming tagged, non-PVID VIDs */
1027 .flags = 0,
1028 };
1029 struct bridge_vlan_info info;
1030 int ret;
1031
1032 /* Check for a possible bridge VLAN entry now since there is no
1033 * need to emulate the switchdev prepare + commit phase.
1034 */
1035 if (dp->bridge_dev) {
1036 /* br_vlan_get_info() returns -EINVAL or -ENOENT if the
1037 * device, respectively the VID is not found, returning
1038 * 0 means success, which is a failure for us here.
1039 */
1040 ret = br_vlan_get_info(dp->bridge_dev, vid, &info);
1041 if (ret == 0)
1042 return -EBUSY;
1043 }
1044
1045 ret = dsa_port_vlan_del(dp, &vlan);
1046 if (ret == -EOPNOTSUPP)
1047 ret = 0;
1048
1049 return ret;
1050}
1051
986static const struct ethtool_ops dsa_slave_ethtool_ops = { 1052static const struct ethtool_ops dsa_slave_ethtool_ops = {
987 .get_drvinfo = dsa_slave_get_drvinfo, 1053 .get_drvinfo = dsa_slave_get_drvinfo,
988 .get_regs_len = dsa_slave_get_regs_len, 1054 .get_regs_len = dsa_slave_get_regs_len,
@@ -1048,6 +1114,8 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
1048 .ndo_setup_tc = dsa_slave_setup_tc, 1114 .ndo_setup_tc = dsa_slave_setup_tc,
1049 .ndo_get_stats64 = dsa_slave_get_stats64, 1115 .ndo_get_stats64 = dsa_slave_get_stats64,
1050 .ndo_get_port_parent_id = dsa_slave_get_port_parent_id, 1116 .ndo_get_port_parent_id = dsa_slave_get_port_parent_id,
1117 .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid,
1118 .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
1051}; 1119};
1052 1120
1053static const struct switchdev_ops dsa_slave_switchdev_ops = { 1121static const struct switchdev_ops dsa_slave_switchdev_ops = {
@@ -1307,7 +1375,8 @@ int dsa_slave_create(struct dsa_port *port)
1307 if (slave_dev == NULL) 1375 if (slave_dev == NULL)
1308 return -ENOMEM; 1376 return -ENOMEM;
1309 1377
1310 slave_dev->features = master->vlan_features | NETIF_F_HW_TC; 1378 slave_dev->features = master->vlan_features | NETIF_F_HW_TC |
1379 NETIF_F_HW_VLAN_CTAG_FILTER;
1311 slave_dev->hw_features |= NETIF_F_HW_TC; 1380 slave_dev->hw_features |= NETIF_F_HW_TC;
1312 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops; 1381 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
1313 eth_hw_addr_inherit(slave_dev, master); 1382 eth_hw_addr_inherit(slave_dev, master);
@@ -1408,16 +1477,49 @@ static int dsa_slave_changeupper(struct net_device *dev,
1408 return err; 1477 return err;
1409} 1478}
1410 1479
1480static int dsa_slave_upper_vlan_check(struct net_device *dev,
1481 struct netdev_notifier_changeupper_info *
1482 info)
1483{
1484 struct netlink_ext_ack *ext_ack;
1485 struct net_device *slave;
1486 struct dsa_port *dp;
1487
1488 ext_ack = netdev_notifier_info_to_extack(&info->info);
1489
1490 if (!is_vlan_dev(dev))
1491 return NOTIFY_DONE;
1492
1493 slave = vlan_dev_real_dev(dev);
1494 if (!dsa_slave_dev_check(slave))
1495 return NOTIFY_DONE;
1496
1497 dp = dsa_slave_to_port(slave);
1498 if (!dp->bridge_dev)
1499 return NOTIFY_DONE;
1500
1501 /* Deny enslaving a VLAN device into a VLAN-aware bridge */
1502 if (br_vlan_enabled(dp->bridge_dev) &&
1503 netif_is_bridge_master(info->upper_dev) && info->linking) {
1504 NL_SET_ERR_MSG_MOD(ext_ack,
1505 "Cannot enslave VLAN device into VLAN aware bridge");
1506 return notifier_from_errno(-EINVAL);
1507 }
1508
1509 return NOTIFY_DONE;
1510}
1511
1411static int dsa_slave_netdevice_event(struct notifier_block *nb, 1512static int dsa_slave_netdevice_event(struct notifier_block *nb,
1412 unsigned long event, void *ptr) 1513 unsigned long event, void *ptr)
1413{ 1514{
1414 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 1515 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1415 1516
1416 if (!dsa_slave_dev_check(dev)) 1517 if (event == NETDEV_CHANGEUPPER) {
1417 return NOTIFY_DONE; 1518 if (!dsa_slave_dev_check(dev))
1519 return dsa_slave_upper_vlan_check(dev, ptr);
1418 1520
1419 if (event == NETDEV_CHANGEUPPER)
1420 return dsa_slave_changeupper(dev, ptr); 1521 return dsa_slave_changeupper(dev, ptr);
1522 }
1421 1523
1422 return NOTIFY_DONE; 1524 return NOTIFY_DONE;
1423} 1525}
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;