From fd364541319749c9880bf3ad613eac80fc6ea91e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:36 -0400 Subject: [PATCH 01/20] net: dsa: change scope of STP state setter Instead of having multiple STP state helpers scoping a slave device supporting both the DSA logic and the switchdev binding, provide a single dsa_port_set_state helper scoping a DSA port, as well as its dsa_port_set_state_now wrapper which skips the prepare phase. This allows us to better separate the DSA logic from the slave device handling. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 91236d602301..403d1dfe7f50 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -85,13 +85,15 @@ static inline bool dsa_port_is_bridged(struct dsa_port *dp) return !!dp->bridge_dev; } -static void dsa_slave_set_state(struct net_device *dev, u8 state) +static int dsa_port_set_state(struct dsa_port *dp, u8 state, + struct switchdev_trans *trans) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_port *dp = p->dp; struct dsa_switch *ds = dp->ds; int port = dp->index; + if (switchdev_trans_ph_prepare(trans)) + return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; + if (ds->ops->port_stp_state_set) ds->ops->port_stp_state_set(ds, port, state); @@ -110,6 +112,17 @@ static void dsa_slave_set_state(struct net_device *dev, u8 state) } dp->stp_state = state; + + return 0; +} + +static void dsa_port_set_state_now(struct dsa_port *dp, u8 state) +{ + int err; + + err = dsa_port_set_state(dp, state, NULL); + if (err) + pr_err("DSA: failed to set STP state %u (%d)\n", state, err); } static int dsa_slave_open(struct net_device *dev) @@ -147,7 +160,7 @@ static int dsa_slave_open(struct net_device *dev) goto clear_promisc; } - dsa_slave_set_state(dev, stp_state); + dsa_port_set_state_now(p->dp, stp_state); if (p->phy) phy_start(p->phy); @@ -189,7 +202,7 @@ static int dsa_slave_close(struct net_device *dev) if (ds->ops->port_disable) ds->ops->port_disable(ds, p->dp->index, p->phy); - dsa_slave_set_state(dev, BR_STATE_DISABLED); + dsa_port_set_state_now(p->dp, BR_STATE_DISABLED); return 0; } @@ -386,21 +399,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } -static int dsa_slave_stp_state_set(struct net_device *dev, - const struct switchdev_attr *attr, - struct switchdev_trans *trans) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; - - if (switchdev_trans_ph_prepare(trans)) - return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; - - dsa_slave_set_state(dev, attr->u.stp_state); - - return 0; -} - static int dsa_slave_vlan_filtering(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) @@ -465,11 +463,13 @@ static int dsa_slave_port_attr_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) { + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_port *dp = p->dp; int ret; switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: - ret = dsa_slave_stp_state_set(dev, attr, trans); + ret = dsa_port_set_state(dp, attr->u.stp_state, trans); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: ret = dsa_slave_vlan_filtering(dev, attr, trans); @@ -621,7 +621,7 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev, /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional */ - dsa_slave_set_state(dev, BR_STATE_FORWARDING); + dsa_port_set_state_now(p->dp, BR_STATE_FORWARDING); } static int dsa_slave_port_attr_get(struct net_device *dev, From a93ecdd9484a51e830249ee9877ac1c1544e75ac Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:37 -0400 Subject: [PATCH 02/20] net: dsa: change scope of notifier call chain Change the scope of the fabric notification helper from the DSA slave to the DSA port, since this is a DSA layer specific notion, that can be used by non-slave ports (CPU and DSA). Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 403d1dfe7f50..371f6d267917 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -27,10 +27,9 @@ static bool dsa_slave_dev_check(struct net_device *dev); -static int dsa_slave_notify(struct net_device *dev, unsigned long e, void *v) +static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct raw_notifier_head *nh = &p->dp->ds->dst->nh; + struct raw_notifier_head *nh = &dp->ds->dst->nh; int err; err = raw_notifier_call_chain(nh, e, v); @@ -589,7 +588,7 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, */ p->dp->bridge_dev = br; - err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_JOIN, &info); + err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); /* The bridging is rolled back on error */ if (err) @@ -614,7 +613,7 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev, */ p->dp->bridge_dev = NULL; - err = dsa_slave_notify(dev, DSA_NOTIFIER_BRIDGE_LEAVE, &info); + err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); if (err) netdev_err(dev, "failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); From 17d7802b7772ddcf505581fe22cffcd2e8b5120e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:38 -0400 Subject: [PATCH 03/20] net: dsa: change scope of bridging code Now that the bridge join and leave functions only deal with a DSA port, change their scope from the DSA slave net_device to the DSA generic dsa_port. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 371f6d267917..1ad62ef8c261 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -572,13 +572,11 @@ static int dsa_slave_port_obj_dump(struct net_device *dev, return err; } -static int dsa_slave_bridge_port_join(struct net_device *dev, - struct net_device *br) +static int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) { - struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_notifier_bridge_info info = { - .sw_index = p->dp->ds->index, - .port = p->dp->index, + .sw_index = dp->ds->index, + .port = dp->index, .br = br, }; int err; @@ -586,24 +584,22 @@ static int dsa_slave_bridge_port_join(struct net_device *dev, /* Here the port is already bridged. Reflect the current configuration * so that drivers can program their chips accordingly. */ - p->dp->bridge_dev = br; + dp->bridge_dev = br; - err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); + err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); /* The bridging is rolled back on error */ if (err) - p->dp->bridge_dev = NULL; + dp->bridge_dev = NULL; return err; } -static void dsa_slave_bridge_port_leave(struct net_device *dev, - struct net_device *br) +static void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) { - struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_notifier_bridge_info info = { - .sw_index = p->dp->ds->index, - .port = p->dp->index, + .sw_index = dp->ds->index, + .port = dp->index, .br = br, }; int err; @@ -611,16 +607,16 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev, /* Here the port is already unbridged. Reflect the current configuration * so that drivers can program their chips accordingly. */ - p->dp->bridge_dev = NULL; + dp->bridge_dev = NULL; - err = dsa_port_notify(p->dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); + err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); if (err) - netdev_err(dev, "failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); + pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional */ - dsa_port_set_state_now(p->dp, BR_STATE_FORWARDING); + dsa_port_set_state_now(dp, BR_STATE_FORWARDING); } static int dsa_slave_port_attr_get(struct net_device *dev, @@ -1526,14 +1522,16 @@ static bool dsa_slave_dev_check(struct net_device *dev) static int dsa_slave_changeupper(struct net_device *dev, struct netdev_notifier_changeupper_info *info) { + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_port *dp = p->dp; int err = NOTIFY_DONE; if (netif_is_bridge_master(info->upper_dev)) { if (info->linking) { - err = dsa_slave_bridge_port_join(dev, info->upper_dev); + err = dsa_port_bridge_join(dp, info->upper_dev); err = notifier_from_errno(err); } else { - dsa_slave_bridge_port_leave(dev, info->upper_dev); + dsa_port_bridge_leave(dp, info->upper_dev); err = NOTIFY_OK; } } From 3fdb023b5e2bad17d0b66e8903de6e38b0c16ca2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:39 -0400 Subject: [PATCH 04/20] net: dsa: change scope of FDB handlers Change the scope of the switchdev FDB object handlers from the DSA slave device to the generic DSA port, so that the future port-wide API can also be used for other port types, such as CPU and DSA links. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 1ad62ef8c261..e9c3ea09cc09 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -299,47 +299,44 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, return -EOPNOTSUPP; } -static int dsa_slave_port_fdb_add(struct net_device *dev, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) +static int dsa_port_fdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (switchdev_trans_ph_prepare(trans)) { if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add) return -EOPNOTSUPP; - return ds->ops->port_fdb_prepare(ds, p->dp->index, fdb, trans); + return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans); } - ds->ops->port_fdb_add(ds, p->dp->index, fdb, trans); + ds->ops->port_fdb_add(ds, dp->index, fdb, trans); return 0; } -static int dsa_slave_port_fdb_del(struct net_device *dev, - const struct switchdev_obj_port_fdb *fdb) +static int dsa_port_fdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_fdb *fdb) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; int ret = -EOPNOTSUPP; if (ds->ops->port_fdb_del) - ret = ds->ops->port_fdb_del(ds, p->dp->index, fdb); + ret = ds->ops->port_fdb_del(ds, dp->index, fdb); return ret; } -static int dsa_slave_port_fdb_dump(struct net_device *dev, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) +static int dsa_port_fdb_dump(struct dsa_port *dp, + struct switchdev_obj_port_fdb *fdb, + switchdev_obj_dump_cb_t *cb) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (ds->ops->port_fdb_dump) - return ds->ops->port_fdb_dump(ds, p->dp->index, fdb, cb); + return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb); return -EOPNOTSUPP; } @@ -488,6 +485,8 @@ static int dsa_slave_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans) { + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_port *dp = p->dp; int err; /* For the prepare phase, ensure the full set of changes is feasable in @@ -497,9 +496,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev, switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = dsa_slave_port_fdb_add(dev, - SWITCHDEV_OBJ_PORT_FDB(obj), - trans); + err = dsa_port_fdb_add(dp, SWITCHDEV_OBJ_PORT_FDB(obj), trans); break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj), @@ -521,12 +518,13 @@ static int dsa_slave_port_obj_add(struct net_device *dev, static int dsa_slave_port_obj_del(struct net_device *dev, const struct switchdev_obj *obj) { + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_port *dp = p->dp; int err; switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = dsa_slave_port_fdb_del(dev, - SWITCHDEV_OBJ_PORT_FDB(obj)); + err = dsa_port_fdb_del(dp, SWITCHDEV_OBJ_PORT_FDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); @@ -547,13 +545,13 @@ static int dsa_slave_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) { + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_port *dp = p->dp; int err; switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = dsa_slave_port_fdb_dump(dev, - SWITCHDEV_OBJ_PORT_FDB(obj), - cb); + err = dsa_port_fdb_dump(dp, SWITCHDEV_OBJ_PORT_FDB(obj), cb); break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_slave_port_mdb_dump(dev, SWITCHDEV_OBJ_PORT_MDB(obj), From bcebb976ec433e1f8a81d1a70db26420e85386aa Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:40 -0400 Subject: [PATCH 05/20] net: dsa: change scope of MDB handlers Change the scope of the switchdev MDB object handlers from the DSA slave device to the generic DSA port, so that the future port-wide API can also be used for other port types, such as CPU and DSA links. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index e9c3ea09cc09..0921d306aedf 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -341,46 +341,43 @@ static int dsa_port_fdb_dump(struct dsa_port *dp, return -EOPNOTSUPP; } -static int dsa_slave_port_mdb_add(struct net_device *dev, - const struct switchdev_obj_port_mdb *mdb, - struct switchdev_trans *trans) +static int dsa_port_mdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (switchdev_trans_ph_prepare(trans)) { if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) return -EOPNOTSUPP; - return ds->ops->port_mdb_prepare(ds, p->dp->index, mdb, trans); + return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans); } - ds->ops->port_mdb_add(ds, p->dp->index, mdb, trans); + ds->ops->port_mdb_add(ds, dp->index, mdb, trans); return 0; } -static int dsa_slave_port_mdb_del(struct net_device *dev, - const struct switchdev_obj_port_mdb *mdb) +static int dsa_port_mdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (ds->ops->port_mdb_del) - return ds->ops->port_mdb_del(ds, p->dp->index, mdb); + return ds->ops->port_mdb_del(ds, dp->index, mdb); return -EOPNOTSUPP; } -static int dsa_slave_port_mdb_dump(struct net_device *dev, - struct switchdev_obj_port_mdb *mdb, - switchdev_obj_dump_cb_t *cb) +static int dsa_port_mdb_dump(struct dsa_port *dp, + struct switchdev_obj_port_mdb *mdb, + switchdev_obj_dump_cb_t *cb) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (ds->ops->port_mdb_dump) - return ds->ops->port_mdb_dump(ds, p->dp->index, mdb, cb); + return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb); return -EOPNOTSUPP; } @@ -499,8 +496,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev, err = dsa_port_fdb_add(dp, SWITCHDEV_OBJ_PORT_FDB(obj), trans); break; case SWITCHDEV_OBJ_ID_PORT_MDB: - err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj), - trans); + err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_port_vlan_add(dev, @@ -527,7 +523,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev, err = dsa_port_fdb_del(dp, SWITCHDEV_OBJ_PORT_FDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_MDB: - err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); + err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_port_vlan_del(dev, @@ -554,8 +550,7 @@ static int dsa_slave_port_obj_dump(struct net_device *dev, err = dsa_port_fdb_dump(dp, SWITCHDEV_OBJ_PORT_FDB(obj), cb); break; case SWITCHDEV_OBJ_ID_PORT_MDB: - err = dsa_slave_port_mdb_dump(dev, SWITCHDEV_OBJ_PORT_MDB(obj), - cb); + err = dsa_port_mdb_dump(dp, SWITCHDEV_OBJ_PORT_MDB(obj), cb); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_port_vlan_dump(dev, From 01676d129c1a7645879a104cbe5ac43bfa3c25a4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:41 -0400 Subject: [PATCH 06/20] net: dsa: change scope of VLAN handlers Change the scope of the switchdev VLAN object handlers from the DSA slave device to the generic DSA port, so that the future port-wide API can also be used for other port types, such as CPU and DSA links. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0921d306aedf..de39da69fd33 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -254,12 +254,10 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a) return 0; } -static int dsa_slave_port_vlan_add(struct net_device *dev, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) +static int dsa_port_vlan_add(struct dsa_port *dp, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_port *dp = p->dp; struct dsa_switch *ds = dp->ds; if (switchdev_trans_ph_prepare(trans)) { @@ -274,27 +272,25 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, return 0; } -static int dsa_slave_port_vlan_del(struct net_device *dev, - const struct switchdev_obj_port_vlan *vlan) +static int dsa_port_vlan_del(struct dsa_port *dp, + const struct switchdev_obj_port_vlan *vlan) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (!ds->ops->port_vlan_del) return -EOPNOTSUPP; - return ds->ops->port_vlan_del(ds, p->dp->index, vlan); + return ds->ops->port_vlan_del(ds, dp->index, vlan); } -static int dsa_slave_port_vlan_dump(struct net_device *dev, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) +static int dsa_port_vlan_dump(struct dsa_port *dp, + struct switchdev_obj_port_vlan *vlan, + switchdev_obj_dump_cb_t *cb) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; if (ds->ops->port_vlan_dump) - return ds->ops->port_vlan_dump(ds, p->dp->index, vlan, cb); + return ds->ops->port_vlan_dump(ds, dp->index, vlan, cb); return -EOPNOTSUPP; } @@ -499,9 +495,8 @@ static int dsa_slave_port_obj_add(struct net_device *dev, err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dsa_slave_port_vlan_add(dev, - SWITCHDEV_OBJ_PORT_VLAN(obj), - trans); + err = dsa_port_vlan_add(dp, SWITCHDEV_OBJ_PORT_VLAN(obj), + trans); break; default: err = -EOPNOTSUPP; @@ -526,8 +521,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev, err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dsa_slave_port_vlan_del(dev, - SWITCHDEV_OBJ_PORT_VLAN(obj)); + err = dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; default: err = -EOPNOTSUPP; @@ -553,9 +547,7 @@ static int dsa_slave_port_obj_dump(struct net_device *dev, err = dsa_port_mdb_dump(dp, SWITCHDEV_OBJ_PORT_MDB(obj), cb); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dsa_slave_port_vlan_dump(dev, - SWITCHDEV_OBJ_PORT_VLAN(obj), - cb); + err = dsa_port_vlan_dump(dp, SWITCHDEV_OBJ_PORT_VLAN(obj), cb); break; default: err = -EOPNOTSUPP; From c02c4175cb9f434af8f20045dd43ae9e573c8da2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:42 -0400 Subject: [PATCH 07/20] net: dsa: change scope of VLAN filtering setter Change the scope of the switchdev VLAN filtering attribute setter from the DSA slave device to the generic DSA port, so that the future port-wide API can also be used for other port types, such as CPU and DSA links. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index de39da69fd33..216eb38a847d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -388,20 +388,18 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } -static int dsa_slave_vlan_filtering(struct net_device *dev, - const struct switchdev_attr *attr, - struct switchdev_trans *trans) +static int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, + struct switchdev_trans *trans) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; + struct dsa_switch *ds = dp->ds; /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ if (switchdev_trans_ph_prepare(trans)) return 0; if (ds->ops->port_vlan_filtering) - return ds->ops->port_vlan_filtering(ds, p->dp->index, - attr->u.vlan_filtering); + return ds->ops->port_vlan_filtering(ds, dp->index, + vlan_filtering); return 0; } @@ -461,7 +459,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev, ret = dsa_port_set_state(dp, attr->u.stp_state, trans); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: - ret = dsa_slave_vlan_filtering(dev, attr, trans); + ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, + trans); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: ret = dsa_slave_ageing_time(dev, attr, trans); From 072bb1903a0ff810c6091d2f6bf7c80e76dab0e6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:43 -0400 Subject: [PATCH 08/20] net: dsa: change scope of ageing time setter Change the scope of the switchdev bridge ageing time attribute setter from the DSA slave device to the generic DSA port, so that the future port-wide API can also be used for other port types, such as CPU and DSA links. Also ds->ports is now a contiguous array of dsa_port structures, thus their addresses cannot be NULL. Remove the useless check in dsa_fastest_ageing_time. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 216eb38a847d..b0150f79dcdd 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -412,21 +412,19 @@ static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds, for (i = 0; i < ds->num_ports; ++i) { struct dsa_port *dp = &ds->ports[i]; - if (dp && dp->ageing_time && dp->ageing_time < ageing_time) + if (dp->ageing_time && dp->ageing_time < ageing_time) ageing_time = dp->ageing_time; } return ageing_time; } -static int dsa_slave_ageing_time(struct net_device *dev, - const struct switchdev_attr *attr, - struct switchdev_trans *trans) +static int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, + struct switchdev_trans *trans) { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->dp->ds; - unsigned long ageing_jiffies = clock_t_to_jiffies(attr->u.ageing_time); + unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); + struct dsa_switch *ds = dp->ds; if (switchdev_trans_ph_prepare(trans)) { if (ds->ageing_time_min && ageing_time < ds->ageing_time_min) @@ -437,7 +435,7 @@ static int dsa_slave_ageing_time(struct net_device *dev, } /* Keep the fastest ageing time in case of multiple bridges */ - p->dp->ageing_time = ageing_time; + dp->ageing_time = ageing_time; ageing_time = dsa_fastest_ageing_time(ds, ageing_time); if (ds->ops->set_ageing_time) @@ -463,7 +461,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev, trans); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: - ret = dsa_slave_ageing_time(dev, attr, trans); + ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans); break; default: ret = -EOPNOTSUPP; From a40c175b4a4a2c6f7e111ed6dc0186c75287dff0 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:44 -0400 Subject: [PATCH 09/20] net: dsa: move port state setters Add a new port.c file to hold all DSA port-wide logic. This patch moves in the code which sets a port state. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/Makefile | 2 +- net/dsa/dsa_priv.h | 5 +++++ net/dsa/port.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 40 --------------------------------- 4 files changed, 61 insertions(+), 41 deletions(-) create mode 100644 net/dsa/port.c diff --git a/net/dsa/Makefile b/net/dsa/Makefile index f8c0251d1f43..90e5aa6f7d0f 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile @@ -1,6 +1,6 @@ # the core obj-$(CONFIG_NET_DSA) += dsa_core.o -dsa_core-y += dsa.o slave.o dsa2.o switch.o legacy.o +dsa_core-y += dsa.o dsa2.o legacy.o port.o slave.o switch.o # tagging formats dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index c274130e3ac9..cda218cd9b05 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -60,6 +60,11 @@ void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds); int dsa_legacy_register(void); void dsa_legacy_unregister(void); +/* port.c */ +int dsa_port_set_state(struct dsa_port *dp, u8 state, + struct switchdev_trans *trans); +void dsa_port_set_state_now(struct dsa_port *dp, u8 state); + /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; void dsa_slave_mii_bus_init(struct dsa_switch *ds); diff --git a/net/dsa/port.c b/net/dsa/port.c new file mode 100644 index 000000000000..6cc4704190fd --- /dev/null +++ b/net/dsa/port.c @@ -0,0 +1,55 @@ +/* + * Handling of a single switch port + * + * Copyright (c) 2017 Savoir-faire Linux Inc. + * Vivien Didelot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "dsa_priv.h" + +int dsa_port_set_state(struct dsa_port *dp, u8 state, + struct switchdev_trans *trans) +{ + struct dsa_switch *ds = dp->ds; + int port = dp->index; + + if (switchdev_trans_ph_prepare(trans)) + return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; + + if (ds->ops->port_stp_state_set) + ds->ops->port_stp_state_set(ds, port, state); + + if (ds->ops->port_fast_age) { + /* Fast age FDB entries or flush appropriate forwarding database + * for the given port, if we are moving it from Learning or + * Forwarding state, to Disabled or Blocking or Listening state. + */ + + if ((dp->stp_state == BR_STATE_LEARNING || + dp->stp_state == BR_STATE_FORWARDING) && + (state == BR_STATE_DISABLED || + state == BR_STATE_BLOCKING || + state == BR_STATE_LISTENING)) + ds->ops->port_fast_age(ds, port); + } + + dp->stp_state = state; + + return 0; +} + +void dsa_port_set_state_now(struct dsa_port *dp, u8 state) +{ + int err; + + err = dsa_port_set_state(dp, state, NULL); + if (err) + pr_err("DSA: failed to set STP state %u (%d)\n", state, err); +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index b0150f79dcdd..2c57c7205aa3 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -84,46 +84,6 @@ static inline bool dsa_port_is_bridged(struct dsa_port *dp) return !!dp->bridge_dev; } -static int dsa_port_set_state(struct dsa_port *dp, u8 state, - struct switchdev_trans *trans) -{ - struct dsa_switch *ds = dp->ds; - int port = dp->index; - - if (switchdev_trans_ph_prepare(trans)) - return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; - - if (ds->ops->port_stp_state_set) - ds->ops->port_stp_state_set(ds, port, state); - - if (ds->ops->port_fast_age) { - /* Fast age FDB entries or flush appropriate forwarding database - * for the given port, if we are moving it from Learning or - * Forwarding state, to Disabled or Blocking or Listening state. - */ - - if ((dp->stp_state == BR_STATE_LEARNING || - dp->stp_state == BR_STATE_FORWARDING) && - (state == BR_STATE_DISABLED || - state == BR_STATE_BLOCKING || - state == BR_STATE_LISTENING)) - ds->ops->port_fast_age(ds, port); - } - - dp->stp_state = state; - - return 0; -} - -static void dsa_port_set_state_now(struct dsa_port *dp, u8 state) -{ - int err; - - err = dsa_port_set_state(dp, state, NULL); - if (err) - pr_err("DSA: failed to set STP state %u (%d)\n", state, err); -} - static int dsa_slave_open(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); From cfbed329beb2e44562c2c6b292142e3c9adc3203 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:45 -0400 Subject: [PATCH 10/20] net: dsa: move bridging routines Move the DSA port code which bridges a port in port.c, where it belongs. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 2 ++ net/dsa/port.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 57 --------------------------------------------- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index cda218cd9b05..f0b6cd3c8a65 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -64,6 +64,8 @@ void dsa_legacy_unregister(void); int dsa_port_set_state(struct dsa_port *dp, u8 state, struct switchdev_trans *trans); void dsa_port_set_state_now(struct dsa_port *dp, u8 state); +int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br); +void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index 6cc4704190fd..da8577fb3d07 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -11,9 +11,20 @@ */ #include +#include #include "dsa_priv.h" +static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v) +{ + struct raw_notifier_head *nh = &dp->ds->dst->nh; + int err; + + err = raw_notifier_call_chain(nh, e, v); + + return notifier_to_errno(err); +} + int dsa_port_set_state(struct dsa_port *dp, u8 state, struct switchdev_trans *trans) { @@ -53,3 +64,50 @@ void dsa_port_set_state_now(struct dsa_port *dp, u8 state) if (err) pr_err("DSA: failed to set STP state %u (%d)\n", state, err); } + +int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) +{ + struct dsa_notifier_bridge_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .br = br, + }; + int err; + + /* Here the port is already bridged. Reflect the current configuration + * so that drivers can program their chips accordingly. + */ + dp->bridge_dev = br; + + err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); + + /* The bridging is rolled back on error */ + if (err) + dp->bridge_dev = NULL; + + return err; +} + +void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) +{ + struct dsa_notifier_bridge_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .br = br, + }; + int err; + + /* Here the port is already unbridged. Reflect the current configuration + * so that drivers can program their chips accordingly. + */ + dp->bridge_dev = NULL; + + err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); + if (err) + pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); + + /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, + * so allow it to be in BR_STATE_FORWARDING to be kept functional + */ + dsa_port_set_state_now(dp, BR_STATE_FORWARDING); +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 2c57c7205aa3..ab298c41b8e7 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -27,16 +27,6 @@ static bool dsa_slave_dev_check(struct net_device *dev); -static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v) -{ - struct raw_notifier_head *nh = &dp->ds->dst->nh; - int err; - - err = raw_notifier_call_chain(nh, e, v); - - return notifier_to_errno(err); -} - /* slave mii_bus handling ***************************************************/ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { @@ -514,53 +504,6 @@ static int dsa_slave_port_obj_dump(struct net_device *dev, return err; } -static int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) -{ - struct dsa_notifier_bridge_info info = { - .sw_index = dp->ds->index, - .port = dp->index, - .br = br, - }; - int err; - - /* Here the port is already bridged. Reflect the current configuration - * so that drivers can program their chips accordingly. - */ - dp->bridge_dev = br; - - err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); - - /* The bridging is rolled back on error */ - if (err) - dp->bridge_dev = NULL; - - return err; -} - -static void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) -{ - struct dsa_notifier_bridge_info info = { - .sw_index = dp->ds->index, - .port = dp->index, - .br = br, - }; - int err; - - /* Here the port is already unbridged. Reflect the current configuration - * so that drivers can program their chips accordingly. - */ - dp->bridge_dev = NULL; - - err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); - if (err) - pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); - - /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, - * so allow it to be in BR_STATE_FORWARDING to be kept functional - */ - dsa_port_set_state_now(dp, BR_STATE_FORWARDING); -} - static int dsa_slave_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) { From 4d61d3043bef7b61e7c30276488ff310bee0d897 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:46 -0400 Subject: [PATCH 11/20] net: dsa: move VLAN filtering setter Move the DSA port code which sets VLAN filtering on a port in port.c, where it belongs. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 2 ++ net/dsa/port.c | 16 ++++++++++++++++ net/dsa/slave.c | 16 ---------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index f0b6cd3c8a65..c145223247c5 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -66,6 +66,8 @@ int dsa_port_set_state(struct dsa_port *dp, u8 state, void dsa_port_set_state_now(struct dsa_port *dp, u8 state); int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br); void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); +int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, + struct switchdev_trans *trans); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index da8577fb3d07..c9f95aaf25f1 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -111,3 +111,19 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) */ dsa_port_set_state_now(dp, BR_STATE_FORWARDING); } + +int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, + struct switchdev_trans *trans) +{ + struct dsa_switch *ds = dp->ds; + + /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (ds->ops->port_vlan_filtering) + return ds->ops->port_vlan_filtering(ds, dp->index, + vlan_filtering); + + return 0; +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ab298c41b8e7..32e7e78313ba 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -338,22 +338,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } -static int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, - struct switchdev_trans *trans) -{ - struct dsa_switch *ds = dp->ds; - - /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ - if (switchdev_trans_ph_prepare(trans)) - return 0; - - if (ds->ops->port_vlan_filtering) - return ds->ops->port_vlan_filtering(ds, dp->index, - vlan_filtering); - - return 0; -} - static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds, unsigned int ageing_time) { From d87bd94e1c2006c1bb1d717020116940f9d0735a Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:47 -0400 Subject: [PATCH 12/20] net: dsa: move ageing time setter Move the DSA port code which sets a port ageing time in port.c, where it belongs. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 2 ++ net/dsa/port.c | 40 ++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 40 ---------------------------------------- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index c145223247c5..b0f9837bf5ed 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -68,6 +68,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br); void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, struct switchdev_trans *trans); +int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, + struct switchdev_trans *trans); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index c9f95aaf25f1..3382fdc07a11 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -127,3 +127,43 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, return 0; } + +static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds, + unsigned int ageing_time) +{ + int i; + + for (i = 0; i < ds->num_ports; ++i) { + struct dsa_port *dp = &ds->ports[i]; + + if (dp->ageing_time && dp->ageing_time < ageing_time) + ageing_time = dp->ageing_time; + } + + return ageing_time; +} + +int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, + struct switchdev_trans *trans) +{ + unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); + unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); + struct dsa_switch *ds = dp->ds; + + if (switchdev_trans_ph_prepare(trans)) { + if (ds->ageing_time_min && ageing_time < ds->ageing_time_min) + return -ERANGE; + if (ds->ageing_time_max && ageing_time > ds->ageing_time_max) + return -ERANGE; + return 0; + } + + /* Keep the fastest ageing time in case of multiple bridges */ + dp->ageing_time = ageing_time; + ageing_time = dsa_fastest_ageing_time(ds, ageing_time); + + if (ds->ops->set_ageing_time) + return ds->ops->set_ageing_time(ds, ageing_time); + + return 0; +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 32e7e78313ba..1b0f396c4314 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -338,46 +338,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } -static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds, - unsigned int ageing_time) -{ - int i; - - for (i = 0; i < ds->num_ports; ++i) { - struct dsa_port *dp = &ds->ports[i]; - - if (dp->ageing_time && dp->ageing_time < ageing_time) - ageing_time = dp->ageing_time; - } - - return ageing_time; -} - -static int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, - struct switchdev_trans *trans) -{ - unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); - unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); - struct dsa_switch *ds = dp->ds; - - if (switchdev_trans_ph_prepare(trans)) { - if (ds->ageing_time_min && ageing_time < ds->ageing_time_min) - return -ERANGE; - if (ds->ageing_time_max && ageing_time > ds->ageing_time_max) - return -ERANGE; - return 0; - } - - /* Keep the fastest ageing time in case of multiple bridges */ - dp->ageing_time = ageing_time; - ageing_time = dsa_fastest_ageing_time(ds, ageing_time); - - if (ds->ops->set_ageing_time) - return ds->ops->set_ageing_time(ds, ageing_time); - - return 0; -} - static int dsa_slave_port_attr_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) From d1cffff008dc2f238bfd0700c0f5027980089510 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:48 -0400 Subject: [PATCH 13/20] net: dsa: move FDB handlers Move the DSA port code which handles FDB objects in port.c, where it belongs. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 7 +++++++ net/dsa/port.c | 40 ++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 42 ------------------------------------------ 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index b0f9837bf5ed..d003a2554c7a 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -70,6 +70,13 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, struct switchdev_trans *trans); int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, struct switchdev_trans *trans); +int dsa_port_fdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans); +int dsa_port_fdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_fdb *fdb); +int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb, + switchdev_obj_dump_cb_t *cb); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index 3382fdc07a11..18ec6d432152 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -167,3 +167,43 @@ int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, return 0; } + +int dsa_port_fdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_fdb *fdb, + struct switchdev_trans *trans) +{ + struct dsa_switch *ds = dp->ds; + + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add) + return -EOPNOTSUPP; + + return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans); + } + + ds->ops->port_fdb_add(ds, dp->index, fdb, trans); + + return 0; +} + +int dsa_port_fdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_fdb *fdb) +{ + struct dsa_switch *ds = dp->ds; + + if (ds->ops->port_fdb_del) + return -EOPNOTSUPP; + + return ds->ops->port_fdb_del(ds, dp->index, fdb); +} + +int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb, + switchdev_obj_dump_cb_t *cb) +{ + struct dsa_switch *ds = dp->ds; + + if (ds->ops->port_fdb_dump) + return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb); + + return -EOPNOTSUPP; +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 1b0f396c4314..d9b7bf759f44 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -245,48 +245,6 @@ static int dsa_port_vlan_dump(struct dsa_port *dp, return -EOPNOTSUPP; } -static int dsa_port_fdb_add(struct dsa_port *dp, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) -{ - struct dsa_switch *ds = dp->ds; - - if (switchdev_trans_ph_prepare(trans)) { - if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add) - return -EOPNOTSUPP; - - return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans); - } - - ds->ops->port_fdb_add(ds, dp->index, fdb, trans); - - return 0; -} - -static int dsa_port_fdb_del(struct dsa_port *dp, - const struct switchdev_obj_port_fdb *fdb) -{ - struct dsa_switch *ds = dp->ds; - int ret = -EOPNOTSUPP; - - if (ds->ops->port_fdb_del) - ret = ds->ops->port_fdb_del(ds, dp->index, fdb); - - return ret; -} - -static int dsa_port_fdb_dump(struct dsa_port *dp, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) -{ - struct dsa_switch *ds = dp->ds; - - if (ds->ops->port_fdb_dump) - return ds->ops->port_fdb_dump(ds, dp->index, fdb, cb); - - return -EOPNOTSUPP; -} - static int dsa_port_mdb_add(struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb, struct switchdev_trans *trans) From 3a9afea37e298f4989629553d44b9bf50dc46125 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:49 -0400 Subject: [PATCH 14/20] net: dsa: move MDB handlers Move the DSA port code which handles MDB objects in port.c, where it belongs. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 7 +++++++ net/dsa/port.c | 40 ++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 41 ----------------------------------------- 3 files changed, 47 insertions(+), 41 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index d003a2554c7a..c2a595036746 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -77,6 +77,13 @@ int dsa_port_fdb_del(struct dsa_port *dp, const struct switchdev_obj_port_fdb *fdb); int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb, switchdev_obj_dump_cb_t *cb); +int dsa_port_mdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans); +int dsa_port_mdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb); +int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb, + switchdev_obj_dump_cb_t *cb); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index 18ec6d432152..4ed0124a8d4b 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -207,3 +207,43 @@ int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb, return -EOPNOTSUPP; } + +int dsa_port_mdb_add(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) +{ + struct dsa_switch *ds = dp->ds; + + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) + return -EOPNOTSUPP; + + return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans); + } + + ds->ops->port_mdb_add(ds, dp->index, mdb, trans); + + return 0; +} + +int dsa_port_mdb_del(struct dsa_port *dp, + const struct switchdev_obj_port_mdb *mdb) +{ + struct dsa_switch *ds = dp->ds; + + if (ds->ops->port_mdb_del) + return ds->ops->port_mdb_del(ds, dp->index, mdb); + + return -EOPNOTSUPP; +} + +int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb, + switchdev_obj_dump_cb_t *cb) +{ + struct dsa_switch *ds = dp->ds; + + if (ds->ops->port_mdb_dump) + return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb); + + return -EOPNOTSUPP; +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index d9b7bf759f44..9adcb8267d9a 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -245,47 +245,6 @@ static int dsa_port_vlan_dump(struct dsa_port *dp, return -EOPNOTSUPP; } -static int dsa_port_mdb_add(struct dsa_port *dp, - const struct switchdev_obj_port_mdb *mdb, - struct switchdev_trans *trans) -{ - struct dsa_switch *ds = dp->ds; - - if (switchdev_trans_ph_prepare(trans)) { - if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) - return -EOPNOTSUPP; - - return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans); - } - - ds->ops->port_mdb_add(ds, dp->index, mdb, trans); - - return 0; -} - -static int dsa_port_mdb_del(struct dsa_port *dp, - const struct switchdev_obj_port_mdb *mdb) -{ - struct dsa_switch *ds = dp->ds; - - if (ds->ops->port_mdb_del) - return ds->ops->port_mdb_del(ds, dp->index, mdb); - - return -EOPNOTSUPP; -} - -static int dsa_port_mdb_dump(struct dsa_port *dp, - struct switchdev_obj_port_mdb *mdb, - switchdev_obj_dump_cb_t *cb) -{ - struct dsa_switch *ds = dp->ds; - - if (ds->ops->port_mdb_dump) - return ds->ops->port_mdb_dump(ds, dp->index, mdb, cb); - - return -EOPNOTSUPP; -} - static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct dsa_slave_priv *p = netdev_priv(dev); From 076e713365c9f4ca1ff3eca9122664a5359b94da Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:50 -0400 Subject: [PATCH 15/20] net: dsa: move VLAN handlers Move the DSA port code which handles VLAN objects in port.c, where it belongs. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 8 ++++++++ net/dsa/port.c | 41 +++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 41 ----------------------------------------- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index c2a595036746..16021a891095 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -84,6 +84,14 @@ int dsa_port_mdb_del(struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb, switchdev_obj_dump_cb_t *cb); +int dsa_port_vlan_add(struct dsa_port *dp, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans); +int dsa_port_vlan_del(struct dsa_port *dp, + const struct switchdev_obj_port_vlan *vlan); +int dsa_port_vlan_dump(struct dsa_port *dp, + struct switchdev_obj_port_vlan *vlan, + switchdev_obj_dump_cb_t *cb); /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index 4ed0124a8d4b..f211b0dfb12d 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -247,3 +247,44 @@ int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb, return -EOPNOTSUPP; } + +int dsa_port_vlan_add(struct dsa_port *dp, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + struct dsa_switch *ds = dp->ds; + + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) + return -EOPNOTSUPP; + + return ds->ops->port_vlan_prepare(ds, dp->index, vlan, trans); + } + + ds->ops->port_vlan_add(ds, dp->index, vlan, trans); + + return 0; +} + +int dsa_port_vlan_del(struct dsa_port *dp, + const struct switchdev_obj_port_vlan *vlan) +{ + struct dsa_switch *ds = dp->ds; + + if (!ds->ops->port_vlan_del) + return -EOPNOTSUPP; + + return ds->ops->port_vlan_del(ds, dp->index, vlan); +} + +int dsa_port_vlan_dump(struct dsa_port *dp, + struct switchdev_obj_port_vlan *vlan, + switchdev_obj_dump_cb_t *cb) +{ + struct dsa_switch *ds = dp->ds; + + if (ds->ops->port_vlan_dump) + return ds->ops->port_vlan_dump(ds, dp->index, vlan, cb); + + return -EOPNOTSUPP; +} diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 9adcb8267d9a..887e26695519 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -204,47 +204,6 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a) return 0; } -static int dsa_port_vlan_add(struct dsa_port *dp, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) -{ - struct dsa_switch *ds = dp->ds; - - if (switchdev_trans_ph_prepare(trans)) { - if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) - return -EOPNOTSUPP; - - return ds->ops->port_vlan_prepare(ds, dp->index, vlan, trans); - } - - ds->ops->port_vlan_add(ds, dp->index, vlan, trans); - - return 0; -} - -static int dsa_port_vlan_del(struct dsa_port *dp, - const struct switchdev_obj_port_vlan *vlan) -{ - struct dsa_switch *ds = dp->ds; - - if (!ds->ops->port_vlan_del) - return -EOPNOTSUPP; - - return ds->ops->port_vlan_del(ds, dp->index, vlan); -} - -static int dsa_port_vlan_dump(struct dsa_port *dp, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - struct dsa_switch *ds = dp->ds; - - if (ds->ops->port_vlan_dump) - return ds->ops->port_vlan_dump(ds, dp->index, vlan, cb); - - return -EOPNOTSUPP; -} - static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct dsa_slave_priv *p = netdev_priv(dev); From 52c96f9d7003c74c7fbec7438c0ed78df0cc1c79 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:51 -0400 Subject: [PATCH 16/20] net: dsa: move notifier info to private header The DSA notifier events and info structure definitions are not meant for DSA drivers and users, but only used internally by the DSA core files. Move them from the public net/dsa.h file to the private dsa_priv.h file. Also use this opportunity to turn the events into an anonymous enum, because we don't care about the values, and this will prevent future conflicts when adding (and sorting) new events. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 10 ---------- net/dsa/dsa_priv.h | 12 ++++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 791fed62fb16..c0e567c0c824 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -285,16 +285,6 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds) return ds->rtable[dst->cpu_dp->ds->index]; } -#define DSA_NOTIFIER_BRIDGE_JOIN 1 -#define DSA_NOTIFIER_BRIDGE_LEAVE 2 - -/* DSA_NOTIFIER_BRIDGE_* */ -struct dsa_notifier_bridge_info { - struct net_device *br; - int sw_index; - int port; -}; - struct dsa_switch_ops { /* * Legacy probing. diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 16021a891095..c19241eb094b 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -16,6 +16,18 @@ #include #include +enum { + DSA_NOTIFIER_BRIDGE_JOIN, + DSA_NOTIFIER_BRIDGE_LEAVE, +}; + +/* DSA_NOTIFIER_BRIDGE_* */ +struct dsa_notifier_bridge_info { + struct net_device *br; + int sw_index; + int port; +}; + struct dsa_device_ops { struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, From 1faabf7440f17999f41973e91878c13ad9f080b2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:52 -0400 Subject: [PATCH 17/20] net: dsa: add notifier for ageing time This patch keeps the port-wide ageing time handling code in dsa_port_ageing_time, pushes the requested ageing time value in a new switch fabric notification, and moves the switch-wide ageing time handling code in dsa_switch_ageing_time. This has the effect that now not only the switch that the target port belongs to can be programmed, but all switches composing the switch fabric. For the moment, keep the current behavior and ignore other switches. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 8 ++++++++ net/dsa/port.c | 37 ++++++++----------------------------- net/dsa/switch.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index c19241eb094b..becaf8a61b13 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -17,10 +17,18 @@ #include enum { + DSA_NOTIFIER_AGEING_TIME, DSA_NOTIFIER_BRIDGE_JOIN, DSA_NOTIFIER_BRIDGE_LEAVE, }; +/* DSA_NOTIFIER_AGEING_TIME */ +struct dsa_notifier_ageing_time_info { + struct switchdev_trans *trans; + unsigned int ageing_time; + int sw_index; +}; + /* DSA_NOTIFIER_BRIDGE_* */ struct dsa_notifier_bridge_info { struct net_device *br; diff --git a/net/dsa/port.c b/net/dsa/port.c index f211b0dfb12d..59328a35394d 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -128,44 +128,23 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, return 0; } -static unsigned int dsa_fastest_ageing_time(struct dsa_switch *ds, - unsigned int ageing_time) -{ - int i; - - for (i = 0; i < ds->num_ports; ++i) { - struct dsa_port *dp = &ds->ports[i]; - - if (dp->ageing_time && dp->ageing_time < ageing_time) - ageing_time = dp->ageing_time; - } - - return ageing_time; -} - int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, struct switchdev_trans *trans) { unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_ageing_time_info info = { + .ageing_time = ageing_time, + .sw_index = dp->ds->index, + .trans = trans, + }; - if (switchdev_trans_ph_prepare(trans)) { - if (ds->ageing_time_min && ageing_time < ds->ageing_time_min) - return -ERANGE; - if (ds->ageing_time_max && ageing_time > ds->ageing_time_max) - return -ERANGE; - return 0; - } + if (switchdev_trans_ph_prepare(trans)) + return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); - /* Keep the fastest ageing time in case of multiple bridges */ dp->ageing_time = ageing_time; - ageing_time = dsa_fastest_ageing_time(ds, ageing_time); - if (ds->ops->set_ageing_time) - return ds->ops->set_ageing_time(ds, ageing_time); - - return 0; + return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); } int dsa_port_fdb_add(struct dsa_port *dp, diff --git a/net/dsa/switch.c b/net/dsa/switch.c index f477053308d2..540770ecc8b0 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -12,9 +12,52 @@ #include #include +#include #include "dsa_priv.h" +static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds, + unsigned int ageing_time) +{ + int i; + + for (i = 0; i < ds->num_ports; ++i) { + struct dsa_port *dp = &ds->ports[i]; + + if (dp->ageing_time && dp->ageing_time < ageing_time) + ageing_time = dp->ageing_time; + } + + return ageing_time; +} + +static int dsa_switch_ageing_time(struct dsa_switch *ds, + struct dsa_notifier_ageing_time_info *info) +{ + unsigned int ageing_time = info->ageing_time; + struct switchdev_trans *trans = info->trans; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (switchdev_trans_ph_prepare(trans)) { + if (ds->ageing_time_min && ageing_time < ds->ageing_time_min) + return -ERANGE; + if (ds->ageing_time_max && ageing_time > ds->ageing_time_max) + return -ERANGE; + return 0; + } + + /* Program the fastest ageing time in case of multiple bridges */ + ageing_time = dsa_switch_fastest_ageing_time(ds, ageing_time); + + if (ds->ops->set_ageing_time) + return ds->ops->set_ageing_time(ds, ageing_time); + + return 0; +} + static int dsa_switch_bridge_join(struct dsa_switch *ds, struct dsa_notifier_bridge_info *info) { @@ -48,6 +91,9 @@ static int dsa_switch_event(struct notifier_block *nb, int err; switch (event) { + case DSA_NOTIFIER_AGEING_TIME: + err = dsa_switch_ageing_time(ds, info); + break; case DSA_NOTIFIER_BRIDGE_JOIN: err = dsa_switch_bridge_join(ds, info); break; From 685fb6a40ddace10a0bc8a680ab6ba65c6cdfdaf Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:53 -0400 Subject: [PATCH 18/20] net: dsa: add FDB notifier Add two new DSA_NOTIFIER_FDB_ADD and DSA_NOTIFIER_FDB_DEL events to notify not only a single switch, but all switches of a the fabric when an FDB entry is added or removed. For the moment, keep the current behavior and ignore other switches. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 10 ++++++++++ net/dsa/port.c | 29 +++++++++++++---------------- net/dsa/switch.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index becaf8a61b13..6a7d0d7d0489 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -20,6 +20,8 @@ enum { DSA_NOTIFIER_AGEING_TIME, DSA_NOTIFIER_BRIDGE_JOIN, DSA_NOTIFIER_BRIDGE_LEAVE, + DSA_NOTIFIER_FDB_ADD, + DSA_NOTIFIER_FDB_DEL, }; /* DSA_NOTIFIER_AGEING_TIME */ @@ -36,6 +38,14 @@ struct dsa_notifier_bridge_info { int port; }; +/* DSA_NOTIFIER_FDB_* */ +struct dsa_notifier_fdb_info { + const struct switchdev_obj_port_fdb *fdb; + struct switchdev_trans *trans; + int sw_index; + int port; +}; + struct dsa_device_ops { struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, diff --git a/net/dsa/port.c b/net/dsa/port.c index 59328a35394d..ed88d8381642 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -151,29 +151,26 @@ int dsa_port_fdb_add(struct dsa_port *dp, const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans) { - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_fdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .trans = trans, + .fdb = fdb, + }; - if (switchdev_trans_ph_prepare(trans)) { - if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add) - return -EOPNOTSUPP; - - return ds->ops->port_fdb_prepare(ds, dp->index, fdb, trans); - } - - ds->ops->port_fdb_add(ds, dp->index, fdb, trans); - - return 0; + return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info); } int dsa_port_fdb_del(struct dsa_port *dp, const struct switchdev_obj_port_fdb *fdb) { - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_fdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .fdb = fdb, + }; - if (ds->ops->port_fdb_del) - return -EOPNOTSUPP; - - return ds->ops->port_fdb_del(ds, dp->index, fdb); + return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); } int dsa_port_fdb_dump(struct dsa_port *dp, struct switchdev_obj_port_fdb *fdb, diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 540770ecc8b0..e71cc860d32c 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -84,6 +84,43 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, return 0; } +static int dsa_switch_fdb_add(struct dsa_switch *ds, + struct dsa_notifier_fdb_info *info) +{ + const struct switchdev_obj_port_fdb *fdb = info->fdb; + struct switchdev_trans *trans = info->trans; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add) + return -EOPNOTSUPP; + + return ds->ops->port_fdb_prepare(ds, info->port, fdb, trans); + } + + ds->ops->port_fdb_add(ds, info->port, fdb, trans); + + return 0; +} + +static int dsa_switch_fdb_del(struct dsa_switch *ds, + struct dsa_notifier_fdb_info *info) +{ + const struct switchdev_obj_port_fdb *fdb = info->fdb; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (!ds->ops->port_fdb_del) + return -EOPNOTSUPP; + + return ds->ops->port_fdb_del(ds, info->port, fdb); +} + static int dsa_switch_event(struct notifier_block *nb, unsigned long event, void *info) { @@ -100,6 +137,12 @@ static int dsa_switch_event(struct notifier_block *nb, case DSA_NOTIFIER_BRIDGE_LEAVE: err = dsa_switch_bridge_leave(ds, info); break; + case DSA_NOTIFIER_FDB_ADD: + err = dsa_switch_fdb_add(ds, info); + break; + case DSA_NOTIFIER_FDB_DEL: + err = dsa_switch_fdb_del(ds, info); + break; default: err = -EOPNOTSUPP; break; From 8ae5bcdc5d98a99e59f194101e7acd2e9d055758 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:54 -0400 Subject: [PATCH 19/20] net: dsa: add MDB notifier Add two new DSA_NOTIFIER_MDB_ADD and DSA_NOTIFIER_MDB_DEL events to notify not only a single switch, but all switches of a the fabric when an MDB entry is added or removed. For the moment, keep the current behavior and ignore other switches. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 10 ++++++++++ net/dsa/port.c | 29 +++++++++++++---------------- net/dsa/switch.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 6a7d0d7d0489..2b60293b325c 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -22,6 +22,8 @@ enum { DSA_NOTIFIER_BRIDGE_LEAVE, DSA_NOTIFIER_FDB_ADD, DSA_NOTIFIER_FDB_DEL, + DSA_NOTIFIER_MDB_ADD, + DSA_NOTIFIER_MDB_DEL, }; /* DSA_NOTIFIER_AGEING_TIME */ @@ -46,6 +48,14 @@ struct dsa_notifier_fdb_info { int port; }; +/* DSA_NOTIFIER_MDB_* */ +struct dsa_notifier_mdb_info { + const struct switchdev_obj_port_mdb *mdb; + struct switchdev_trans *trans; + int sw_index; + int port; +}; + struct dsa_device_ops { struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, diff --git a/net/dsa/port.c b/net/dsa/port.c index ed88d8381642..c7c4920e7bc9 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -188,29 +188,26 @@ int dsa_port_mdb_add(struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb, struct switchdev_trans *trans) { - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_mdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .trans = trans, + .mdb = mdb, + }; - if (switchdev_trans_ph_prepare(trans)) { - if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) - return -EOPNOTSUPP; - - return ds->ops->port_mdb_prepare(ds, dp->index, mdb, trans); - } - - ds->ops->port_mdb_add(ds, dp->index, mdb, trans); - - return 0; + return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info); } int dsa_port_mdb_del(struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb) { - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_mdb_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .mdb = mdb, + }; - if (ds->ops->port_mdb_del) - return ds->ops->port_mdb_del(ds, dp->index, mdb); - - return -EOPNOTSUPP; + return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info); } int dsa_port_mdb_dump(struct dsa_port *dp, struct switchdev_obj_port_mdb *mdb, diff --git a/net/dsa/switch.c b/net/dsa/switch.c index e71cc860d32c..b7e8e45869fc 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -121,6 +121,43 @@ static int dsa_switch_fdb_del(struct dsa_switch *ds, return ds->ops->port_fdb_del(ds, info->port, fdb); } +static int dsa_switch_mdb_add(struct dsa_switch *ds, + struct dsa_notifier_mdb_info *info) +{ + const struct switchdev_obj_port_mdb *mdb = info->mdb; + struct switchdev_trans *trans = info->trans; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) + return -EOPNOTSUPP; + + return ds->ops->port_mdb_prepare(ds, info->port, mdb, trans); + } + + ds->ops->port_mdb_add(ds, info->port, mdb, trans); + + return 0; +} + +static int dsa_switch_mdb_del(struct dsa_switch *ds, + struct dsa_notifier_mdb_info *info) +{ + const struct switchdev_obj_port_mdb *mdb = info->mdb; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (!ds->ops->port_mdb_del) + return -EOPNOTSUPP; + + return ds->ops->port_mdb_del(ds, info->port, mdb); +} + static int dsa_switch_event(struct notifier_block *nb, unsigned long event, void *info) { @@ -143,6 +180,12 @@ static int dsa_switch_event(struct notifier_block *nb, case DSA_NOTIFIER_FDB_DEL: err = dsa_switch_fdb_del(ds, info); break; + case DSA_NOTIFIER_MDB_ADD: + err = dsa_switch_mdb_add(ds, info); + break; + case DSA_NOTIFIER_MDB_DEL: + err = dsa_switch_mdb_del(ds, info); + break; default: err = -EOPNOTSUPP; break; From d0c627b8740ca6243054263fbc98981a36ac5618 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 19 May 2017 17:00:55 -0400 Subject: [PATCH 20/20] net: dsa: add VLAN notifier Add two new DSA_NOTIFIER_VLAN_ADD and DSA_NOTIFIER_VLAN_DEL events to notify not only a single switch, but all switches of a the fabric when an VLAN entry is added or removed. For the moment, keep the current behavior and ignore other switches. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa_priv.h | 10 ++++++++++ net/dsa/port.c | 29 +++++++++++++---------------- net/dsa/switch.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 2b60293b325c..1d52f9051d0e 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -24,6 +24,8 @@ enum { DSA_NOTIFIER_FDB_DEL, DSA_NOTIFIER_MDB_ADD, DSA_NOTIFIER_MDB_DEL, + DSA_NOTIFIER_VLAN_ADD, + DSA_NOTIFIER_VLAN_DEL, }; /* DSA_NOTIFIER_AGEING_TIME */ @@ -56,6 +58,14 @@ struct dsa_notifier_mdb_info { int port; }; +/* DSA_NOTIFIER_VLAN_* */ +struct dsa_notifier_vlan_info { + const struct switchdev_obj_port_vlan *vlan; + struct switchdev_trans *trans; + int sw_index; + int port; +}; + struct dsa_device_ops { struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, diff --git a/net/dsa/port.c b/net/dsa/port.c index c7c4920e7bc9..c88c0cec8454 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -225,29 +225,26 @@ int dsa_port_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans) { - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_vlan_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .trans = trans, + .vlan = vlan, + }; - if (switchdev_trans_ph_prepare(trans)) { - if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) - return -EOPNOTSUPP; - - return ds->ops->port_vlan_prepare(ds, dp->index, vlan, trans); - } - - ds->ops->port_vlan_add(ds, dp->index, vlan, trans); - - return 0; + return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); } int dsa_port_vlan_del(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan) { - struct dsa_switch *ds = dp->ds; + struct dsa_notifier_vlan_info info = { + .sw_index = dp->ds->index, + .port = dp->index, + .vlan = vlan, + }; - if (!ds->ops->port_vlan_del) - return -EOPNOTSUPP; - - return ds->ops->port_vlan_del(ds, dp->index, vlan); + return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); } int dsa_port_vlan_dump(struct dsa_port *dp, diff --git a/net/dsa/switch.c b/net/dsa/switch.c index b7e8e45869fc..c1e4b2d5a3ae 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -158,6 +158,43 @@ static int dsa_switch_mdb_del(struct dsa_switch *ds, return ds->ops->port_mdb_del(ds, info->port, mdb); } +static int dsa_switch_vlan_add(struct dsa_switch *ds, + struct dsa_notifier_vlan_info *info) +{ + const struct switchdev_obj_port_vlan *vlan = info->vlan; + struct switchdev_trans *trans = info->trans; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) + return -EOPNOTSUPP; + + return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans); + } + + ds->ops->port_vlan_add(ds, info->port, vlan, trans); + + return 0; +} + +static int dsa_switch_vlan_del(struct dsa_switch *ds, + struct dsa_notifier_vlan_info *info) +{ + const struct switchdev_obj_port_vlan *vlan = info->vlan; + + /* Do not care yet about other switch chips of the fabric */ + if (ds->index != info->sw_index) + return 0; + + if (!ds->ops->port_vlan_del) + return -EOPNOTSUPP; + + return ds->ops->port_vlan_del(ds, info->port, vlan); +} + static int dsa_switch_event(struct notifier_block *nb, unsigned long event, void *info) { @@ -186,6 +223,12 @@ static int dsa_switch_event(struct notifier_block *nb, case DSA_NOTIFIER_MDB_DEL: err = dsa_switch_mdb_del(ds, info); break; + case DSA_NOTIFIER_VLAN_ADD: + err = dsa_switch_vlan_add(ds, info); + break; + case DSA_NOTIFIER_VLAN_DEL: + err = dsa_switch_vlan_del(ds, info); + break; default: err = -EOPNOTSUPP; break;