From 69f5df491e0becb75d2d795add7481a35218d657 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 24 Sep 2015 10:02:40 +0200 Subject: switchdev: rename "trans" to "trans_ph". This is temporary, name "trans" will be used for something else and "trans_ph" will eventually disappear. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index fda38f830a108..df5a5446ff4c1 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -163,7 +163,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * but should not commit the attr. */ - attr->trans = SWITCHDEV_TRANS_PREPARE; + attr->trans_ph = SWITCHDEV_TRANS_PREPARE; err = __switchdev_port_attr_set(dev, attr); if (err) { /* Prepare phase failed: abort the transaction. Any @@ -172,7 +172,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) */ if (err != -EOPNOTSUPP) { - attr->trans = SWITCHDEV_TRANS_ABORT; + attr->trans_ph = SWITCHDEV_TRANS_ABORT; __switchdev_port_attr_set(dev, attr); } @@ -184,7 +184,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * because the driver said everythings was OK in phase I. */ - attr->trans = SWITCHDEV_TRANS_COMMIT; + attr->trans_ph = SWITCHDEV_TRANS_COMMIT; err = __switchdev_port_attr_set(dev, attr); WARN(err, "%s: Commit of attribute (id=%d) failed.\n", dev->name, attr->id); @@ -243,7 +243,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * but should not commit the obj. */ - obj->trans = SWITCHDEV_TRANS_PREPARE; + obj->trans_ph = SWITCHDEV_TRANS_PREPARE; err = __switchdev_port_obj_add(dev, obj); if (err) { /* Prepare phase failed: abort the transaction. Any @@ -252,7 +252,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) */ if (err != -EOPNOTSUPP) { - obj->trans = SWITCHDEV_TRANS_ABORT; + obj->trans_ph = SWITCHDEV_TRANS_ABORT; __switchdev_port_obj_add(dev, obj); } @@ -264,7 +264,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * because the driver said everythings was OK in phase I. */ - obj->trans = SWITCHDEV_TRANS_COMMIT; + obj->trans_ph = SWITCHDEV_TRANS_COMMIT; err = __switchdev_port_obj_add(dev, obj); WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); -- cgit v1.2.3 From 7ea6eb3f56f45cf4babae8b9a7421868e5005f17 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 24 Sep 2015 10:02:41 +0200 Subject: switchdev: introduce transaction item queue for attr_set and obj_add Now, the memory allocation in prepare/commit state is done separatelly in each driver (rocker). Introduce the similar mechanism in generic switchdev code, in form of queue. That can be used not only for memory allocations, but also for different items. Abort item destruction is handled as well. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 19 ++++++ drivers/net/ethernet/rocker/rocker.c | 6 +- include/net/switchdev.h | 24 ++++++- net/dsa/slave.c | 6 +- net/switchdev/switchdev.c | 111 +++++++++++++++++++++++++++++---- 5 files changed, 146 insertions(+), 20 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt index 67e43ee7840a1..9f9e2587b3479 100644 --- a/Documentation/networking/switchdev.txt +++ b/Documentation/networking/switchdev.txt @@ -369,3 +369,22 @@ The driver can monitor for updates to arp_tbl using the netevent notifier NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy to know when arp_tbl neighbor entries are purged from the port. + +Transaction item queue +^^^^^^^^^^^^^^^^^^^^^^ + +For switchdev ops attr_set and obj_add, there is a 2 phase transaction model +used. First phase is to "prepare" anything needed, including various checks, +memory allocation, etc. The goal is to handle the stuff that is not unlikely +to fail here. The second phase is to "commit" the actual changes. + +Switchdev provides an inftrastructure for sharing items (for example memory +allocations) between the two phases. + +The object created by a driver in "prepare" phase and it is queued up by: +switchdev_trans_item_enqueue() +During the "commit" phase, the driver gets the object by: +switchdev_trans_item_dequeue() + +If a transaction is aborted during "prepare" phase, switchdev code will handle +cleanup of the queued-up objects. diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index cf03b077311e3..dcc6f3fd13c9f 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4383,7 +4383,8 @@ static int rocker_port_brport_flags_set(struct rocker_port *rocker_port, } static int rocker_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr) + struct switchdev_attr *attr, + struct switchdev_trans *trans) { struct rocker_port *rocker_port = netdev_priv(dev); int err = 0; @@ -4467,7 +4468,8 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port, } static int rocker_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj *obj, + struct switchdev_trans *trans) { struct rocker_port *rocker_port = netdev_priv(dev); const struct switchdev_obj_ipv4_fib *fib4; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 494f51097dc66..1e394f1176b65 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -1,6 +1,6 @@ /* * include/net/switchdev.h - Switch device API - * Copyright (c) 2014 Jiri Pirko + * Copyright (c) 2014-2015 Jiri Pirko * Copyright (c) 2014-2015 Scott Feldman * * This program is free software; you can redistribute it and/or modify @@ -13,6 +13,7 @@ #include #include +#include #define SWITCHDEV_F_NO_RECURSE BIT(0) @@ -23,6 +24,16 @@ enum switchdev_trans_ph { SWITCHDEV_TRANS_COMMIT, }; +struct switchdev_trans_item { + struct list_head list; + void *data; + void (*destructor)(const void *data); +}; + +struct switchdev_trans { + struct list_head item_list; +}; + enum switchdev_attr_id { SWITCHDEV_ATTR_UNDEFINED, SWITCHDEV_ATTR_PORT_PARENT_ID, @@ -77,6 +88,11 @@ struct switchdev_obj { } u; }; +void switchdev_trans_item_enqueue(struct switchdev_trans *trans, + void *data, void (*destructor)(void const *), + struct switchdev_trans_item *tritem); +void *switchdev_trans_item_dequeue(struct switchdev_trans *trans); + /** * struct switchdev_ops - switchdev operations * @@ -94,9 +110,11 @@ struct switchdev_ops { int (*switchdev_port_attr_get)(struct net_device *dev, struct switchdev_attr *attr); int (*switchdev_port_attr_set)(struct net_device *dev, - struct switchdev_attr *attr); + struct switchdev_attr *attr, + struct switchdev_trans *trans); int (*switchdev_port_obj_add)(struct net_device *dev, - struct switchdev_obj *obj); + struct switchdev_obj *obj, + struct switchdev_trans *trans); int (*switchdev_port_obj_del)(struct net_device *dev, struct switchdev_obj *obj); int (*switchdev_port_obj_dump)(struct net_device *dev, diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 7f50b74434020..ac76fd15ad8be 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -456,7 +456,8 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state) } static int dsa_slave_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr) + struct switchdev_attr *attr, + struct switchdev_trans *trans) { int ret = 0; @@ -474,7 +475,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev, } static int dsa_slave_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj *obj, + struct switchdev_trans *trans) { int err; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index df5a5446ff4c1..35e2967ffa18b 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -1,6 +1,6 @@ /* * net/switchdev/switchdev.c - Switch device API - * Copyright (c) 2014 Jiri Pirko + * Copyright (c) 2014-2015 Jiri Pirko * Copyright (c) 2014-2015 Scott Feldman * * This program is free software; you can redistribute it and/or modify @@ -16,9 +16,82 @@ #include #include #include +#include #include #include +/** + * switchdev_trans_item_enqueue - Enqueue data item to transaction queue + * + * @trans: transaction + * @data: pointer to data being queued + * @destructor: data destructor + * @tritem: transaction item being queued + * + * Enqeueue data item to transaction queue. tritem is typically placed in + * cointainter pointed at by data pointer. Destructor is called on + * transaction abort and after successful commit phase in case + * the caller did not dequeue the item before. + */ +void switchdev_trans_item_enqueue(struct switchdev_trans *trans, + void *data, void (*destructor)(void const *), + struct switchdev_trans_item *tritem) +{ + tritem->data = data; + tritem->destructor = destructor; + list_add_tail(&tritem->list, &trans->item_list); +} +EXPORT_SYMBOL_GPL(switchdev_trans_item_enqueue); + +static struct switchdev_trans_item * +__switchdev_trans_item_dequeue(struct switchdev_trans *trans) +{ + struct switchdev_trans_item *tritem; + + if (list_empty(&trans->item_list)) + return NULL; + tritem = list_first_entry(&trans->item_list, + struct switchdev_trans_item, list); + list_del(&tritem->list); + return tritem; +} + +/** + * switchdev_trans_item_dequeue - Dequeue data item from transaction queue + * + * @trans: transaction + */ +void *switchdev_trans_item_dequeue(struct switchdev_trans *trans) +{ + struct switchdev_trans_item *tritem; + + tritem = __switchdev_trans_item_dequeue(trans); + BUG_ON(!tritem); + return tritem->data; +} +EXPORT_SYMBOL_GPL(switchdev_trans_item_dequeue); + +static void switchdev_trans_init(struct switchdev_trans *trans) +{ + INIT_LIST_HEAD(&trans->item_list); +} + +static void switchdev_trans_items_destroy(struct switchdev_trans *trans) +{ + struct switchdev_trans_item *tritem; + + while ((tritem = __switchdev_trans_item_dequeue(trans))) + tritem->destructor(tritem->data); +} + +static void switchdev_trans_items_warn_destroy(struct net_device *dev, + struct switchdev_trans *trans) +{ + WARN(!list_empty(&trans->item_list), "%s: transaction item queue is not empty.\n", + dev->name); + switchdev_trans_items_destroy(trans); +} + /** * switchdev_port_attr_get - Get port attribute * @@ -62,7 +135,8 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) EXPORT_SYMBOL_GPL(switchdev_port_attr_get); static int __switchdev_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr) + struct switchdev_attr *attr, + struct switchdev_trans *trans) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -70,7 +144,7 @@ static int __switchdev_port_attr_set(struct net_device *dev, int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_attr_set) - return ops->switchdev_port_attr_set(dev, attr); + return ops->switchdev_port_attr_set(dev, attr, trans); if (attr->flags & SWITCHDEV_F_NO_RECURSE) return err; @@ -81,7 +155,7 @@ static int __switchdev_port_attr_set(struct net_device *dev, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = __switchdev_port_attr_set(lower_dev, attr); + err = __switchdev_port_attr_set(lower_dev, attr, trans); if (err) break; } @@ -144,6 +218,7 @@ static int switchdev_port_attr_set_defer(struct net_device *dev, */ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) { + struct switchdev_trans trans; int err; if (!rtnl_is_locked()) { @@ -156,6 +231,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) return switchdev_port_attr_set_defer(dev, attr); } + switchdev_trans_init(&trans); + /* Phase I: prepare for attr set. Driver/device should fail * here if there are going to be issues in the commit phase, * such as lack of resources or support. The driver/device @@ -164,7 +241,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) */ attr->trans_ph = SWITCHDEV_TRANS_PREPARE; - err = __switchdev_port_attr_set(dev, attr); + err = __switchdev_port_attr_set(dev, attr, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any * resources reserved in the prepare phase are @@ -173,7 +250,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) if (err != -EOPNOTSUPP) { attr->trans_ph = SWITCHDEV_TRANS_ABORT; - __switchdev_port_attr_set(dev, attr); + __switchdev_port_attr_set(dev, attr, &trans); + switchdev_trans_items_destroy(&trans); } return err; @@ -185,16 +263,18 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) */ attr->trans_ph = SWITCHDEV_TRANS_COMMIT; - err = __switchdev_port_attr_set(dev, attr); + err = __switchdev_port_attr_set(dev, attr, &trans); WARN(err, "%s: Commit of attribute (id=%d) failed.\n", dev->name, attr->id); + switchdev_trans_items_warn_destroy(dev, &trans); return err; } EXPORT_SYMBOL_GPL(switchdev_port_attr_set); static int __switchdev_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj *obj, + struct switchdev_trans *trans) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -202,7 +282,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_add) - return ops->switchdev_port_obj_add(dev, obj); + return ops->switchdev_port_obj_add(dev, obj, trans); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to add object on @@ -210,7 +290,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = __switchdev_port_obj_add(lower_dev, obj); + err = __switchdev_port_obj_add(lower_dev, obj, trans); if (err) break; } @@ -232,10 +312,13 @@ static int __switchdev_port_obj_add(struct net_device *dev, */ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) { + struct switchdev_trans trans; int err; ASSERT_RTNL(); + switchdev_trans_init(&trans); + /* Phase I: prepare for obj add. Driver/device should fail * here if there are going to be issues in the commit phase, * such as lack of resources or support. The driver/device @@ -244,7 +327,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) */ obj->trans_ph = SWITCHDEV_TRANS_PREPARE; - err = __switchdev_port_obj_add(dev, obj); + err = __switchdev_port_obj_add(dev, obj, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any * resources reserved in the prepare phase are @@ -253,7 +336,8 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) if (err != -EOPNOTSUPP) { obj->trans_ph = SWITCHDEV_TRANS_ABORT; - __switchdev_port_obj_add(dev, obj); + __switchdev_port_obj_add(dev, obj, &trans); + switchdev_trans_items_destroy(&trans); } return err; @@ -265,8 +349,9 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) */ obj->trans_ph = SWITCHDEV_TRANS_COMMIT; - err = __switchdev_port_obj_add(dev, obj); + err = __switchdev_port_obj_add(dev, obj, &trans); WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); + switchdev_trans_items_warn_destroy(dev, &trans); return err; } -- cgit v1.2.3 From f8db83486e316ff50f97961a82b614985645508e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 24 Sep 2015 10:02:42 +0200 Subject: switchdev: move transaction phase enum under transaction structure Before it disappears completely, move transaction phase enum under transaction structure and make attr/obj structures a bit cleaner. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 17 +++++++++-------- include/net/switchdev.h | 3 +-- net/dsa/slave.c | 18 ++++++++++-------- net/switchdev/switchdev.c | 12 ++++++------ 4 files changed, 26 insertions(+), 24 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index dcc6f3fd13c9f..c348f86d9b8dd 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4389,7 +4389,7 @@ static int rocker_port_attr_set(struct net_device *dev, struct rocker_port *rocker_port = netdev_priv(dev); int err = 0; - switch (attr->trans_ph) { + switch (trans->ph) { case SWITCHDEV_TRANS_PREPARE: BUG_ON(!list_empty(&rocker_port->trans_mem)); break; @@ -4402,12 +4402,12 @@ static int rocker_port_attr_set(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_STP_STATE: - err = rocker_port_stp_update(rocker_port, attr->trans_ph, + err = rocker_port_stp_update(rocker_port, trans->ph, ROCKER_OP_FLAG_NOWAIT, attr->u.stp_state); break; case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: - err = rocker_port_brport_flags_set(rocker_port, attr->trans_ph, + err = rocker_port_brport_flags_set(rocker_port, trans->ph, attr->u.brport_flags); break; default: @@ -4475,7 +4475,7 @@ static int rocker_port_obj_add(struct net_device *dev, const struct switchdev_obj_ipv4_fib *fib4; int err = 0; - switch (obj->trans_ph) { + switch (trans->ph) { case SWITCHDEV_TRANS_PREPARE: BUG_ON(!list_empty(&rocker_port->trans_mem)); break; @@ -4488,17 +4488,17 @@ static int rocker_port_obj_add(struct net_device *dev, switch (obj->id) { case SWITCHDEV_OBJ_PORT_VLAN: - err = rocker_port_vlans_add(rocker_port, obj->trans_ph, + err = rocker_port_vlans_add(rocker_port, trans->ph, &obj->u.vlan); break; case SWITCHDEV_OBJ_IPV4_FIB: fib4 = &obj->u.ipv4_fib; - err = rocker_port_fib_ipv4(rocker_port, obj->trans_ph, + err = rocker_port_fib_ipv4(rocker_port, trans->ph, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, 0); break; case SWITCHDEV_OBJ_PORT_FDB: - err = rocker_port_fdb_add(rocker_port, obj->trans_ph, &obj->u.fdb); + err = rocker_port_fdb_add(rocker_port, trans->ph, &obj->u.fdb); break; default: err = -EOPNOTSUPP; @@ -4569,7 +4569,8 @@ static int rocker_port_obj_del(struct net_device *dev, ROCKER_OP_FLAG_REMOVE); break; case SWITCHDEV_OBJ_PORT_FDB: - err = rocker_port_fdb_del(rocker_port, obj->trans_ph, &obj->u.fdb); + err = rocker_port_fdb_del(rocker_port, SWITCHDEV_TRANS_NONE, + &obj->u.fdb); break; default: err = -EOPNOTSUPP; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 1e394f1176b65..368a6429198db 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -32,6 +32,7 @@ struct switchdev_trans_item { struct switchdev_trans { struct list_head item_list; + enum switchdev_trans_ph ph; }; enum switchdev_attr_id { @@ -43,7 +44,6 @@ enum switchdev_attr_id { struct switchdev_attr { enum switchdev_attr_id id; - enum switchdev_trans_ph trans_ph; u32 flags; union { struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ @@ -63,7 +63,6 @@ enum switchdev_obj_id { struct switchdev_obj { enum switchdev_obj_id id; - enum switchdev_trans_ph trans_ph; int (*cb)(struct net_device *dev, struct switchdev_obj *obj); union { struct switchdev_obj_vlan { /* PORT_VLAN */ diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ac76fd15ad8be..748cc6394bbb9 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -242,7 +242,8 @@ static int dsa_bridge_check_vlan_range(struct dsa_switch *ds, } static int dsa_slave_port_vlan_add(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj *obj, + struct switchdev_trans *trans) { struct switchdev_obj_vlan *vlan = &obj->u.vlan; struct dsa_slave_priv *p = netdev_priv(dev); @@ -250,7 +251,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, u16 vid; int err; - switch (obj->trans_ph) { + switch (trans->ph) { case SWITCHDEV_TRANS_PREPARE: if (!ds->drv->port_vlan_add || !ds->drv->port_pvid_set) return -EOPNOTSUPP; @@ -347,16 +348,17 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, } static int dsa_slave_port_fdb_add(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj *obj, + struct switchdev_trans *trans) { struct switchdev_obj_fdb *fdb = &obj->u.fdb; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret = -EOPNOTSUPP; - if (obj->trans_ph == SWITCHDEV_TRANS_PREPARE) + if (trans->ph == SWITCHDEV_TRANS_PREPARE) ret = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP; - else if (obj->trans_ph == SWITCHDEV_TRANS_COMMIT) + else if (trans->ph == SWITCHDEV_TRANS_COMMIT) ret = ds->drv->port_fdb_add(ds, p->port, fdb->addr, fdb->vid); return ret; @@ -463,7 +465,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev, switch (attr->id) { case SWITCHDEV_ATTR_PORT_STP_STATE: - if (attr->trans_ph == SWITCHDEV_TRANS_COMMIT) + if (trans->ph == SWITCHDEV_TRANS_COMMIT) ret = dsa_slave_stp_update(dev, attr->u.stp_state); break; default: @@ -487,10 +489,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev, switch (obj->id) { case SWITCHDEV_OBJ_PORT_FDB: - err = dsa_slave_port_fdb_add(dev, obj); + err = dsa_slave_port_fdb_add(dev, obj, trans); break; case SWITCHDEV_OBJ_PORT_VLAN: - err = dsa_slave_port_vlan_add(dev, obj); + err = dsa_slave_port_vlan_add(dev, obj, trans); break; default: err = -EOPNOTSUPP; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 35e2967ffa18b..d1c7d51620b1a 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -240,7 +240,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * but should not commit the attr. */ - attr->trans_ph = SWITCHDEV_TRANS_PREPARE; + trans.ph = SWITCHDEV_TRANS_PREPARE; err = __switchdev_port_attr_set(dev, attr, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any @@ -249,7 +249,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) */ if (err != -EOPNOTSUPP) { - attr->trans_ph = SWITCHDEV_TRANS_ABORT; + trans.ph = SWITCHDEV_TRANS_ABORT; __switchdev_port_attr_set(dev, attr, &trans); switchdev_trans_items_destroy(&trans); } @@ -262,7 +262,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * because the driver said everythings was OK in phase I. */ - attr->trans_ph = SWITCHDEV_TRANS_COMMIT; + trans.ph = SWITCHDEV_TRANS_COMMIT; err = __switchdev_port_attr_set(dev, attr, &trans); WARN(err, "%s: Commit of attribute (id=%d) failed.\n", dev->name, attr->id); @@ -326,7 +326,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * but should not commit the obj. */ - obj->trans_ph = SWITCHDEV_TRANS_PREPARE; + trans.ph = SWITCHDEV_TRANS_PREPARE; err = __switchdev_port_obj_add(dev, obj, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any @@ -335,7 +335,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) */ if (err != -EOPNOTSUPP) { - obj->trans_ph = SWITCHDEV_TRANS_ABORT; + trans.ph = SWITCHDEV_TRANS_ABORT; __switchdev_port_obj_add(dev, obj, &trans); switchdev_trans_items_destroy(&trans); } @@ -348,7 +348,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * because the driver said everythings was OK in phase I. */ - obj->trans_ph = SWITCHDEV_TRANS_COMMIT; + trans.ph = SWITCHDEV_TRANS_COMMIT; err = __switchdev_port_obj_add(dev, obj, &trans); WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); switchdev_trans_items_warn_destroy(dev, &trans); -- cgit v1.2.3 From 9f6467cf229a0e8a7580401b07de2a76e4c8618d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 24 Sep 2015 10:02:47 +0200 Subject: switchdev: remove "ABORT" transaction phase No longer used by drivers, as transaction queue with item destructors takes care of abort phase internally in switchdev code. So kill it. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 1 - net/switchdev/switchdev.c | 10 ++-------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index f61ee38c7c963..9cf372fe13650 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -19,7 +19,6 @@ enum switchdev_trans_ph { SWITCHDEV_TRANS_PREPARE, - SWITCHDEV_TRANS_ABORT, SWITCHDEV_TRANS_COMMIT, }; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index d1c7d51620b1a..1adeedade0fbb 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -248,11 +248,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * released. */ - if (err != -EOPNOTSUPP) { - trans.ph = SWITCHDEV_TRANS_ABORT; - __switchdev_port_attr_set(dev, attr, &trans); + if (err != -EOPNOTSUPP) switchdev_trans_items_destroy(&trans); - } return err; } @@ -334,11 +331,8 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * released. */ - if (err != -EOPNOTSUPP) { - trans.ph = SWITCHDEV_TRANS_ABORT; - __switchdev_port_obj_add(dev, obj, &trans); + if (err != -EOPNOTSUPP) switchdev_trans_items_destroy(&trans); - } return err; } -- cgit v1.2.3 From f623ab7f51b1bfb523c9cd492747392abf3c4421 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 24 Sep 2015 10:02:49 +0200 Subject: switchdev: reduce transaction phase enum down to a boolean Now, since we have only 2 values for transaction phase, just use bool. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 11 +++-------- net/switchdev/switchdev.c | 8 ++++---- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 9cf372fe13650..18207878e407b 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -17,11 +17,6 @@ #define SWITCHDEV_F_NO_RECURSE BIT(0) -enum switchdev_trans_ph { - SWITCHDEV_TRANS_PREPARE, - SWITCHDEV_TRANS_COMMIT, -}; - struct switchdev_trans_item { struct list_head list; void *data; @@ -30,17 +25,17 @@ struct switchdev_trans_item { struct switchdev_trans { struct list_head item_list; - enum switchdev_trans_ph ph; + bool ph_prepare; }; static inline bool switchdev_trans_ph_prepare(struct switchdev_trans *trans) { - return trans && trans->ph == SWITCHDEV_TRANS_PREPARE; + return trans && trans->ph_prepare; } static inline bool switchdev_trans_ph_commit(struct switchdev_trans *trans) { - return trans && trans->ph == SWITCHDEV_TRANS_COMMIT; + return trans && !trans->ph_prepare; } enum switchdev_attr_id { diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 1adeedade0fbb..00ee547ba45bc 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -240,7 +240,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * but should not commit the attr. */ - trans.ph = SWITCHDEV_TRANS_PREPARE; + trans.ph_prepare = true; err = __switchdev_port_attr_set(dev, attr, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any @@ -259,7 +259,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) * because the driver said everythings was OK in phase I. */ - trans.ph = SWITCHDEV_TRANS_COMMIT; + trans.ph_prepare = false; err = __switchdev_port_attr_set(dev, attr, &trans); WARN(err, "%s: Commit of attribute (id=%d) failed.\n", dev->name, attr->id); @@ -323,7 +323,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * but should not commit the obj. */ - trans.ph = SWITCHDEV_TRANS_PREPARE; + trans.ph_prepare = true; err = __switchdev_port_obj_add(dev, obj, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any @@ -342,7 +342,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) * because the driver said everythings was OK in phase I. */ - trans.ph = SWITCHDEV_TRANS_COMMIT; + trans.ph_prepare = false; err = __switchdev_port_obj_add(dev, obj, &trans); WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); switchdev_trans_items_warn_destroy(dev, &trans); -- cgit v1.2.3 From e23b002b23dfdcd12ca982fbc57dcb071a1fee62 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 29 Sep 2015 12:07:13 -0400 Subject: net: switchdev: remove dev in port_vlan_dump_put The static switchdev_port_vlan_dump_put function does not need the net_device parameter, so remove it. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 00ee547ba45bc..56d34edc74426 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -484,8 +484,7 @@ struct switchdev_vlan_dump { u16 end; }; -static int switchdev_port_vlan_dump_put(struct net_device *dev, - struct switchdev_vlan_dump *dump) +static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) { struct bridge_vlan_info vinfo; @@ -531,7 +530,7 @@ static int switchdev_port_vlan_dump_cb(struct net_device *dev, for (dump->begin = dump->end = vlan->vid_begin; dump->begin <= vlan->vid_end; dump->begin++, dump->end++) { - err = switchdev_port_vlan_dump_put(dev, dump); + err = switchdev_port_vlan_dump_put(dump); if (err) return err; } @@ -543,7 +542,7 @@ static int switchdev_port_vlan_dump_cb(struct net_device *dev, /* prepend */ dump->begin = vlan->vid_begin; } else { - err = switchdev_port_vlan_dump_put(dev, dump); + err = switchdev_port_vlan_dump_put(dump); dump->flags = vlan->flags; dump->begin = vlan->vid_begin; dump->end = vlan->vid_end; @@ -555,7 +554,7 @@ static int switchdev_port_vlan_dump_cb(struct net_device *dev, /* append */ dump->end = vlan->vid_end; } else { - err = switchdev_port_vlan_dump_put(dev, dump); + err = switchdev_port_vlan_dump_put(dump); dump->flags = vlan->flags; dump->begin = vlan->vid_begin; dump->end = vlan->vid_end; @@ -588,7 +587,7 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, goto err_out; if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) /* last one */ - err = switchdev_port_vlan_dump_put(dev, &dump); + err = switchdev_port_vlan_dump_put(&dump); } err_out: -- cgit v1.2.3 From e02a06b2a7c6e8b43c60ed8e0181172231af13d7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 29 Sep 2015 12:07:14 -0400 Subject: net: switchdev: move dev in switchdev_fdb_dump The FDB dump callback requires the related net_device so move it to the struct switchdev_fdb_dump superset instead of using a callback param. With this done, it'll be simpler to change the dump function signature. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 56d34edc74426..c0e2047f89845 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -858,6 +858,7 @@ EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); struct switchdev_fdb_dump { struct switchdev_obj obj; + struct net_device *dev; struct sk_buff *skb; struct netlink_callback *cb; int idx; @@ -887,7 +888,7 @@ static int switchdev_port_fdb_dump_cb(struct net_device *dev, ndm->ndm_pad2 = 0; ndm->ndm_flags = NTF_SELF; ndm->ndm_type = 0; - ndm->ndm_ifindex = dev->ifindex; + ndm->ndm_ifindex = dump->dev->ifindex; ndm->ndm_state = obj->u.fdb.ndm_state; if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, obj->u.fdb.addr)) @@ -927,6 +928,7 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, .id = SWITCHDEV_OBJ_PORT_FDB, .cb = switchdev_port_fdb_dump_cb, }, + .dev = dev, .skb = skb, .cb = cb, .idx = idx, -- cgit v1.2.3 From 03d5fb18626aff95426a380aef0d1c6904cac7c9 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 29 Sep 2015 12:07:15 -0400 Subject: net: switchdev: remove dev from switchdev_obj cb The net_device associated to a dump operation does not have to be passed to the callback. switchdev stores it in a superset struct, if needed. Also some drivers (such as DSA drivers) may not have easy access to it. This will simplify pushing the callback function down to the drivers. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 4 ++-- include/net/switchdev.h | 2 +- net/dsa/slave.c | 4 ++-- net/switchdev/switchdev.c | 6 ++---- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index d3f663262184e..78fd443f2ea16 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4556,7 +4556,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, fdb->ndm_state = NUD_REACHABLE; fdb->vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id); - err = obj->cb(rocker_port->dev, obj); + err = obj->cb(obj); if (err) break; } @@ -4579,7 +4579,7 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, if (rocker_vlan_id_is_internal(htons(vid))) vlan->flags |= BRIDGE_VLAN_INFO_PVID; vlan->vid_begin = vlan->vid_end = vid; - err = obj->cb(rocker_port->dev, obj); + err = obj->cb(obj); if (err) break; } diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 18207878e407b..9ef7c56357698 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -66,7 +66,7 @@ enum switchdev_obj_id { struct switchdev_obj { enum switchdev_obj_id id; - int (*cb)(struct net_device *dev, struct switchdev_obj *obj); + int (*cb)(struct switchdev_obj *obj); union { struct switchdev_obj_vlan { /* PORT_VLAN */ u16 flags; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index f18cae54a5d8f..0b47647961e8c 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -334,7 +334,7 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, if (test_bit(p->port, untagged)) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - err = obj->cb(dev, obj); + err = obj->cb(obj); if (err) break; } @@ -397,7 +397,7 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev, obj->u.fdb.vid = vid; obj->u.fdb.ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; - ret = obj->cb(dev, obj); + ret = obj->cb(obj); if (ret < 0) break; } diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index c0e2047f89845..93f4971e68dba 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -514,8 +514,7 @@ static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) return 0; } -static int switchdev_port_vlan_dump_cb(struct net_device *dev, - struct switchdev_obj *obj) +static int switchdev_port_vlan_dump_cb(struct switchdev_obj *obj) { struct switchdev_vlan_dump *dump = container_of(obj, struct switchdev_vlan_dump, obj); @@ -864,8 +863,7 @@ struct switchdev_fdb_dump { int idx; }; -static int switchdev_port_fdb_dump_cb(struct net_device *dev, - struct switchdev_obj *obj) +static int switchdev_port_fdb_dump_cb(struct switchdev_obj *obj) { struct switchdev_fdb_dump *dump = container_of(obj, struct switchdev_fdb_dump, obj); -- cgit v1.2.3 From 25f07adc473f05f850efc9414b9da3374563015f Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 29 Sep 2015 12:07:16 -0400 Subject: net: switchdev: pass callback to dump operation Similar to the notifier_call callback of a notifier_block, change the function signature of switchdev dump operation to: int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, void *obj, int (*cb)(void *obj)); This allows the caller to pass and expect back a specific switchdev_obj_* structure instead of the generic switchdev_obj one. Drivers implementation of dump operation can now expect this specific structure and call the callback with it. Drivers have been changed accordingly. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 21 +++++++++-------- include/net/switchdev.h | 9 +++++--- net/dsa/slave.c | 26 +++++++++++---------- net/switchdev/switchdev.c | 45 ++++++++++++++++++------------------ 4 files changed, 53 insertions(+), 48 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 78fd443f2ea16..107adb6aee818 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4538,10 +4538,10 @@ static int rocker_port_obj_del(struct net_device *dev, } static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, - struct switchdev_obj *obj) + struct switchdev_obj_fdb *fdb, + int (*cb)(void *obj)) { struct rocker *rocker = rocker_port->rocker; - struct switchdev_obj_fdb *fdb = &obj->u.fdb; struct rocker_fdb_tbl_entry *found; struct hlist_node *tmp; unsigned long lock_flags; @@ -4556,7 +4556,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, fdb->ndm_state = NUD_REACHABLE; fdb->vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id); - err = obj->cb(obj); + err = cb(fdb); if (err) break; } @@ -4566,9 +4566,9 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, } static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, - struct switchdev_obj *obj) + struct switchdev_obj_vlan *vlan, + int (*cb)(void *obj)) { - struct switchdev_obj_vlan *vlan = &obj->u.vlan; u16 vid; int err = 0; @@ -4579,7 +4579,7 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, if (rocker_vlan_id_is_internal(htons(vid))) vlan->flags |= BRIDGE_VLAN_INFO_PVID; vlan->vid_begin = vlan->vid_end = vid; - err = obj->cb(obj); + err = cb(vlan); if (err) break; } @@ -4588,17 +4588,18 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, } static int rocker_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, void *obj, + int (*cb)(void *obj)) { const struct rocker_port *rocker_port = netdev_priv(dev); int err = 0; - switch (obj->id) { + switch (id) { case SWITCHDEV_OBJ_PORT_FDB: - err = rocker_port_fdb_dump(rocker_port, obj); + err = rocker_port_fdb_dump(rocker_port, obj, cb); break; case SWITCHDEV_OBJ_PORT_VLAN: - err = rocker_port_vlan_dump(rocker_port, obj); + err = rocker_port_vlan_dump(rocker_port, obj, cb); break; default: err = -EOPNOTSUPP; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 9ef7c56357698..a2f57fb5f6226 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -120,7 +120,8 @@ struct switchdev_ops { int (*switchdev_port_obj_del)(struct net_device *dev, struct switchdev_obj *obj); int (*switchdev_port_obj_dump)(struct net_device *dev, - struct switchdev_obj *obj); + enum switchdev_obj_id id, void *obj, + int (*cb)(void *obj)); }; enum switchdev_notifier_type { @@ -152,7 +153,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj); int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj); -int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj); +int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, + void *obj, int (*cb)(void *obj)); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); int call_switchdev_notifiers(unsigned long val, struct net_device *dev, @@ -209,7 +211,8 @@ static inline int switchdev_port_obj_del(struct net_device *dev, } static inline int switchdev_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, void *obj, + int (*cb)(void *obj)) { return -EOPNOTSUPP; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0b47647961e8c..c3b868c3373bf 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -300,9 +300,9 @@ static int dsa_slave_port_vlan_del(struct net_device *dev, } static int dsa_slave_port_vlan_dump(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj_vlan *vlan, + int (*cb)(void *obj)) { - struct switchdev_obj_vlan *vlan = &obj->u.vlan; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; DECLARE_BITMAP(members, DSA_MAX_PORTS); @@ -334,7 +334,7 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, if (test_bit(p->port, untagged)) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - err = obj->cb(obj); + err = cb(vlan); if (err) break; } @@ -374,7 +374,8 @@ static int dsa_slave_port_fdb_del(struct net_device *dev, } static int dsa_slave_port_fdb_dump(struct net_device *dev, - struct switchdev_obj *obj) + struct switchdev_obj_fdb *fdb, + int (*cb)(void *obj)) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; @@ -393,11 +394,11 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev, if (ret < 0) break; - obj->u.fdb.addr = addr; - obj->u.fdb.vid = vid; - obj->u.fdb.ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; + fdb->addr = addr; + fdb->vid = vid; + fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; - ret = obj->cb(obj); + ret = cb(fdb); if (ret < 0) break; } @@ -518,16 +519,17 @@ static int dsa_slave_port_obj_del(struct net_device *dev, } static int dsa_slave_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, void *obj, + int (*cb)(void *obj)) { int err; - switch (obj->id) { + switch (id) { case SWITCHDEV_OBJ_PORT_FDB: - err = dsa_slave_port_fdb_dump(dev, obj); + err = dsa_slave_port_fdb_dump(dev, obj, cb); break; case SWITCHDEV_OBJ_PORT_VLAN: - err = dsa_slave_port_vlan_dump(dev, obj); + err = dsa_slave_port_vlan_dump(dev, obj, cb); break; default: err = -EOPNOTSUPP; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 93f4971e68dba..2ef863c963596 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -386,9 +386,12 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_del); * switchdev_port_obj_dump - Dump port objects * * @dev: port device + * @id: object ID * @obj: object to dump + * @cb: function to call with a filled object */ -int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj) +int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, + void *obj, int (*cb)(void *obj)) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -396,7 +399,7 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj) int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_dump) - return ops->switchdev_port_obj_dump(dev, obj); + return ops->switchdev_port_obj_dump(dev, id, obj, cb); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to dump objects on @@ -404,7 +407,7 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj) */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_obj_dump(lower_dev, obj); + err = switchdev_port_obj_dump(lower_dev, id, obj, cb); break; } @@ -476,7 +479,7 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, EXPORT_SYMBOL_GPL(call_switchdev_notifiers); struct switchdev_vlan_dump { - struct switchdev_obj obj; + struct switchdev_obj_vlan vlan; struct sk_buff *skb; u32 filter_mask; u16 flags; @@ -514,11 +517,11 @@ static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) return 0; } -static int switchdev_port_vlan_dump_cb(struct switchdev_obj *obj) +static int switchdev_port_vlan_dump_cb(void *obj) { + struct switchdev_obj_vlan *vlan = obj; struct switchdev_vlan_dump *dump = - container_of(obj, struct switchdev_vlan_dump, obj); - struct switchdev_obj_vlan *vlan = &dump->obj.u.vlan; + container_of(vlan, struct switchdev_vlan_dump, vlan); int err = 0; if (vlan->vid_begin > vlan->vid_end) @@ -570,10 +573,6 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, u32 filter_mask) { struct switchdev_vlan_dump dump = { - .obj = { - .id = SWITCHDEV_OBJ_PORT_VLAN, - .cb = switchdev_port_vlan_dump_cb, - }, .skb = skb, .filter_mask = filter_mask, }; @@ -581,7 +580,9 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, if ((filter_mask & RTEXT_FILTER_BRVLAN) || (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { - err = switchdev_port_obj_dump(dev, &dump.obj); + err = switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_PORT_VLAN, + &dump.vlan, + switchdev_port_vlan_dump_cb); if (err) goto err_out; if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) @@ -856,17 +857,18 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); struct switchdev_fdb_dump { - struct switchdev_obj obj; + struct switchdev_obj_fdb fdb; struct net_device *dev; struct sk_buff *skb; struct netlink_callback *cb; int idx; }; -static int switchdev_port_fdb_dump_cb(struct switchdev_obj *obj) +static int switchdev_port_fdb_dump_cb(void *obj) { + struct switchdev_obj_fdb *fdb = obj; struct switchdev_fdb_dump *dump = - container_of(obj, struct switchdev_fdb_dump, obj); + container_of(fdb, struct switchdev_fdb_dump, fdb); u32 portid = NETLINK_CB(dump->cb->skb).portid; u32 seq = dump->cb->nlh->nlmsg_seq; struct nlmsghdr *nlh; @@ -887,12 +889,12 @@ static int switchdev_port_fdb_dump_cb(struct switchdev_obj *obj) ndm->ndm_flags = NTF_SELF; ndm->ndm_type = 0; ndm->ndm_ifindex = dump->dev->ifindex; - ndm->ndm_state = obj->u.fdb.ndm_state; + ndm->ndm_state = fdb->ndm_state; - if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, obj->u.fdb.addr)) + if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, fdb->addr)) goto nla_put_failure; - if (obj->u.fdb.vid && nla_put_u16(dump->skb, NDA_VLAN, obj->u.fdb.vid)) + if (fdb->vid && nla_put_u16(dump->skb, NDA_VLAN, fdb->vid)) goto nla_put_failure; nlmsg_end(dump->skb, nlh); @@ -922,17 +924,14 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *filter_dev, int idx) { struct switchdev_fdb_dump dump = { - .obj = { - .id = SWITCHDEV_OBJ_PORT_FDB, - .cb = switchdev_port_fdb_dump_cb, - }, .dev = dev, .skb = skb, .cb = cb, .idx = idx, }; - switchdev_port_obj_dump(dev, &dump.obj); + switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_PORT_FDB, &dump.fdb, + switchdev_port_fdb_dump_cb); return dump.idx; } EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); -- cgit v1.2.3 From ab06900230181b5a717b1e1a39c44e96f6292e71 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 29 Sep 2015 12:07:17 -0400 Subject: net: switchdev: abstract object in add/del ops Similar to the notifier_call callback of a notifier_block, change the function signature of switchdev add and del operations to: int switchdev_port_obj_add/del(struct net_device *dev, enum switchdev_obj_id id, void *obj); This allows the caller to pass a specific switchdev_obj_* structure instead of the generic switchdev_obj one. Drivers implementation of these operations and switchdev have been changed accordingly. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 21 +++--- include/net/switchdev.h | 18 ++++-- net/bridge/br_fdb.c | 11 ++-- net/bridge/br_vlan.c | 24 +++---- net/dsa/slave.c | 20 +++--- net/switchdev/switchdev.c | 122 ++++++++++++++++------------------- 6 files changed, 99 insertions(+), 117 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 107adb6aee818..9773f5b652969 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4437,26 +4437,25 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port, } static int rocker_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj, + enum switchdev_obj_id id, const void *obj, struct switchdev_trans *trans) { struct rocker_port *rocker_port = netdev_priv(dev); const struct switchdev_obj_ipv4_fib *fib4; int err = 0; - switch (obj->id) { + switch (id) { case SWITCHDEV_OBJ_PORT_VLAN: - err = rocker_port_vlans_add(rocker_port, trans, - &obj->u.vlan); + err = rocker_port_vlans_add(rocker_port, trans, obj); break; case SWITCHDEV_OBJ_IPV4_FIB: - fib4 = &obj->u.ipv4_fib; + fib4 = obj; err = rocker_port_fib_ipv4(rocker_port, trans, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, 0); break; case SWITCHDEV_OBJ_PORT_FDB: - err = rocker_port_fdb_add(rocker_port, trans, &obj->u.fdb); + err = rocker_port_fdb_add(rocker_port, trans, obj); break; default: err = -EOPNOTSUPP; @@ -4509,25 +4508,25 @@ static int rocker_port_fdb_del(struct rocker_port *rocker_port, } static int rocker_port_obj_del(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, const void *obj) { struct rocker_port *rocker_port = netdev_priv(dev); const struct switchdev_obj_ipv4_fib *fib4; int err = 0; - switch (obj->id) { + switch (id) { case SWITCHDEV_OBJ_PORT_VLAN: - err = rocker_port_vlans_del(rocker_port, &obj->u.vlan); + err = rocker_port_vlans_del(rocker_port, obj); break; case SWITCHDEV_OBJ_IPV4_FIB: - fib4 = &obj->u.ipv4_fib; + fib4 = obj; err = rocker_port_fib_ipv4(rocker_port, NULL, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, ROCKER_OP_FLAG_REMOVE); break; case SWITCHDEV_OBJ_PORT_FDB: - err = rocker_port_fdb_del(rocker_port, NULL, &obj->u.fdb); + err = rocker_port_fdb_del(rocker_port, NULL, obj); break; default: err = -EOPNOTSUPP; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index a2f57fb5f6226..bcadac33c29c2 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -115,10 +115,12 @@ struct switchdev_ops { struct switchdev_attr *attr, struct switchdev_trans *trans); int (*switchdev_port_obj_add)(struct net_device *dev, - struct switchdev_obj *obj, + enum switchdev_obj_id id, + const void *obj, struct switchdev_trans *trans); int (*switchdev_port_obj_del)(struct net_device *dev, - struct switchdev_obj *obj); + enum switchdev_obj_id id, + const void *obj); int (*switchdev_port_obj_dump)(struct net_device *dev, enum switchdev_obj_id id, void *obj, int (*cb)(void *obj)); @@ -151,8 +153,10 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); -int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj); -int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj); +int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, + const void *obj); +int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, + const void *obj); int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, void *obj, int (*cb)(void *obj)); int register_switchdev_notifier(struct notifier_block *nb); @@ -199,13 +203,15 @@ static inline int switchdev_port_attr_set(struct net_device *dev, } static inline int switchdev_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, + const void *obj) { return -EOPNOTSUPP; } static inline int switchdev_port_obj_del(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, + const void *obj) { return -EOPNOTSUPP; } diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 41de11e2eb112..7826782d62ab6 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -133,15 +133,12 @@ static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr) static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) { - struct switchdev_obj obj = { - .id = SWITCHDEV_OBJ_PORT_FDB, - .u.fdb = { - .addr = f->addr.addr, - .vid = f->vlan_id, - }, + struct switchdev_obj_fdb fdb = { + .addr = f->addr.addr, + .vid = f->vlan_id, }; - switchdev_port_obj_del(f->dst->dev, &obj); + switchdev_port_obj_del(f->dst->dev, SWITCHDEV_OBJ_PORT_FDB, &fdb); } static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 8b392070051c0..e227164bc3e17 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -80,16 +80,13 @@ static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, if (ops->ndo_vlan_rx_add_vid) { err = vlan_vid_add(dev, br->vlan_proto, vid); } else { - struct switchdev_obj vlan_obj = { - .id = SWITCHDEV_OBJ_PORT_VLAN, - .u.vlan = { - .flags = flags, - .vid_begin = vid, - .vid_end = vid, - }, + struct switchdev_obj_vlan v = { + .flags = flags, + .vid_begin = vid, + .vid_end = vid, }; - err = switchdev_port_obj_add(dev, &vlan_obj); + err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_PORT_VLAN, &v); if (err == -EOPNOTSUPP) err = 0; } @@ -132,15 +129,12 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, if (ops->ndo_vlan_rx_kill_vid) { vlan_vid_del(dev, br->vlan_proto, vid); } else { - struct switchdev_obj vlan_obj = { - .id = SWITCHDEV_OBJ_PORT_VLAN, - .u.vlan = { - .vid_begin = vid, - .vid_end = vid, - }, + struct switchdev_obj_vlan v = { + .vid_begin = vid, + .vid_end = vid, }; - err = switchdev_port_obj_del(dev, &vlan_obj); + err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_PORT_VLAN, &v); if (err == -EOPNOTSUPP) err = 0; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index c3b868c3373bf..04f01535d2b6a 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -242,10 +242,9 @@ static int dsa_bridge_check_vlan_range(struct dsa_switch *ds, } static int dsa_slave_port_vlan_add(struct net_device *dev, - struct switchdev_obj *obj, + const struct switchdev_obj_vlan *vlan, struct switchdev_trans *trans) { - struct switchdev_obj_vlan *vlan = &obj->u.vlan; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; u16 vid; @@ -279,9 +278,8 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, } static int dsa_slave_port_vlan_del(struct net_device *dev, - struct switchdev_obj *obj) + const struct switchdev_obj_vlan *vlan) { - struct switchdev_obj_vlan *vlan = &obj->u.vlan; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; u16 vid; @@ -343,10 +341,9 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, } static int dsa_slave_port_fdb_add(struct net_device *dev, - struct switchdev_obj *obj, + const struct switchdev_obj_fdb *fdb, struct switchdev_trans *trans) { - struct switchdev_obj_fdb *fdb = &obj->u.fdb; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret = -EOPNOTSUPP; @@ -360,9 +357,8 @@ static int dsa_slave_port_fdb_add(struct net_device *dev, } static int dsa_slave_port_fdb_del(struct net_device *dev, - struct switchdev_obj *obj) + const struct switchdev_obj_fdb *fdb) { - struct switchdev_obj_fdb *fdb = &obj->u.fdb; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; int ret = -EOPNOTSUPP; @@ -473,7 +469,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev, } static int dsa_slave_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj, + enum switchdev_obj_id id, const void *obj, struct switchdev_trans *trans) { int err; @@ -483,7 +479,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev, * supported, return -EOPNOTSUPP. */ - switch (obj->id) { + switch (id) { case SWITCHDEV_OBJ_PORT_FDB: err = dsa_slave_port_fdb_add(dev, obj, trans); break; @@ -499,11 +495,11 @@ static int dsa_slave_port_obj_add(struct net_device *dev, } static int dsa_slave_port_obj_del(struct net_device *dev, - struct switchdev_obj *obj) + enum switchdev_obj_id id, const void *obj) { int err; - switch (obj->id) { + switch (id) { case SWITCHDEV_OBJ_PORT_FDB: err = dsa_slave_port_fdb_del(dev, obj); break; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 2ef863c963596..fe82fab1d55c1 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -270,7 +270,7 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) EXPORT_SYMBOL_GPL(switchdev_port_attr_set); static int __switchdev_port_obj_add(struct net_device *dev, - struct switchdev_obj *obj, + enum switchdev_obj_id id, const void *obj, struct switchdev_trans *trans) { const struct switchdev_ops *ops = dev->switchdev_ops; @@ -279,7 +279,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_add) - return ops->switchdev_port_obj_add(dev, obj, trans); + return ops->switchdev_port_obj_add(dev, id, obj, trans); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to add object on @@ -287,7 +287,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = __switchdev_port_obj_add(lower_dev, obj, trans); + err = __switchdev_port_obj_add(lower_dev, id, obj, trans); if (err) break; } @@ -299,6 +299,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, * switchdev_port_obj_add - Add port object * * @dev: port device + * @id: object ID * @obj: object to add * * Use a 2-phase prepare-commit transaction model to ensure @@ -307,7 +308,8 @@ static int __switchdev_port_obj_add(struct net_device *dev, * * rtnl_lock must be held. */ -int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) +int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, + const void *obj) { struct switchdev_trans trans; int err; @@ -324,7 +326,7 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) */ trans.ph_prepare = true; - err = __switchdev_port_obj_add(dev, obj, &trans); + err = __switchdev_port_obj_add(dev, id, obj, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any * resources reserved in the prepare phase are @@ -343,8 +345,8 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) */ trans.ph_prepare = false; - err = __switchdev_port_obj_add(dev, obj, &trans); - WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); + err = __switchdev_port_obj_add(dev, id, obj, &trans); + WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, id); switchdev_trans_items_warn_destroy(dev, &trans); return err; @@ -355,9 +357,11 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_add); * switchdev_port_obj_del - Delete port object * * @dev: port device + * @id: object ID * @obj: object to delete */ -int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) +int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, + const void *obj) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -365,7 +369,7 @@ int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_del) - return ops->switchdev_port_obj_del(dev, obj); + return ops->switchdev_port_obj_del(dev, id, obj); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to delete object on @@ -373,7 +377,7 @@ int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj) */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_obj_del(lower_dev, obj); + err = switchdev_port_obj_del(lower_dev, id, obj); if (err) break; } @@ -695,14 +699,12 @@ static int switchdev_port_br_setlink_protinfo(struct net_device *dev, static int switchdev_port_br_afspec(struct net_device *dev, struct nlattr *afspec, int (*f)(struct net_device *dev, - struct switchdev_obj *obj)) + enum switchdev_obj_id id, + const void *obj)) { struct nlattr *attr; struct bridge_vlan_info *vinfo; - struct switchdev_obj obj = { - .id = SWITCHDEV_OBJ_PORT_VLAN, - }; - struct switchdev_obj_vlan *vlan = &obj.u.vlan; + struct switchdev_obj_vlan vlan = { 0 }; int rem; int err; @@ -712,30 +714,30 @@ static int switchdev_port_br_afspec(struct net_device *dev, if (nla_len(attr) != sizeof(struct bridge_vlan_info)) return -EINVAL; vinfo = nla_data(attr); - vlan->flags = vinfo->flags; + vlan.flags = vinfo->flags; if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { - if (vlan->vid_begin) + if (vlan.vid_begin) return -EINVAL; - vlan->vid_begin = vinfo->vid; + vlan.vid_begin = vinfo->vid; } else if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) { - if (!vlan->vid_begin) + if (!vlan.vid_begin) return -EINVAL; - vlan->vid_end = vinfo->vid; - if (vlan->vid_end <= vlan->vid_begin) + vlan.vid_end = vinfo->vid; + if (vlan.vid_end <= vlan.vid_begin) return -EINVAL; - err = f(dev, &obj); + err = f(dev, SWITCHDEV_OBJ_PORT_VLAN, &vlan); if (err) return err; - memset(vlan, 0, sizeof(*vlan)); + memset(&vlan, 0, sizeof(vlan)); } else { - if (vlan->vid_begin) + if (vlan.vid_begin) return -EINVAL; - vlan->vid_begin = vinfo->vid; - vlan->vid_end = vinfo->vid; - err = f(dev, &obj); + vlan.vid_begin = vinfo->vid; + vlan.vid_end = vinfo->vid; + err = f(dev, SWITCHDEV_OBJ_PORT_VLAN, &vlan); if (err) return err; - memset(vlan, 0, sizeof(*vlan)); + memset(&vlan, 0, sizeof(vlan)); } } @@ -817,15 +819,12 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, u16 nlm_flags) { - struct switchdev_obj obj = { - .id = SWITCHDEV_OBJ_PORT_FDB, - .u.fdb = { - .addr = addr, - .vid = vid, - }, + struct switchdev_obj_fdb fdb = { + .addr = addr, + .vid = vid, }; - return switchdev_port_obj_add(dev, &obj); + return switchdev_port_obj_add(dev, SWITCHDEV_OBJ_PORT_FDB, &fdb); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); @@ -844,15 +843,12 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid) { - struct switchdev_obj obj = { - .id = SWITCHDEV_OBJ_PORT_FDB, - .u.fdb = { - .addr = addr, - .vid = vid, - }, + struct switchdev_obj_fdb fdb = { + .addr = addr, + .vid = vid, }; - return switchdev_port_obj_del(dev, &obj); + return switchdev_port_obj_del(dev, SWITCHDEV_OBJ_PORT_FDB, &fdb); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); @@ -1009,17 +1005,14 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, u32 tb_id) { - struct switchdev_obj fib_obj = { - .id = SWITCHDEV_OBJ_IPV4_FIB, - .u.ipv4_fib = { - .dst = dst, - .dst_len = dst_len, - .fi = fi, - .tos = tos, - .type = type, - .nlflags = nlflags, - .tb_id = tb_id, - }, + struct switchdev_obj_ipv4_fib ipv4_fib = { + .dst = dst, + .dst_len = dst_len, + .fi = fi, + .tos = tos, + .type = type, + .nlflags = nlflags, + .tb_id = tb_id, }; struct net_device *dev; int err = 0; @@ -1040,7 +1033,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_add(dev, &fib_obj); + err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_IPV4_FIB, &ipv4_fib); if (!err) fi->fib_flags |= RTNH_F_OFFLOAD; @@ -1063,17 +1056,14 @@ EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_add); int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 tb_id) { - struct switchdev_obj fib_obj = { - .id = SWITCHDEV_OBJ_IPV4_FIB, - .u.ipv4_fib = { - .dst = dst, - .dst_len = dst_len, - .fi = fi, - .tos = tos, - .type = type, - .nlflags = 0, - .tb_id = tb_id, - }, + struct switchdev_obj_ipv4_fib ipv4_fib = { + .dst = dst, + .dst_len = dst_len, + .fi = fi, + .tos = tos, + .type = type, + .nlflags = 0, + .tb_id = tb_id, }; struct net_device *dev; int err = 0; @@ -1085,7 +1075,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_del(dev, &fib_obj); + err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_IPV4_FIB, &ipv4_fib); if (!err) fi->fib_flags &= ~RTNH_F_OFFLOAD; -- cgit v1.2.3 From 57d80838dae55c1bc6ca629e471c84100513079a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Oct 2015 11:03:41 +0200 Subject: switchdev: rename SWITCHDEV_OBJ_* enum values to SWITCHDEV_OBJ_ID_* Suggested-by: Vivien Didelot Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 6 +++--- drivers/net/ethernet/rocker/rocker.c | 16 ++++++++-------- include/net/switchdev.h | 14 +++++++------- net/bridge/br_fdb.c | 2 +- net/bridge/br_vlan.c | 6 ++++-- net/dsa/slave.c | 12 ++++++------ net/switchdev/switchdev.c | 16 ++++++++-------- 7 files changed, 37 insertions(+), 35 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt index 9f9e2587b3479..c150a87c774b2 100644 --- a/Documentation/networking/switchdev.txt +++ b/Documentation/networking/switchdev.txt @@ -178,7 +178,7 @@ entries are installed, for example, using iproute2 bridge cmd: bridge fdb add ADDR dev DEV [vlan VID] [self] The driver should use the helper switchdev_port_fdb_xxx ops for ndo_fdb_xxx -ops, and handle add/delete/dump of SWITCHDEV_OBJ_PORT_FDB object using +ops, and handle add/delete/dump of SWITCHDEV_OBJ_ID_PORT_FDB object using switchdev_port_obj_xxx ops. XXX: what should be done if offloading this rule to hardware fails (for @@ -316,9 +316,9 @@ SWITCHDEV_OBJ_IPV[4|6]_FIB object using switchdev_port_obj_xxx ops. switchdev_port_obj_add is used for both adding a new FIB entry to the device, or modifying an existing entry on the device. -XXX: Currently, only SWITCHDEV_OBJ_IPV4_FIB objects are supported. +XXX: Currently, only SWITCHDEV_OBJ_ID_IPV4_FIB objects are supported. -SWITCHDEV_OBJ_IPV4_FIB object passes: +SWITCHDEV_OBJ_ID_IPV4_FIB object passes: struct switchdev_obj_ipv4_fib { /* IPV4_FIB */ u32 dst; diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 9773f5b652969..9b2e8bed8f837 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4445,16 +4445,16 @@ static int rocker_port_obj_add(struct net_device *dev, int err = 0; switch (id) { - case SWITCHDEV_OBJ_PORT_VLAN: + case SWITCHDEV_OBJ_ID_PORT_VLAN: err = rocker_port_vlans_add(rocker_port, trans, obj); break; - case SWITCHDEV_OBJ_IPV4_FIB: + case SWITCHDEV_OBJ_ID_IPV4_FIB: fib4 = obj; err = rocker_port_fib_ipv4(rocker_port, trans, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, 0); break; - case SWITCHDEV_OBJ_PORT_FDB: + case SWITCHDEV_OBJ_ID_PORT_FDB: err = rocker_port_fdb_add(rocker_port, trans, obj); break; default: @@ -4515,17 +4515,17 @@ static int rocker_port_obj_del(struct net_device *dev, int err = 0; switch (id) { - case SWITCHDEV_OBJ_PORT_VLAN: + case SWITCHDEV_OBJ_ID_PORT_VLAN: err = rocker_port_vlans_del(rocker_port, obj); break; - case SWITCHDEV_OBJ_IPV4_FIB: + case SWITCHDEV_OBJ_ID_IPV4_FIB: fib4 = obj; err = rocker_port_fib_ipv4(rocker_port, NULL, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, ROCKER_OP_FLAG_REMOVE); break; - case SWITCHDEV_OBJ_PORT_FDB: + case SWITCHDEV_OBJ_ID_PORT_FDB: err = rocker_port_fdb_del(rocker_port, NULL, obj); break; default: @@ -4594,10 +4594,10 @@ static int rocker_port_obj_dump(struct net_device *dev, int err = 0; switch (id) { - case SWITCHDEV_OBJ_PORT_FDB: + case SWITCHDEV_OBJ_ID_PORT_FDB: err = rocker_port_fdb_dump(rocker_port, obj, cb); break; - case SWITCHDEV_OBJ_PORT_VLAN: + case SWITCHDEV_OBJ_ID_PORT_VLAN: err = rocker_port_vlan_dump(rocker_port, obj, cb); break; default: diff --git a/include/net/switchdev.h b/include/net/switchdev.h index e11425eb07353..11f9c706cf5c7 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -58,20 +58,20 @@ struct switchdev_attr { struct fib_info; enum switchdev_obj_id { - SWITCHDEV_OBJ_UNDEFINED, - SWITCHDEV_OBJ_PORT_VLAN, - SWITCHDEV_OBJ_IPV4_FIB, - SWITCHDEV_OBJ_PORT_FDB, + SWITCHDEV_OBJ_ID_UNDEFINED, + SWITCHDEV_OBJ_ID_PORT_VLAN, + SWITCHDEV_OBJ_ID_IPV4_FIB, + SWITCHDEV_OBJ_ID_PORT_FDB, }; -/* SWITCHDEV_OBJ_PORT_VLAN */ +/* SWITCHDEV_OBJ_ID_PORT_VLAN */ struct switchdev_obj_vlan { u16 flags; u16 vid_begin; u16 vid_end; }; -/* SWITCHDEV_OBJ_IPV4_FIB */ +/* SWITCHDEV_OBJ_ID_IPV4_FIB */ struct switchdev_obj_ipv4_fib { u32 dst; int dst_len; @@ -82,7 +82,7 @@ struct switchdev_obj_ipv4_fib { u32 tb_id; }; -/* SWITCHDEV_OBJ_PORT_FDB */ +/* SWITCHDEV_OBJ_ID_PORT_FDB */ struct switchdev_obj_fdb { const unsigned char *addr; u16 vid; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 7826782d62ab6..6fc8e71277d44 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -138,7 +138,7 @@ static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) .vid = f->vlan_id, }; - switchdev_port_obj_del(f->dst->dev, SWITCHDEV_OBJ_PORT_FDB, &fdb); + switchdev_port_obj_del(f->dst->dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb); } static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 75214a51cf0e0..68b5a11256671 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -88,7 +88,8 @@ static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, .vid_end = vid, }; - err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_PORT_VLAN, &v); + err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, + &v); if (err == -EOPNOTSUPP) err = 0; } @@ -136,7 +137,8 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, .vid_end = vid, }; - err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_PORT_VLAN, &v); + err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, + &v); if (err == -EOPNOTSUPP) err = 0; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 7b1d9ec74e092..a7060298b8563 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -485,10 +485,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev, */ switch (id) { - case SWITCHDEV_OBJ_PORT_FDB: + case SWITCHDEV_OBJ_ID_PORT_FDB: err = dsa_slave_port_fdb_add(dev, obj, trans); break; - case SWITCHDEV_OBJ_PORT_VLAN: + case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_port_vlan_add(dev, obj, trans); break; default: @@ -505,10 +505,10 @@ static int dsa_slave_port_obj_del(struct net_device *dev, int err; switch (id) { - case SWITCHDEV_OBJ_PORT_FDB: + case SWITCHDEV_OBJ_ID_PORT_FDB: err = dsa_slave_port_fdb_del(dev, obj); break; - case SWITCHDEV_OBJ_PORT_VLAN: + case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_port_vlan_del(dev, obj); break; default: @@ -526,10 +526,10 @@ static int dsa_slave_port_obj_dump(struct net_device *dev, int err; switch (id) { - case SWITCHDEV_OBJ_PORT_FDB: + case SWITCHDEV_OBJ_ID_PORT_FDB: err = dsa_slave_port_fdb_dump(dev, obj, cb); break; - case SWITCHDEV_OBJ_PORT_VLAN: + case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_slave_port_vlan_dump(dev, obj, cb); break; default: diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index fe82fab1d55c1..5b1aa9f6f2615 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -584,7 +584,7 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, if ((filter_mask & RTEXT_FILTER_BRVLAN) || (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { - err = switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_PORT_VLAN, + err = switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &dump.vlan, switchdev_port_vlan_dump_cb); if (err) @@ -725,7 +725,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, vlan.vid_end = vinfo->vid; if (vlan.vid_end <= vlan.vid_begin) return -EINVAL; - err = f(dev, SWITCHDEV_OBJ_PORT_VLAN, &vlan); + err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan); if (err) return err; memset(&vlan, 0, sizeof(vlan)); @@ -734,7 +734,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, return -EINVAL; vlan.vid_begin = vinfo->vid; vlan.vid_end = vinfo->vid; - err = f(dev, SWITCHDEV_OBJ_PORT_VLAN, &vlan); + err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan); if (err) return err; memset(&vlan, 0, sizeof(vlan)); @@ -824,7 +824,7 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], .vid = vid, }; - return switchdev_port_obj_add(dev, SWITCHDEV_OBJ_PORT_FDB, &fdb); + return switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); @@ -848,7 +848,7 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], .vid = vid, }; - return switchdev_port_obj_del(dev, SWITCHDEV_OBJ_PORT_FDB, &fdb); + return switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); @@ -926,7 +926,7 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, .idx = idx, }; - switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_PORT_FDB, &dump.fdb, + switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &dump.fdb, switchdev_port_fdb_dump_cb); return dump.idx; } @@ -1033,7 +1033,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_IPV4_FIB, &ipv4_fib); + err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, &ipv4_fib); if (!err) fi->fib_flags |= RTNH_F_OFFLOAD; @@ -1075,7 +1075,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_IPV4_FIB, &ipv4_fib); + err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, &ipv4_fib); if (!err) fi->fib_flags &= ~RTNH_F_OFFLOAD; -- cgit v1.2.3 From 1f86839874a50c9ee2009567d2f312b1e1949e24 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Oct 2015 11:03:42 +0200 Subject: switchdev: rename SWITCHDEV_ATTR_* enum values to SWITCHDEV_ATTR_ID_* To be aligned with obj. Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 9 +++++---- drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 2 +- drivers/net/ethernet/rocker/rocker.c | 8 ++++---- include/net/switchdev.h | 8 ++++---- net/bridge/br_stp.c | 2 +- net/core/net-sysfs.c | 2 +- net/core/rtnetlink.c | 2 +- net/dsa/slave.c | 4 ++-- net/switchdev/switchdev.c | 14 +++++++------- 9 files changed, 26 insertions(+), 25 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt index c150a87c774b2..0714fe5550165 100644 --- a/Documentation/networking/switchdev.txt +++ b/Documentation/networking/switchdev.txt @@ -115,7 +115,7 @@ Switch ID ^^^^^^^^^ The switchdev driver must implement the switchdev op switchdev_port_attr_get -for SWITCHDEV_ATTR_PORT_PARENT_ID for each port netdev, returning the same +for SWITCHDEV_ATTR_ID_PORT_PARENT_ID for each port netdev, returning the same physical ID for each port of a switch. The ID must be unique between switches on the same system. The ID does not need to be unique between switches on different systems. @@ -233,8 +233,9 @@ the bridge's FDB. It's possible, but not optimal, to enable learning on the device port and on the bridge port, and disable learning_sync. To support learning and learning_sync port attributes, the driver implements -switchdev op switchdev_port_attr_get/set for SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS. -The driver should initialize the attributes to the hardware defaults. +switchdev op switchdev_port_attr_get/set for +SWITCHDEV_ATTR_PORT_ID_BRIDGE_FLAGS. The driver should initialize the attributes +to the hardware defaults. FDB Ageing ^^^^^^^^^^ @@ -260,7 +261,7 @@ STP State Change on Port Internally or with a third-party STP protocol implementation (e.g. mstpd), the bridge driver maintains the STP state for ports, and will notify the switch driver of STP state change on a port using the switchdev op -switchdev_attr_port_set for SWITCHDEV_ATTR_PORT_STP_UPDATE. +switchdev_attr_port_set for SWITCHDEV_ATTR_PORT_ID_STP_UPDATE. State is one of BR_STATE_*. The switch driver can use STP state updates to update ingress packet filter list for the port. For example, if port is diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 3e52ee93438c0..d448431bbc838 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -868,7 +868,7 @@ static int mlxsw_sx_port_attr_get(struct net_device *dev, struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; switch (attr->id) { - case SWITCHDEV_ATTR_PORT_PARENT_ID: + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: attr->u.ppid.id_len = sizeof(mlxsw_sx->hw_id); memcpy(&attr->u.ppid.id, &mlxsw_sx->hw_id, attr->u.ppid.id_len); break; diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 9b2e8bed8f837..4540ca63a434e 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4329,11 +4329,11 @@ static int rocker_port_attr_get(struct net_device *dev, const struct rocker *rocker = rocker_port->rocker; switch (attr->id) { - case SWITCHDEV_ATTR_PORT_PARENT_ID: + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: attr->u.ppid.id_len = sizeof(rocker->hw.id); memcpy(&attr->u.ppid.id, &rocker->hw.id, attr->u.ppid.id_len); break; - case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: attr->u.brport_flags = rocker_port->brport_flags; break; default: @@ -4369,12 +4369,12 @@ static int rocker_port_attr_set(struct net_device *dev, int err = 0; switch (attr->id) { - case SWITCHDEV_ATTR_PORT_STP_STATE: + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: err = rocker_port_stp_update(rocker_port, trans, ROCKER_OP_FLAG_NOWAIT, attr->u.stp_state); break; - case SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS: + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: err = rocker_port_brport_flags_set(rocker_port, trans, attr->u.brport_flags); break; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 11f9c706cf5c7..612719b9618a6 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -39,10 +39,10 @@ static inline bool switchdev_trans_ph_commit(struct switchdev_trans *trans) } enum switchdev_attr_id { - SWITCHDEV_ATTR_UNDEFINED, - SWITCHDEV_ATTR_PORT_PARENT_ID, - SWITCHDEV_ATTR_PORT_STP_STATE, - SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS, + SWITCHDEV_ATTR_ID_UNDEFINED, + SWITCHDEV_ATTR_ID_PORT_PARENT_ID, + SWITCHDEV_ATTR_ID_PORT_STP_STATE, + SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, }; struct switchdev_attr { diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 3a7392e6010e8..3a982c02599ab 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -40,7 +40,7 @@ void br_log_state(const struct net_bridge_port *p) void br_set_state(struct net_bridge_port *p, unsigned int state) { struct switchdev_attr attr = { - .id = SWITCHDEV_ATTR_PORT_STP_STATE, + .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, .u.stp_state = state, }; int err; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 410c6e42bf1f5..f88a62ab019d2 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -471,7 +471,7 @@ static ssize_t phys_switch_id_show(struct device *dev, if (dev_isalive(netdev)) { struct switchdev_attr attr = { - .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, .flags = SWITCHDEV_F_NO_RECURSE, }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 474a6da3b51ab..b2258a36d8944 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1025,7 +1025,7 @@ static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) { int err; struct switchdev_attr attr = { - .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, .flags = SWITCHDEV_F_NO_RECURSE, }; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a7060298b8563..8992568f5c0ed 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -458,7 +458,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev, int ret; switch (attr->id) { - case SWITCHDEV_ATTR_PORT_STP_STATE: + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: if (switchdev_trans_ph_prepare(trans)) ret = ds->drv->port_stp_update ? 0 : -EOPNOTSUPP; else @@ -584,7 +584,7 @@ static int dsa_slave_port_attr_get(struct net_device *dev, struct dsa_switch *ds = p->parent; switch (attr->id) { - case SWITCHDEV_ATTR_PORT_PARENT_ID: + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: attr->u.ppid.id_len = sizeof(ds->index); memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len); break; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 5b1aa9f6f2615..c457c1f73d35c 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -104,7 +104,7 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) struct net_device *lower_dev; struct list_head *iter; struct switchdev_attr first = { - .id = SWITCHDEV_ATTR_UNDEFINED + .id = SWITCHDEV_ATTR_ID_UNDEFINED }; int err = -EOPNOTSUPP; @@ -124,7 +124,7 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) err = switchdev_port_attr_get(lower_dev, attr); if (err) break; - if (first.id == SWITCHDEV_ATTR_UNDEFINED) + if (first.id == SWITCHDEV_ATTR_ID_UNDEFINED) first = *attr; else if (memcmp(&first, attr, sizeof(*attr))) return -ENODATA; @@ -611,7 +611,7 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, int nlflags) { struct switchdev_attr attr = { - .id = SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS, + .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, }; u16 mode = BRIDGE_MODE_UNDEF; u32 mask = BR_LEARNING | BR_LEARNING_SYNC; @@ -632,7 +632,7 @@ static int switchdev_port_br_setflag(struct net_device *dev, unsigned long brport_flag) { struct switchdev_attr attr = { - .id = SWITCHDEV_ATTR_PORT_BRIDGE_FLAGS, + .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, }; u8 flag = nla_get_u8(nlattr); int err; @@ -958,7 +958,7 @@ static struct net_device *switchdev_get_lowest_dev(struct net_device *dev) static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) { struct switchdev_attr attr = { - .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, }; struct switchdev_attr prev_attr; struct net_device *dev = NULL; @@ -1107,11 +1107,11 @@ static bool switchdev_port_same_parent_id(struct net_device *a, struct net_device *b) { struct switchdev_attr a_attr = { - .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, .flags = SWITCHDEV_F_NO_RECURSE, }; struct switchdev_attr b_attr = { - .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, .flags = SWITCHDEV_F_NO_RECURSE, }; -- cgit v1.2.3 From 8f24f3095dcedaa4eb4719eee2bed738fe2ce4a0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Oct 2015 11:03:43 +0200 Subject: switchdev: rename switchdev_obj_vlan to switchdev_obj_port_vlan Make the struct name in sync with object id name. Suggested-by: Vivien Didelot Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 6 +++--- include/net/switchdev.h | 2 +- net/bridge/br_vlan.c | 4 ++-- net/dsa/slave.c | 6 +++--- net/switchdev/switchdev.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 4540ca63a434e..d75fc4b3baa90 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4408,7 +4408,7 @@ static int rocker_port_vlan_add(struct rocker_port *rocker_port, static int rocker_port_vlans_add(struct rocker_port *rocker_port, struct switchdev_trans *trans, - const struct switchdev_obj_vlan *vlan) + const struct switchdev_obj_port_vlan *vlan) { u16 vid; int err; @@ -4480,7 +4480,7 @@ static int rocker_port_vlan_del(struct rocker_port *rocker_port, } static int rocker_port_vlans_del(struct rocker_port *rocker_port, - const struct switchdev_obj_vlan *vlan) + const struct switchdev_obj_port_vlan *vlan) { u16 vid; int err; @@ -4565,7 +4565,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, } static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_vlan *vlan, + struct switchdev_obj_port_vlan *vlan, int (*cb)(void *obj)) { u16 vid; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 612719b9618a6..0138f9b374e2a 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -65,7 +65,7 @@ enum switchdev_obj_id { }; /* SWITCHDEV_OBJ_ID_PORT_VLAN */ -struct switchdev_obj_vlan { +struct switchdev_obj_port_vlan { u16 flags; u16 vid_begin; u16 vid_end; diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 68b5a11256671..d4cb129557f48 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -82,7 +82,7 @@ static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, if (ops->ndo_vlan_rx_add_vid) { err = vlan_vid_add(dev, br->vlan_proto, vid); } else { - struct switchdev_obj_vlan v = { + struct switchdev_obj_port_vlan v = { .flags = flags, .vid_begin = vid, .vid_end = vid, @@ -132,7 +132,7 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, if (ops->ndo_vlan_rx_kill_vid) { vlan_vid_del(dev, br->vlan_proto, vid); } else { - struct switchdev_obj_vlan v = { + struct switchdev_obj_port_vlan v = { .vid_begin = vid, .vid_end = vid, }; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8992568f5c0ed..baf34f2221153 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -242,7 +242,7 @@ static int dsa_bridge_check_vlan_range(struct dsa_switch *ds, } static int dsa_slave_port_vlan_add(struct net_device *dev, - const struct switchdev_obj_vlan *vlan, + const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); @@ -278,7 +278,7 @@ static int dsa_slave_port_vlan_add(struct net_device *dev, } static int dsa_slave_port_vlan_del(struct net_device *dev, - const struct switchdev_obj_vlan *vlan) + const struct switchdev_obj_port_vlan *vlan) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; @@ -298,7 +298,7 @@ static int dsa_slave_port_vlan_del(struct net_device *dev, } static int dsa_slave_port_vlan_dump(struct net_device *dev, - struct switchdev_obj_vlan *vlan, + struct switchdev_obj_port_vlan *vlan, int (*cb)(void *obj)) { struct dsa_slave_priv *p = netdev_priv(dev); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index c457c1f73d35c..02ee926ebde63 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -483,7 +483,7 @@ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, EXPORT_SYMBOL_GPL(call_switchdev_notifiers); struct switchdev_vlan_dump { - struct switchdev_obj_vlan vlan; + struct switchdev_obj_port_vlan vlan; struct sk_buff *skb; u32 filter_mask; u16 flags; @@ -523,7 +523,7 @@ static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) static int switchdev_port_vlan_dump_cb(void *obj) { - struct switchdev_obj_vlan *vlan = obj; + struct switchdev_obj_port_vlan *vlan = obj; struct switchdev_vlan_dump *dump = container_of(vlan, struct switchdev_vlan_dump, vlan); int err = 0; @@ -704,7 +704,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, { struct nlattr *attr; struct bridge_vlan_info *vinfo; - struct switchdev_obj_vlan vlan = { 0 }; + struct switchdev_obj_port_vlan vlan = { 0 }; int rem; int err; -- cgit v1.2.3 From 52ba57cfdc4c90da3bf996dfbe0c5feb731eb477 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Oct 2015 11:03:44 +0200 Subject: switchdev: rename switchdev_obj_fdb to switchdev_obj_port_fdb Make the struct name in sync with object id name. Suggested-by: Vivien Didelot Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 6 +++--- include/net/switchdev.h | 2 +- net/bridge/br_fdb.c | 2 +- net/dsa/slave.c | 6 +++--- net/switchdev/switchdev.c | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index d75fc4b3baa90..875f9b5b78a2b 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4425,7 +4425,7 @@ static int rocker_port_vlans_add(struct rocker_port *rocker_port, static int rocker_port_fdb_add(struct rocker_port *rocker_port, struct switchdev_trans *trans, - const struct switchdev_obj_fdb *fdb) + const struct switchdev_obj_port_fdb *fdb) { __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); int flags = 0; @@ -4496,7 +4496,7 @@ static int rocker_port_vlans_del(struct rocker_port *rocker_port, static int rocker_port_fdb_del(struct rocker_port *rocker_port, struct switchdev_trans *trans, - const struct switchdev_obj_fdb *fdb) + const struct switchdev_obj_port_fdb *fdb) { __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE; @@ -4537,7 +4537,7 @@ static int rocker_port_obj_del(struct net_device *dev, } static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_fdb *fdb, + struct switchdev_obj_port_fdb *fdb, int (*cb)(void *obj)) { struct rocker *rocker = rocker_port->rocker; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 0138f9b374e2a..8d71fdbaa7a6d 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -83,7 +83,7 @@ struct switchdev_obj_ipv4_fib { }; /* SWITCHDEV_OBJ_ID_PORT_FDB */ -struct switchdev_obj_fdb { +struct switchdev_obj_port_fdb { const unsigned char *addr; u16 vid; u16 ndm_state; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 6fc8e71277d44..36aab5e4784c6 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -133,7 +133,7 @@ static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr) static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) { - struct switchdev_obj_fdb fdb = { + struct switchdev_obj_port_fdb fdb = { .addr = f->addr.addr, .vid = f->vlan_id, }; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index baf34f2221153..6e8dc6a0102c4 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -341,7 +341,7 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, } static int dsa_slave_port_fdb_add(struct net_device *dev, - const struct switchdev_obj_fdb *fdb, + const struct switchdev_obj_port_fdb *fdb, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); @@ -357,7 +357,7 @@ static int dsa_slave_port_fdb_add(struct net_device *dev, } static int dsa_slave_port_fdb_del(struct net_device *dev, - const struct switchdev_obj_fdb *fdb) + const struct switchdev_obj_port_fdb *fdb) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; @@ -370,7 +370,7 @@ static int dsa_slave_port_fdb_del(struct net_device *dev, } static int dsa_slave_port_fdb_dump(struct net_device *dev, - struct switchdev_obj_fdb *fdb, + struct switchdev_obj_port_fdb *fdb, int (*cb)(void *obj)) { struct dsa_slave_priv *p = netdev_priv(dev); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 02ee926ebde63..250d013d64c6d 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -819,7 +819,7 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, u16 nlm_flags) { - struct switchdev_obj_fdb fdb = { + struct switchdev_obj_port_fdb fdb = { .addr = addr, .vid = vid, }; @@ -843,7 +843,7 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid) { - struct switchdev_obj_fdb fdb = { + struct switchdev_obj_port_fdb fdb = { .addr = addr, .vid = vid, }; @@ -853,7 +853,7 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); struct switchdev_fdb_dump { - struct switchdev_obj_fdb fdb; + struct switchdev_obj_port_fdb fdb; struct net_device *dev; struct sk_buff *skb; struct netlink_callback *cb; @@ -862,7 +862,7 @@ struct switchdev_fdb_dump { static int switchdev_port_fdb_dump_cb(void *obj) { - struct switchdev_obj_fdb *fdb = obj; + struct switchdev_obj_port_fdb *fdb = obj; struct switchdev_fdb_dump *dump = container_of(fdb, struct switchdev_fdb_dump, fdb); u32 portid = NETLINK_CB(dump->cb->skb).portid; -- cgit v1.2.3 From 648b4a995a057187ddd77cdb181e6a0b24ab2959 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Oct 2015 11:03:45 +0200 Subject: switchdev: bring back switchdev_obj and use it as a generic object param Replace "void *obj" with a generic structure. Introduce couple of helpers along that. Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 41 +++++++++++++++++++++-------------- include/net/switchdev.h | 42 ++++++++++++++++++++++++++---------- net/bridge/br_fdb.c | 3 ++- net/bridge/br_vlan.c | 4 ++-- net/dsa/slave.c | 41 +++++++++++++++++++++++------------ net/switchdev/switchdev.c | 40 ++++++++++++++++++---------------- 6 files changed, 109 insertions(+), 62 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 875f9b5b78a2b..2a577e5b8ca52 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4437,7 +4437,8 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port, } static int rocker_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const void *obj, + enum switchdev_obj_id id, + const struct switchdev_obj *obj, struct switchdev_trans *trans) { struct rocker_port *rocker_port = netdev_priv(dev); @@ -4446,16 +4447,18 @@ static int rocker_port_obj_add(struct net_device *dev, switch (id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = rocker_port_vlans_add(rocker_port, trans, obj); + err = rocker_port_vlans_add(rocker_port, trans, + SWITCHDEV_OBJ_PORT_VLAN(obj)); break; case SWITCHDEV_OBJ_ID_IPV4_FIB: - fib4 = obj; + fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); err = rocker_port_fib_ipv4(rocker_port, trans, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, 0); break; case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_port_fdb_add(rocker_port, trans, obj); + err = rocker_port_fdb_add(rocker_port, trans, + SWITCHDEV_OBJ_PORT_FDB(obj)); break; default: err = -EOPNOTSUPP; @@ -4508,7 +4511,8 @@ static int rocker_port_fdb_del(struct rocker_port *rocker_port, } static int rocker_port_obj_del(struct net_device *dev, - enum switchdev_obj_id id, const void *obj) + enum switchdev_obj_id id, + const struct switchdev_obj *obj) { struct rocker_port *rocker_port = netdev_priv(dev); const struct switchdev_obj_ipv4_fib *fib4; @@ -4516,17 +4520,19 @@ static int rocker_port_obj_del(struct net_device *dev, switch (id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = rocker_port_vlans_del(rocker_port, obj); + err = rocker_port_vlans_del(rocker_port, + SWITCHDEV_OBJ_PORT_VLAN(obj)); break; case SWITCHDEV_OBJ_ID_IPV4_FIB: - fib4 = obj; + fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); err = rocker_port_fib_ipv4(rocker_port, NULL, htonl(fib4->dst), fib4->dst_len, fib4->fi, fib4->tb_id, ROCKER_OP_FLAG_REMOVE); break; case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_port_fdb_del(rocker_port, NULL, obj); + err = rocker_port_fdb_del(rocker_port, NULL, + SWITCHDEV_OBJ_PORT_FDB(obj)); break; default: err = -EOPNOTSUPP; @@ -4538,7 +4544,7 @@ static int rocker_port_obj_del(struct net_device *dev, static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, struct switchdev_obj_port_fdb *fdb, - int (*cb)(void *obj)) + switchdev_obj_dump_cb_t *cb) { struct rocker *rocker = rocker_port->rocker; struct rocker_fdb_tbl_entry *found; @@ -4555,7 +4561,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, fdb->ndm_state = NUD_REACHABLE; fdb->vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id); - err = cb(fdb); + err = cb(&fdb->obj); if (err) break; } @@ -4566,7 +4572,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, struct switchdev_obj_port_vlan *vlan, - int (*cb)(void *obj)) + switchdev_obj_dump_cb_t *cb) { u16 vid; int err = 0; @@ -4578,7 +4584,7 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, if (rocker_vlan_id_is_internal(htons(vid))) vlan->flags |= BRIDGE_VLAN_INFO_PVID; vlan->vid_begin = vlan->vid_end = vid; - err = cb(vlan); + err = cb(&vlan->obj); if (err) break; } @@ -4587,18 +4593,21 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, } static int rocker_port_obj_dump(struct net_device *dev, - enum switchdev_obj_id id, void *obj, - int (*cb)(void *obj)) + enum switchdev_obj_id id, + struct switchdev_obj *obj, + switchdev_obj_dump_cb_t *cb) { const struct rocker_port *rocker_port = netdev_priv(dev); int err = 0; switch (id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_port_fdb_dump(rocker_port, obj, cb); + err = rocker_port_fdb_dump(rocker_port, + SWITCHDEV_OBJ_PORT_FDB(obj), cb); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = rocker_port_vlan_dump(rocker_port, obj, cb); + err = rocker_port_vlan_dump(rocker_port, + SWITCHDEV_OBJ_PORT_VLAN(obj), cb); break; default: err = -EOPNOTSUPP; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 8d71fdbaa7a6d..3e1bd14cc0ab3 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -64,15 +64,23 @@ enum switchdev_obj_id { SWITCHDEV_OBJ_ID_PORT_FDB, }; +struct switchdev_obj { +}; + /* SWITCHDEV_OBJ_ID_PORT_VLAN */ struct switchdev_obj_port_vlan { + struct switchdev_obj obj; u16 flags; u16 vid_begin; u16 vid_end; }; +#define SWITCHDEV_OBJ_PORT_VLAN(obj) \ + container_of(obj, struct switchdev_obj_port_vlan, obj) + /* SWITCHDEV_OBJ_ID_IPV4_FIB */ struct switchdev_obj_ipv4_fib { + struct switchdev_obj obj; u32 dst; int dst_len; struct fib_info *fi; @@ -82,18 +90,27 @@ struct switchdev_obj_ipv4_fib { u32 tb_id; }; +#define SWITCHDEV_OBJ_IPV4_FIB(obj) \ + container_of(obj, struct switchdev_obj_ipv4_fib, obj) + /* SWITCHDEV_OBJ_ID_PORT_FDB */ struct switchdev_obj_port_fdb { + struct switchdev_obj obj; const unsigned char *addr; u16 vid; u16 ndm_state; }; +#define SWITCHDEV_OBJ_PORT_FDB(obj) \ + container_of(obj, struct switchdev_obj_port_fdb, obj) + void switchdev_trans_item_enqueue(struct switchdev_trans *trans, void *data, void (*destructor)(void const *), struct switchdev_trans_item *tritem); void *switchdev_trans_item_dequeue(struct switchdev_trans *trans); +typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); + /** * struct switchdev_ops - switchdev operations * @@ -115,14 +132,15 @@ struct switchdev_ops { struct switchdev_trans *trans); int (*switchdev_port_obj_add)(struct net_device *dev, enum switchdev_obj_id id, - const void *obj, + const struct switchdev_obj *obj, struct switchdev_trans *trans); int (*switchdev_port_obj_del)(struct net_device *dev, enum switchdev_obj_id id, - const void *obj); + const struct switchdev_obj *obj); int (*switchdev_port_obj_dump)(struct net_device *dev, - enum switchdev_obj_id id, void *obj, - int (*cb)(void *obj)); + enum switchdev_obj_id id, + struct switchdev_obj *obj, + switchdev_obj_dump_cb_t *cb); }; enum switchdev_notifier_type { @@ -153,11 +171,12 @@ int switchdev_port_attr_get(struct net_device *dev, int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, - const void *obj); + const struct switchdev_obj *obj); int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, - const void *obj); + const struct switchdev_obj *obj); int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, - void *obj, int (*cb)(void *obj)); + struct switchdev_obj *obj, + switchdev_obj_dump_cb_t *cb); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); int call_switchdev_notifiers(unsigned long val, struct net_device *dev, @@ -203,21 +222,22 @@ static inline int switchdev_port_attr_set(struct net_device *dev, static inline int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, - const void *obj) + const struct switchdev_obj *obj) { return -EOPNOTSUPP; } static inline int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, - const void *obj) + const struct switchdev_obj *obj) { return -EOPNOTSUPP; } static inline int switchdev_port_obj_dump(struct net_device *dev, - enum switchdev_obj_id id, void *obj, - int (*cb)(void *obj)) + enum switchdev_obj_id id, + const struct switchdev_obj *obj, + switchdev_obj_dump_cb_t *cb) { return -EOPNOTSUPP; } diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 36aab5e4784c6..34b62df08d343 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -138,7 +138,8 @@ static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) .vid = f->vlan_id, }; - switchdev_port_obj_del(f->dst->dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb); + switchdev_port_obj_del(f->dst->dev, SWITCHDEV_OBJ_ID_PORT_FDB, + &fdb.obj); } static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index d4cb129557f48..0b87cf6ccb46f 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -89,7 +89,7 @@ static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, }; err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, - &v); + &v.obj); if (err == -EOPNOTSUPP) err = 0; } @@ -138,7 +138,7 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, }; err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, - &v); + &v.obj); if (err == -EOPNOTSUPP) err = 0; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 6e8dc6a0102c4..3f6d79d034570 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -299,7 +299,7 @@ static int dsa_slave_port_vlan_del(struct net_device *dev, static int dsa_slave_port_vlan_dump(struct net_device *dev, struct switchdev_obj_port_vlan *vlan, - int (*cb)(void *obj)) + switchdev_obj_dump_cb_t *cb) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; @@ -332,7 +332,7 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev, if (test_bit(p->port, untagged)) vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - err = cb(vlan); + err = cb(&vlan->obj); if (err) break; } @@ -371,7 +371,7 @@ static int dsa_slave_port_fdb_del(struct net_device *dev, static int dsa_slave_port_fdb_dump(struct net_device *dev, struct switchdev_obj_port_fdb *fdb, - int (*cb)(void *obj)) + switchdev_obj_dump_cb_t *cb) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; @@ -394,7 +394,7 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev, fdb->vid = vid; fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; - ret = cb(fdb); + ret = cb(&fdb->obj); if (ret < 0) break; } @@ -474,7 +474,8 @@ static int dsa_slave_port_attr_set(struct net_device *dev, } static int dsa_slave_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const void *obj, + enum switchdev_obj_id id, + const struct switchdev_obj *obj, struct switchdev_trans *trans) { int err; @@ -486,10 +487,14 @@ static int dsa_slave_port_obj_add(struct net_device *dev, switch (id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = dsa_slave_port_fdb_add(dev, obj, trans); + err = dsa_slave_port_fdb_add(dev, + SWITCHDEV_OBJ_PORT_FDB(obj), + trans); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dsa_slave_port_vlan_add(dev, obj, trans); + err = dsa_slave_port_vlan_add(dev, + SWITCHDEV_OBJ_PORT_VLAN(obj), + trans); break; default: err = -EOPNOTSUPP; @@ -500,16 +505,19 @@ static int dsa_slave_port_obj_add(struct net_device *dev, } static int dsa_slave_port_obj_del(struct net_device *dev, - enum switchdev_obj_id id, const void *obj) + enum switchdev_obj_id id, + const struct switchdev_obj *obj) { int err; switch (id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = dsa_slave_port_fdb_del(dev, obj); + err = dsa_slave_port_fdb_del(dev, + SWITCHDEV_OBJ_PORT_FDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dsa_slave_port_vlan_del(dev, obj); + err = dsa_slave_port_vlan_del(dev, + SWITCHDEV_OBJ_PORT_VLAN(obj)); break; default: err = -EOPNOTSUPP; @@ -520,17 +528,22 @@ static int dsa_slave_port_obj_del(struct net_device *dev, } static int dsa_slave_port_obj_dump(struct net_device *dev, - enum switchdev_obj_id id, void *obj, - int (*cb)(void *obj)) + enum switchdev_obj_id id, + struct switchdev_obj *obj, + switchdev_obj_dump_cb_t *cb) { int err; switch (id) { case SWITCHDEV_OBJ_ID_PORT_FDB: - err = dsa_slave_port_fdb_dump(dev, obj, cb); + err = dsa_slave_port_fdb_dump(dev, + SWITCHDEV_OBJ_PORT_FDB(obj), + cb); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = dsa_slave_port_vlan_dump(dev, obj, cb); + err = dsa_slave_port_vlan_dump(dev, + SWITCHDEV_OBJ_PORT_VLAN(obj), + cb); break; default: err = -EOPNOTSUPP; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 250d013d64c6d..0402b3633100c 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -270,7 +270,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) EXPORT_SYMBOL_GPL(switchdev_port_attr_set); static int __switchdev_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const void *obj, + enum switchdev_obj_id id, + const struct switchdev_obj *obj, struct switchdev_trans *trans) { const struct switchdev_ops *ops = dev->switchdev_ops; @@ -309,7 +310,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, * rtnl_lock must be held. */ int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, - const void *obj) + const struct switchdev_obj *obj) { struct switchdev_trans trans; int err; @@ -361,7 +362,7 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_add); * @obj: object to delete */ int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, - const void *obj) + const struct switchdev_obj *obj) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -395,7 +396,8 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_del); * @cb: function to call with a filled object */ int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, - void *obj, int (*cb)(void *obj)) + struct switchdev_obj *obj, + switchdev_obj_dump_cb_t *cb) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -521,9 +523,9 @@ static int switchdev_port_vlan_dump_put(struct switchdev_vlan_dump *dump) return 0; } -static int switchdev_port_vlan_dump_cb(void *obj) +static int switchdev_port_vlan_dump_cb(struct switchdev_obj *obj) { - struct switchdev_obj_port_vlan *vlan = obj; + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); struct switchdev_vlan_dump *dump = container_of(vlan, struct switchdev_vlan_dump, vlan); int err = 0; @@ -585,7 +587,7 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, if ((filter_mask & RTEXT_FILTER_BRVLAN) || (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { err = switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, - &dump.vlan, + &dump.vlan.obj, switchdev_port_vlan_dump_cb); if (err) goto err_out; @@ -700,11 +702,11 @@ static int switchdev_port_br_afspec(struct net_device *dev, struct nlattr *afspec, int (*f)(struct net_device *dev, enum switchdev_obj_id id, - const void *obj)) + const struct switchdev_obj *obj)) { struct nlattr *attr; struct bridge_vlan_info *vinfo; - struct switchdev_obj_port_vlan vlan = { 0 }; + struct switchdev_obj_port_vlan vlan = { {}, 0 }; int rem; int err; @@ -725,7 +727,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, vlan.vid_end = vinfo->vid; if (vlan.vid_end <= vlan.vid_begin) return -EINVAL; - err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan); + err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan.obj); if (err) return err; memset(&vlan, 0, sizeof(vlan)); @@ -734,7 +736,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, return -EINVAL; vlan.vid_begin = vinfo->vid; vlan.vid_end = vinfo->vid; - err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan); + err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan.obj); if (err) return err; memset(&vlan, 0, sizeof(vlan)); @@ -824,7 +826,7 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], .vid = vid, }; - return switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb); + return switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb.obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); @@ -848,7 +850,7 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], .vid = vid, }; - return switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb); + return switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb.obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); @@ -860,9 +862,9 @@ struct switchdev_fdb_dump { int idx; }; -static int switchdev_port_fdb_dump_cb(void *obj) +static int switchdev_port_fdb_dump_cb(struct switchdev_obj *obj) { - struct switchdev_obj_port_fdb *fdb = obj; + struct switchdev_obj_port_fdb *fdb = SWITCHDEV_OBJ_PORT_FDB(obj); struct switchdev_fdb_dump *dump = container_of(fdb, struct switchdev_fdb_dump, fdb); u32 portid = NETLINK_CB(dump->cb->skb).portid; @@ -926,7 +928,7 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, .idx = idx, }; - switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &dump.fdb, + switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &dump.fdb.obj, switchdev_port_fdb_dump_cb); return dump.idx; } @@ -1033,7 +1035,8 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, &ipv4_fib); + err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, + &ipv4_fib.obj); if (!err) fi->fib_flags |= RTNH_F_OFFLOAD; @@ -1075,7 +1078,8 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, &ipv4_fib); + err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, + &ipv4_fib.obj); if (!err) fi->fib_flags &= ~RTNH_F_OFFLOAD; -- cgit v1.2.3 From 9e8f4a548ab4710002c23c94c4b1bbde91b5e335 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Oct 2015 11:03:46 +0200 Subject: switchdev: push object ID back to object structure Suggested-by: Scott Feldman Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 9 ++---- include/net/switchdev.h | 14 +++------ net/bridge/br_fdb.c | 4 +-- net/bridge/br_vlan.c | 8 ++--- net/dsa/slave.c | 9 ++---- net/switchdev/switchdev.c | 57 ++++++++++++++++++------------------ 6 files changed, 45 insertions(+), 56 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 2a577e5b8ca52..cf91ffc6c9877 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4437,7 +4437,6 @@ static int rocker_port_fdb_add(struct rocker_port *rocker_port, } static int rocker_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj, struct switchdev_trans *trans) { @@ -4445,7 +4444,7 @@ static int rocker_port_obj_add(struct net_device *dev, const struct switchdev_obj_ipv4_fib *fib4; int err = 0; - switch (id) { + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: err = rocker_port_vlans_add(rocker_port, trans, SWITCHDEV_OBJ_PORT_VLAN(obj)); @@ -4511,14 +4510,13 @@ static int rocker_port_fdb_del(struct rocker_port *rocker_port, } static int rocker_port_obj_del(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj) { struct rocker_port *rocker_port = netdev_priv(dev); const struct switchdev_obj_ipv4_fib *fib4; int err = 0; - switch (id) { + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_VLAN: err = rocker_port_vlans_del(rocker_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); @@ -4593,14 +4591,13 @@ static int rocker_port_vlan_dump(const struct rocker_port *rocker_port, } static int rocker_port_obj_dump(struct net_device *dev, - enum switchdev_obj_id id, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) { const struct rocker_port *rocker_port = netdev_priv(dev); int err = 0; - switch (id) { + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: err = rocker_port_fdb_dump(rocker_port, SWITCHDEV_OBJ_PORT_FDB(obj), cb); diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 3e1bd14cc0ab3..89266a3e473d6 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -65,6 +65,7 @@ enum switchdev_obj_id { }; struct switchdev_obj { + enum switchdev_obj_id id; }; /* SWITCHDEV_OBJ_ID_PORT_VLAN */ @@ -131,14 +132,11 @@ struct switchdev_ops { struct switchdev_attr *attr, struct switchdev_trans *trans); int (*switchdev_port_obj_add)(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj, struct switchdev_trans *trans); int (*switchdev_port_obj_del)(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj); int (*switchdev_port_obj_dump)(struct net_device *dev, - enum switchdev_obj_id id, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb); }; @@ -170,12 +168,11 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr); -int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, +int switchdev_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj); -int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, +int switchdev_port_obj_del(struct net_device *dev, const struct switchdev_obj *obj); -int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, - struct switchdev_obj *obj, +int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb); int register_switchdev_notifier(struct notifier_block *nb); int unregister_switchdev_notifier(struct notifier_block *nb); @@ -221,21 +218,18 @@ static inline int switchdev_port_attr_set(struct net_device *dev, } static inline int switchdev_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj) { return -EOPNOTSUPP; } static inline int switchdev_port_obj_del(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj) { return -EOPNOTSUPP; } static inline int switchdev_port_obj_dump(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) { diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 34b62df08d343..7f7d55132dd50 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -134,12 +134,12 @@ static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr) static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) { struct switchdev_obj_port_fdb fdb = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, .addr = f->addr.addr, .vid = f->vlan_id, }; - switchdev_port_obj_del(f->dst->dev, SWITCHDEV_OBJ_ID_PORT_FDB, - &fdb.obj); + switchdev_port_obj_del(f->dst->dev, &fdb.obj); } static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 0b87cf6ccb46f..1a79e199ca3b7 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -83,13 +83,13 @@ static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, err = vlan_vid_add(dev, br->vlan_proto, vid); } else { struct switchdev_obj_port_vlan v = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, .flags = flags, .vid_begin = vid, .vid_end = vid, }; - err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, - &v.obj); + err = switchdev_port_obj_add(dev, &v.obj); if (err == -EOPNOTSUPP) err = 0; } @@ -133,12 +133,12 @@ static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, vlan_vid_del(dev, br->vlan_proto, vid); } else { struct switchdev_obj_port_vlan v = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, .vid_begin = vid, .vid_end = vid, }; - err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, - &v.obj); + err = switchdev_port_obj_del(dev, &v.obj); if (err == -EOPNOTSUPP) err = 0; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3f6d79d034570..5f65f929902e1 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -474,7 +474,6 @@ static int dsa_slave_port_attr_set(struct net_device *dev, } static int dsa_slave_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj, struct switchdev_trans *trans) { @@ -485,7 +484,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev, * supported, return -EOPNOTSUPP. */ - switch (id) { + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: err = dsa_slave_port_fdb_add(dev, SWITCHDEV_OBJ_PORT_FDB(obj), @@ -505,12 +504,11 @@ static int dsa_slave_port_obj_add(struct net_device *dev, } static int dsa_slave_port_obj_del(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj) { int err; - switch (id) { + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: err = dsa_slave_port_fdb_del(dev, SWITCHDEV_OBJ_PORT_FDB(obj)); @@ -528,13 +526,12 @@ static int dsa_slave_port_obj_del(struct net_device *dev, } static int dsa_slave_port_obj_dump(struct net_device *dev, - enum switchdev_obj_id id, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) { int err; - switch (id) { + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_FDB: err = dsa_slave_port_fdb_dump(dev, SWITCHDEV_OBJ_PORT_FDB(obj), diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 0402b3633100c..6e4a4f9ad927a 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -270,7 +270,6 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) EXPORT_SYMBOL_GPL(switchdev_port_attr_set); static int __switchdev_port_obj_add(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj, struct switchdev_trans *trans) { @@ -280,7 +279,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_add) - return ops->switchdev_port_obj_add(dev, id, obj, trans); + return ops->switchdev_port_obj_add(dev, obj, trans); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to add object on @@ -288,7 +287,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = __switchdev_port_obj_add(lower_dev, id, obj, trans); + err = __switchdev_port_obj_add(lower_dev, obj, trans); if (err) break; } @@ -309,7 +308,7 @@ static int __switchdev_port_obj_add(struct net_device *dev, * * rtnl_lock must be held. */ -int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, +int switchdev_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj) { struct switchdev_trans trans; @@ -327,7 +326,7 @@ int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, */ trans.ph_prepare = true; - err = __switchdev_port_obj_add(dev, id, obj, &trans); + err = __switchdev_port_obj_add(dev, obj, &trans); if (err) { /* Prepare phase failed: abort the transaction. Any * resources reserved in the prepare phase are @@ -346,8 +345,8 @@ int switchdev_port_obj_add(struct net_device *dev, enum switchdev_obj_id id, */ trans.ph_prepare = false; - err = __switchdev_port_obj_add(dev, id, obj, &trans); - WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, id); + err = __switchdev_port_obj_add(dev, obj, &trans); + WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); switchdev_trans_items_warn_destroy(dev, &trans); return err; @@ -361,7 +360,7 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_add); * @id: object ID * @obj: object to delete */ -int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, +int switchdev_port_obj_del(struct net_device *dev, const struct switchdev_obj *obj) { const struct switchdev_ops *ops = dev->switchdev_ops; @@ -370,7 +369,7 @@ int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_del) - return ops->switchdev_port_obj_del(dev, id, obj); + return ops->switchdev_port_obj_del(dev, obj); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to delete object on @@ -378,7 +377,7 @@ int switchdev_port_obj_del(struct net_device *dev, enum switchdev_obj_id id, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_obj_del(lower_dev, id, obj); + err = switchdev_port_obj_del(lower_dev, obj); if (err) break; } @@ -395,8 +394,7 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_del); * @obj: object to dump * @cb: function to call with a filled object */ -int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, - struct switchdev_obj *obj, +int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) { const struct switchdev_ops *ops = dev->switchdev_ops; @@ -405,7 +403,7 @@ int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, int err = -EOPNOTSUPP; if (ops && ops->switchdev_port_obj_dump) - return ops->switchdev_port_obj_dump(dev, id, obj, cb); + return ops->switchdev_port_obj_dump(dev, obj, cb); /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to dump objects on @@ -413,7 +411,7 @@ int switchdev_port_obj_dump(struct net_device *dev, enum switchdev_obj_id id, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_obj_dump(lower_dev, id, obj, cb); + err = switchdev_port_obj_dump(lower_dev, obj, cb); break; } @@ -579,6 +577,7 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, u32 filter_mask) { struct switchdev_vlan_dump dump = { + .vlan.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, .skb = skb, .filter_mask = filter_mask, }; @@ -586,8 +585,7 @@ static int switchdev_port_vlan_fill(struct sk_buff *skb, struct net_device *dev, if ((filter_mask & RTEXT_FILTER_BRVLAN) || (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { - err = switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, - &dump.vlan.obj, + err = switchdev_port_obj_dump(dev, &dump.vlan.obj, switchdev_port_vlan_dump_cb); if (err) goto err_out; @@ -701,12 +699,13 @@ static int switchdev_port_br_setlink_protinfo(struct net_device *dev, static int switchdev_port_br_afspec(struct net_device *dev, struct nlattr *afspec, int (*f)(struct net_device *dev, - enum switchdev_obj_id id, const struct switchdev_obj *obj)) { struct nlattr *attr; struct bridge_vlan_info *vinfo; - struct switchdev_obj_port_vlan vlan = { {}, 0 }; + struct switchdev_obj_port_vlan vlan = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, + }; int rem; int err; @@ -727,7 +726,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, vlan.vid_end = vinfo->vid; if (vlan.vid_end <= vlan.vid_begin) return -EINVAL; - err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan.obj); + err = f(dev, &vlan.obj); if (err) return err; memset(&vlan, 0, sizeof(vlan)); @@ -736,7 +735,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, return -EINVAL; vlan.vid_begin = vinfo->vid; vlan.vid_end = vinfo->vid; - err = f(dev, SWITCHDEV_OBJ_ID_PORT_VLAN, &vlan.obj); + err = f(dev, &vlan.obj); if (err) return err; memset(&vlan, 0, sizeof(vlan)); @@ -822,11 +821,12 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], u16 vid, u16 nlm_flags) { struct switchdev_obj_port_fdb fdb = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, .addr = addr, .vid = vid, }; - return switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb.obj); + return switchdev_port_obj_add(dev, &fdb.obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); @@ -846,11 +846,12 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], u16 vid) { struct switchdev_obj_port_fdb fdb = { + .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, .addr = addr, .vid = vid, }; - return switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &fdb.obj); + return switchdev_port_obj_del(dev, &fdb.obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); @@ -922,14 +923,14 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *filter_dev, int idx) { struct switchdev_fdb_dump dump = { + .fdb.obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, .dev = dev, .skb = skb, .cb = cb, .idx = idx, }; - switchdev_port_obj_dump(dev, SWITCHDEV_OBJ_ID_PORT_FDB, &dump.fdb.obj, - switchdev_port_fdb_dump_cb); + switchdev_port_obj_dump(dev, &dump.fdb.obj, switchdev_port_fdb_dump_cb); return dump.idx; } EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); @@ -1008,6 +1009,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 nlflags, u32 tb_id) { struct switchdev_obj_ipv4_fib ipv4_fib = { + .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, .dst = dst, .dst_len = dst_len, .fi = fi, @@ -1035,8 +1037,7 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_add(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, - &ipv4_fib.obj); + err = switchdev_port_obj_add(dev, &ipv4_fib.obj); if (!err) fi->fib_flags |= RTNH_F_OFFLOAD; @@ -1060,6 +1061,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, u8 tos, u8 type, u32 tb_id) { struct switchdev_obj_ipv4_fib ipv4_fib = { + .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, .dst = dst, .dst_len = dst_len, .fi = fi, @@ -1078,8 +1080,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, if (!dev) return 0; - err = switchdev_port_obj_del(dev, SWITCHDEV_OBJ_ID_IPV4_FIB, - &ipv4_fib.obj); + err = switchdev_port_obj_del(dev, &ipv4_fib.obj); if (!err) fi->fib_flags &= ~RTNH_F_OFFLOAD; -- cgit v1.2.3 From 464314ea6c119ebc22ee78453e63814453c31611 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Thu, 8 Oct 2015 19:23:18 -0700 Subject: switchdev: skip over ports returning -EOPNOTSUPP when recursing ports This allows us to recurse over all the ports, skipping over unsupporting ports. Without the change, the recursion would stop at first unsupported port. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 1 + net/switchdev/switchdev.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'net/switchdev/switchdev.c') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 61f129bd74b23..1ce70830357d7 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -16,6 +16,7 @@ #include #define SWITCHDEV_F_NO_RECURSE BIT(0) +#define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) struct switchdev_trans_item { struct list_head list; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 6e4a4f9ad927a..7a9ab90363be1 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -147,7 +147,7 @@ static int __switchdev_port_attr_set(struct net_device *dev, return ops->switchdev_port_attr_set(dev, attr, trans); if (attr->flags & SWITCHDEV_F_NO_RECURSE) - return err; + goto done; /* Switch device port(s) may be stacked under * bond/team/vlan dev, so recurse down to set attr on @@ -156,10 +156,17 @@ static int __switchdev_port_attr_set(struct net_device *dev, netdev_for_each_lower_dev(dev, lower_dev, iter) { err = __switchdev_port_attr_set(lower_dev, attr, trans); + if (err == -EOPNOTSUPP && + attr->flags & SWITCHDEV_F_SKIP_EOPNOTSUPP) + continue; if (err) break; } +done: + if (err == -EOPNOTSUPP && attr->flags & SWITCHDEV_F_SKIP_EOPNOTSUPP) + err = 0; + return err; } -- cgit v1.2.3 From cc02aa8e41c50f690d0bb22ed5629468483421b7 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 12 Oct 2015 14:01:39 +0200 Subject: switchdev: enforce no pvid flag in vlan ranges We shouldn't allow BRIDGE_VLAN_INFO_PVID flag in VLAN ranges. Signed-off-by: Nikolay Aleksandrov Acked-by: Elad Raz Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 7a9ab90363be1..b8aaf820ef65d 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -727,6 +727,9 @@ static int switchdev_port_br_afspec(struct net_device *dev, if (vlan.vid_begin) return -EINVAL; vlan.vid_begin = vinfo->vid; + /* don't allow range of pvids */ + if (vlan.flags & BRIDGE_VLAN_INFO_PVID) + return -EINVAL; } else if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) { if (!vlan.vid_begin) return -EINVAL; -- cgit v1.2.3 From 87aaf2caed8496404d3809edc30d38d4a4a5d273 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 12 Oct 2015 14:31:01 +0200 Subject: switchdev: check if the vlan id is in the proper vlan range VLANs 0 and 4095 are reserved and shouldn't be used, add checks to switchdev similar to the bridge. Also make sure ids above 4095 cannot be passed either. Fixes: 47f8328bb1a4 ("switchdev: add new switchdev bridge setlink") Signed-off-by: Nikolay Aleksandrov Acked-by: Scott Feldman Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index fda38f830a108..77f5d17e26123 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -634,6 +635,8 @@ static int switchdev_port_br_afspec(struct net_device *dev, if (nla_len(attr) != sizeof(struct bridge_vlan_info)) return -EINVAL; vinfo = nla_data(attr); + if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) + return -EINVAL; vlan->flags = vinfo->flags; if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { if (vlan->vid_begin) -- cgit v1.2.3 From 793f40147e82cdedc80971fa7f5596d6ed1e555e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Oct 2015 19:40:48 +0200 Subject: switchdev: introduce switchdev deferred ops infrastructure Introduce infrastructure which will be used internally to defer ops. Note that the deferred ops are queued up and either are processed by scheduled work or explicitly by user calling deferred_process function. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 5 +++ net/switchdev/switchdev.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) (limited to 'net/switchdev/switchdev.c') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 1ce70830357d7..31b9038e07b0e 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -167,6 +167,7 @@ switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) #ifdef CONFIG_NET_SWITCHDEV +void switchdev_deferred_process(void); int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, @@ -208,6 +209,10 @@ void switchdev_port_fwd_mark_set(struct net_device *dev, #else +static inline void switchdev_deferred_process(void) +{ +} + static inline int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) { diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index b8aaf820ef65d..5e64b591aff73 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -92,6 +93,85 @@ static void switchdev_trans_items_warn_destroy(struct net_device *dev, switchdev_trans_items_destroy(trans); } +static LIST_HEAD(deferred); +static DEFINE_SPINLOCK(deferred_lock); + +typedef void switchdev_deferred_func_t(struct net_device *dev, + const void *data); + +struct switchdev_deferred_item { + struct list_head list; + struct net_device *dev; + switchdev_deferred_func_t *func; + unsigned long data[0]; +}; + +static struct switchdev_deferred_item *switchdev_deferred_dequeue(void) +{ + struct switchdev_deferred_item *dfitem; + + spin_lock_bh(&deferred_lock); + if (list_empty(&deferred)) { + dfitem = NULL; + goto unlock; + } + dfitem = list_first_entry(&deferred, + struct switchdev_deferred_item, list); + list_del(&dfitem->list); +unlock: + spin_unlock_bh(&deferred_lock); + return dfitem; +} + +/** + * switchdev_deferred_process - Process ops in deferred queue + * + * Called to flush the ops currently queued in deferred ops queue. + * rtnl_lock must be held. + */ +void switchdev_deferred_process(void) +{ + struct switchdev_deferred_item *dfitem; + + ASSERT_RTNL(); + + while ((dfitem = switchdev_deferred_dequeue())) { + dfitem->func(dfitem->dev, dfitem->data); + dev_put(dfitem->dev); + kfree(dfitem); + } +} +EXPORT_SYMBOL_GPL(switchdev_deferred_process); + +static void switchdev_deferred_process_work(struct work_struct *work) +{ + rtnl_lock(); + switchdev_deferred_process(); + rtnl_unlock(); +} + +static DECLARE_WORK(deferred_process_work, switchdev_deferred_process_work); + +static int switchdev_deferred_enqueue(struct net_device *dev, + const void *data, size_t data_len, + switchdev_deferred_func_t *func) +{ + struct switchdev_deferred_item *dfitem; + + dfitem = kmalloc(sizeof(*dfitem) + data_len, GFP_ATOMIC); + if (!dfitem) + return -ENOMEM; + dfitem->dev = dev; + dfitem->func = func; + memcpy(dfitem->data, data, data_len); + dev_hold(dev); + spin_lock_bh(&deferred_lock); + list_add_tail(&dfitem->list, &deferred); + spin_unlock_bh(&deferred_lock); + schedule_work(&deferred_process_work); + return 0; +} + /** * switchdev_port_attr_get - Get port attribute * -- cgit v1.2.3 From f7fadf3047d005d17376da65aa9e5734f45a77d4 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Oct 2015 19:40:49 +0200 Subject: switchdev: make struct switchdev_attr parameter const for attr_set calls Signed-off-by: Jiri Pirko Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 2 +- include/net/switchdev.h | 6 +++--- net/dsa/slave.c | 2 +- net/switchdev/switchdev.c | 7 ++++--- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index eafa907965ecb..f0e820d2b8ec5 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4374,7 +4374,7 @@ static int rocker_port_bridge_ageing_time(struct rocker_port *rocker_port, } static int rocker_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr, + const struct switchdev_attr *attr, struct switchdev_trans *trans) { struct rocker_port *rocker_port = netdev_priv(dev); diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 31b9038e07b0e..d1c7f901ea61d 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -132,7 +132,7 @@ struct switchdev_ops { int (*switchdev_port_attr_get)(struct net_device *dev, struct switchdev_attr *attr); int (*switchdev_port_attr_set)(struct net_device *dev, - struct switchdev_attr *attr, + const struct switchdev_attr *attr, struct switchdev_trans *trans); int (*switchdev_port_obj_add)(struct net_device *dev, const struct switchdev_obj *obj, @@ -171,7 +171,7 @@ void switchdev_deferred_process(void); int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr); int switchdev_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr); + const struct switchdev_attr *attr); int switchdev_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj); int switchdev_port_obj_del(struct net_device *dev, @@ -220,7 +220,7 @@ static inline int switchdev_port_attr_get(struct net_device *dev, } static inline int switchdev_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr) + const struct switchdev_attr *attr) { return -EOPNOTSUPP; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 43d7342e75271..84cd8639e37be 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -453,7 +453,7 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state) } static int dsa_slave_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr, + const struct switchdev_attr *attr, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 5e64b591aff73..23b4e5b347dca 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -215,7 +215,7 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) EXPORT_SYMBOL_GPL(switchdev_port_attr_get); static int __switchdev_port_attr_set(struct net_device *dev, - struct switchdev_attr *attr, + const struct switchdev_attr *attr, struct switchdev_trans *trans) { const struct switchdev_ops *ops = dev->switchdev_ops; @@ -274,7 +274,7 @@ static void switchdev_port_attr_set_work(struct work_struct *work) } static int switchdev_port_attr_set_defer(struct net_device *dev, - struct switchdev_attr *attr) + const struct switchdev_attr *attr) { struct switchdev_attr_set_work *asw; @@ -303,7 +303,8 @@ static int switchdev_port_attr_set_defer(struct net_device *dev, * system is not left in a partially updated state due to * failure from driver/device. */ -int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) +int switchdev_port_attr_set(struct net_device *dev, + const struct switchdev_attr *attr) { struct switchdev_trans trans; int err; -- cgit v1.2.3 From 0bc05d585d381c30de3fdf955730df31593d2101 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Oct 2015 19:40:50 +0200 Subject: switchdev: allow caller to explicitly request attr_set as deferred Caller should know if he can call attr_set directly (when holding RTNL) or if he has to defer the att_set processing for later. This also allows drivers to sleep inside attr_set and report operation status back to switchdev core. Switchdev core then warns if status is not ok, instead of silent errors happening in drivers. Benefit from newly introduced switchdev deferred ops infrastructure. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 1 + net/bridge/br_stp.c | 3 +- net/switchdev/switchdev.c | 108 ++++++++++++++++++---------------------------- 3 files changed, 46 insertions(+), 66 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index d1c7f901ea61d..f7de6f8e9a4c8 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -17,6 +17,7 @@ #define SWITCHDEV_F_NO_RECURSE BIT(0) #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) +#define SWITCHDEV_F_DEFER BIT(2) struct switchdev_trans_item { struct list_head list; diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index db6d243defb2d..80c34d70218c0 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -41,13 +41,14 @@ void br_set_state(struct net_bridge_port *p, unsigned int state) { struct switchdev_attr attr = { .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, + .flags = SWITCHDEV_F_DEFER, .u.stp_state = state, }; int err; p->state = state; err = switchdev_port_attr_set(p->dev, &attr); - if (err && err != -EOPNOTSUPP) + if (err) br_warn(p->br, "error setting offload STP state on port %u(%s)\n", (unsigned int) p->port_no, p->dev->name); } diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 23b4e5b347dca..007b8f40df069 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -250,75 +250,12 @@ done: return err; } -struct switchdev_attr_set_work { - struct work_struct work; - struct net_device *dev; - struct switchdev_attr attr; -}; - -static void switchdev_port_attr_set_work(struct work_struct *work) -{ - struct switchdev_attr_set_work *asw = - container_of(work, struct switchdev_attr_set_work, work); - int err; - - rtnl_lock(); - err = switchdev_port_attr_set(asw->dev, &asw->attr); - if (err && err != -EOPNOTSUPP) - netdev_err(asw->dev, "failed (err=%d) to set attribute (id=%d)\n", - err, asw->attr.id); - rtnl_unlock(); - - dev_put(asw->dev); - kfree(work); -} - -static int switchdev_port_attr_set_defer(struct net_device *dev, - const struct switchdev_attr *attr) -{ - struct switchdev_attr_set_work *asw; - - asw = kmalloc(sizeof(*asw), GFP_ATOMIC); - if (!asw) - return -ENOMEM; - - INIT_WORK(&asw->work, switchdev_port_attr_set_work); - - dev_hold(dev); - asw->dev = dev; - memcpy(&asw->attr, attr, sizeof(asw->attr)); - - schedule_work(&asw->work); - - return 0; -} - -/** - * switchdev_port_attr_set - Set port attribute - * - * @dev: port device - * @attr: attribute to set - * - * Use a 2-phase prepare-commit transaction model to ensure - * system is not left in a partially updated state due to - * failure from driver/device. - */ -int switchdev_port_attr_set(struct net_device *dev, - const struct switchdev_attr *attr) +static int switchdev_port_attr_set_now(struct net_device *dev, + const struct switchdev_attr *attr) { struct switchdev_trans trans; int err; - if (!rtnl_is_locked()) { - /* Running prepare-commit transaction across stacked - * devices requires nothing moves, so if rtnl_lock is - * not held, schedule a worker thread to hold rtnl_lock - * while setting attr. - */ - - return switchdev_port_attr_set_defer(dev, attr); - } - switchdev_trans_init(&trans); /* Phase I: prepare for attr set. Driver/device should fail @@ -355,6 +292,47 @@ int switchdev_port_attr_set(struct net_device *dev, return err; } + +static void switchdev_port_attr_set_deferred(struct net_device *dev, + const void *data) +{ + const struct switchdev_attr *attr = data; + int err; + + err = switchdev_port_attr_set_now(dev, attr); + if (err && err != -EOPNOTSUPP) + netdev_err(dev, "failed (err=%d) to set attribute (id=%d)\n", + err, attr->id); +} + +static int switchdev_port_attr_set_defer(struct net_device *dev, + const struct switchdev_attr *attr) +{ + return switchdev_deferred_enqueue(dev, attr, sizeof(*attr), + switchdev_port_attr_set_deferred); +} + +/** + * switchdev_port_attr_set - Set port attribute + * + * @dev: port device + * @attr: attribute to set + * + * Use a 2-phase prepare-commit transaction model to ensure + * system is not left in a partially updated state due to + * failure from driver/device. + * + * rtnl_lock must be held and must not be in atomic section, + * in case SWITCHDEV_F_DEFER flag is not set. + */ +int switchdev_port_attr_set(struct net_device *dev, + const struct switchdev_attr *attr) +{ + if (attr->flags & SWITCHDEV_F_DEFER) + return switchdev_port_attr_set_defer(dev, attr); + ASSERT_RTNL(); + return switchdev_port_attr_set_now(dev, attr); +} EXPORT_SYMBOL_GPL(switchdev_port_attr_set); static int __switchdev_port_obj_add(struct net_device *dev, -- cgit v1.2.3 From 850d0cbc9171f63f0418afffb0d89a84db927851 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Oct 2015 19:40:51 +0200 Subject: switchdev: remove pointers from switchdev objects When object is used in deferred work, we cannot use pointers in switchdev object structures because the memory they point at may be already used by someone else. So rather do local copy of the value. Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Reviewed-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 6 +++--- include/net/switchdev.h | 7 +++---- net/bridge/br_fdb.c | 2 +- net/dsa/slave.c | 2 +- net/switchdev/switchdev.c | 11 +++++++---- 5 files changed, 15 insertions(+), 13 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index f0e820d2b8ec5..2cd7435b2316c 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4469,7 +4469,7 @@ static int rocker_port_obj_add(struct net_device *dev, fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); err = rocker_port_fib_ipv4(rocker_port, trans, htonl(fib4->dst), fib4->dst_len, - fib4->fi, fib4->tb_id, 0); + &fib4->fi, fib4->tb_id, 0); break; case SWITCHDEV_OBJ_ID_PORT_FDB: err = rocker_port_fdb_add(rocker_port, trans, @@ -4541,7 +4541,7 @@ static int rocker_port_obj_del(struct net_device *dev, fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); err = rocker_port_fib_ipv4(rocker_port, NULL, htonl(fib4->dst), fib4->dst_len, - fib4->fi, fib4->tb_id, + &fib4->fi, fib4->tb_id, ROCKER_OP_FLAG_REMOVE); break; case SWITCHDEV_OBJ_ID_PORT_FDB: @@ -4571,7 +4571,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) { if (found->key.rocker_port != rocker_port) continue; - fdb->addr = found->key.addr; + ether_addr_copy(fdb->addr, found->key.addr); fdb->ndm_state = NUD_REACHABLE; fdb->vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id); diff --git a/include/net/switchdev.h b/include/net/switchdev.h index f7de6f8e9a4c8..f8672d7f3ff2b 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -14,6 +14,7 @@ #include #include #include +#include #define SWITCHDEV_F_NO_RECURSE BIT(0) #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) @@ -59,8 +60,6 @@ struct switchdev_attr { } u; }; -struct fib_info; - enum switchdev_obj_id { SWITCHDEV_OBJ_ID_UNDEFINED, SWITCHDEV_OBJ_ID_PORT_VLAN, @@ -88,7 +87,7 @@ struct switchdev_obj_ipv4_fib { struct switchdev_obj obj; u32 dst; int dst_len; - struct fib_info *fi; + struct fib_info fi; u8 tos; u8 type; u32 nlflags; @@ -101,7 +100,7 @@ struct switchdev_obj_ipv4_fib { /* SWITCHDEV_OBJ_ID_PORT_FDB */ struct switchdev_obj_port_fdb { struct switchdev_obj obj; - const unsigned char *addr; + unsigned char addr[ETH_ALEN]; u16 vid; u16 ndm_state; }; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index f43ce05c66a67..f5e7da0fe93b5 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -135,10 +135,10 @@ static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) { struct switchdev_obj_port_fdb fdb = { .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, - .addr = f->addr.addr, .vid = f->vlan_id, }; + ether_addr_copy(fdb.addr, f->addr.addr); switchdev_port_obj_del(f->dst->dev, &fdb.obj); } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 84cd8639e37be..b0b8da0f5af89 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -393,7 +393,7 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev, if (ret < 0) break; - fdb->addr = addr; + ether_addr_copy(fdb->addr, addr); fdb->vid = vid; fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 007b8f40df069..5963d7ac10268 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -891,10 +892,10 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], { struct switchdev_obj_port_fdb fdb = { .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, - .addr = addr, .vid = vid, }; + ether_addr_copy(fdb.addr, addr); return switchdev_port_obj_add(dev, &fdb.obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); @@ -916,10 +917,10 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], { struct switchdev_obj_port_fdb fdb = { .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, - .addr = addr, .vid = vid, }; + ether_addr_copy(fdb.addr, addr); return switchdev_port_obj_del(dev, &fdb.obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); @@ -1081,7 +1082,6 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, .dst = dst, .dst_len = dst_len, - .fi = fi, .tos = tos, .type = type, .nlflags = nlflags, @@ -1090,6 +1090,8 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi, struct net_device *dev; int err = 0; + memcpy(&ipv4_fib.fi, fi, sizeof(ipv4_fib.fi)); + /* Don't offload route if using custom ip rules or if * IPv4 FIB offloading has been disabled completely. */ @@ -1133,7 +1135,6 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, .dst = dst, .dst_len = dst_len, - .fi = fi, .tos = tos, .type = type, .nlflags = 0, @@ -1142,6 +1143,8 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi, struct net_device *dev; int err = 0; + memcpy(&ipv4_fib.fi, fi, sizeof(ipv4_fib.fi)); + if (!(fi->fib_flags & RTNH_F_OFFLOAD)) return 0; -- cgit v1.2.3 From 4d429c5ddc5128fccd3048059ae26bb39f0d8284 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Oct 2015 19:40:52 +0200 Subject: switchdev: introduce possibility to defer obj_add/del Similar to the attr usecase, the caller knows if he is holding RTNL and is in atomic section. So let the called to decide the correct call variant. This allows drivers to sleep inside their ops and wait for hw to get the operation status. Then the status is propagated into switchdev core. This avoids silent errors in drivers. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 1 + net/switchdev/switchdev.c | 100 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 81 insertions(+), 20 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/include/net/switchdev.h b/include/net/switchdev.h index f8672d7f3ff2b..bc865e244efea 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -69,6 +69,7 @@ enum switchdev_obj_id { struct switchdev_obj { enum switchdev_obj_id id; + u32 flags; }; /* SWITCHDEV_OBJ_ID_PORT_VLAN */ diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 5963d7ac10268..eac68c4e57ec9 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -362,21 +362,8 @@ static int __switchdev_port_obj_add(struct net_device *dev, return err; } -/** - * switchdev_port_obj_add - Add port object - * - * @dev: port device - * @id: object ID - * @obj: object to add - * - * Use a 2-phase prepare-commit transaction model to ensure - * system is not left in a partially updated state due to - * failure from driver/device. - * - * rtnl_lock must be held. - */ -int switchdev_port_obj_add(struct net_device *dev, - const struct switchdev_obj *obj) +static int switchdev_port_obj_add_now(struct net_device *dev, + const struct switchdev_obj *obj) { struct switchdev_trans trans; int err; @@ -418,17 +405,52 @@ int switchdev_port_obj_add(struct net_device *dev, return err; } -EXPORT_SYMBOL_GPL(switchdev_port_obj_add); + +static void switchdev_port_obj_add_deferred(struct net_device *dev, + const void *data) +{ + const struct switchdev_obj *obj = data; + int err; + + err = switchdev_port_obj_add_now(dev, obj); + if (err && err != -EOPNOTSUPP) + netdev_err(dev, "failed (err=%d) to add object (id=%d)\n", + err, obj->id); +} + +static int switchdev_port_obj_add_defer(struct net_device *dev, + const struct switchdev_obj *obj) +{ + return switchdev_deferred_enqueue(dev, obj, sizeof(*obj), + switchdev_port_obj_add_deferred); +} /** - * switchdev_port_obj_del - Delete port object + * switchdev_port_obj_add - Add port object * * @dev: port device * @id: object ID - * @obj: object to delete + * @obj: object to add + * + * Use a 2-phase prepare-commit transaction model to ensure + * system is not left in a partially updated state due to + * failure from driver/device. + * + * rtnl_lock must be held and must not be in atomic section, + * in case SWITCHDEV_F_DEFER flag is not set. */ -int switchdev_port_obj_del(struct net_device *dev, +int switchdev_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj) +{ + if (obj->flags & SWITCHDEV_F_DEFER) + return switchdev_port_obj_add_defer(dev, obj); + ASSERT_RTNL(); + return switchdev_port_obj_add_now(dev, obj); +} +EXPORT_SYMBOL_GPL(switchdev_port_obj_add); + +static int switchdev_port_obj_del_now(struct net_device *dev, + const struct switchdev_obj *obj) { const struct switchdev_ops *ops = dev->switchdev_ops; struct net_device *lower_dev; @@ -444,13 +466,51 @@ int switchdev_port_obj_del(struct net_device *dev, */ netdev_for_each_lower_dev(dev, lower_dev, iter) { - err = switchdev_port_obj_del(lower_dev, obj); + err = switchdev_port_obj_del_now(lower_dev, obj); if (err) break; } return err; } + +static void switchdev_port_obj_del_deferred(struct net_device *dev, + const void *data) +{ + const struct switchdev_obj *obj = data; + int err; + + err = switchdev_port_obj_del_now(dev, obj); + if (err && err != -EOPNOTSUPP) + netdev_err(dev, "failed (err=%d) to del object (id=%d)\n", + err, obj->id); +} + +static int switchdev_port_obj_del_defer(struct net_device *dev, + const struct switchdev_obj *obj) +{ + return switchdev_deferred_enqueue(dev, obj, sizeof(*obj), + switchdev_port_obj_del_deferred); +} + +/** + * switchdev_port_obj_del - Delete port object + * + * @dev: port device + * @id: object ID + * @obj: object to delete + * + * rtnl_lock must be held and must not be in atomic section, + * in case SWITCHDEV_F_DEFER flag is not set. + */ +int switchdev_port_obj_del(struct net_device *dev, + const struct switchdev_obj *obj) +{ + if (obj->flags & SWITCHDEV_F_DEFER) + return switchdev_port_obj_del_defer(dev, obj); + ASSERT_RTNL(); + return switchdev_port_obj_del_now(dev, obj); +} EXPORT_SYMBOL_GPL(switchdev_port_obj_del); /** -- cgit v1.2.3 From 771acac2ffa5957b91e881908cd4c9657978a209 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 14 Oct 2015 19:40:55 +0200 Subject: switchdev: assert rtnl mutex when going over lower netdevs netdev_for_each_lower_dev has to be called with rtnl mutex held. So better enforce it in switchdev functions. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index eac68c4e57ec9..73e3895175cf7 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -520,6 +520,8 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_del); * @id: object ID * @obj: object to dump * @cb: function to call with a filled object + * + * rtnl_lock must be held. */ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, switchdev_obj_dump_cb_t *cb) @@ -529,6 +531,8 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, struct list_head *iter; int err = -EOPNOTSUPP; + ASSERT_RTNL(); + if (ops && ops->switchdev_port_obj_dump) return ops->switchdev_port_obj_dump(dev, obj, cb); @@ -1097,6 +1101,8 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) struct net_device *dev = NULL; int nhsel; + ASSERT_RTNL(); + /* For this route, all nexthop devs must be on the same switch. */ for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { @@ -1327,10 +1333,11 @@ void switchdev_port_fwd_mark_set(struct net_device *dev, u32 mark = dev->ifindex; u32 reset_mark = 0; - if (group_dev && joining) { - mark = switchdev_port_fwd_mark_get(dev, group_dev); - } else if (group_dev && !joining) { - if (dev->offload_fwd_mark == mark) + if (group_dev) { + ASSERT_RTNL(); + if (joining) + mark = switchdev_port_fwd_mark_get(dev, group_dev); + else if (dev->offload_fwd_mark == mark) /* Ohoh, this port was the mark reference port, * but it's leaving the group, so reset the * mark for the remaining ports in the group. -- cgit v1.2.3 From 741af0053b43d8b9a688a12c57ece62338616ae8 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Oct 2015 10:16:54 +0100 Subject: switchdev: Add support for flood control Allow devices supporting this feature to control the flooding of unknown unicast traffic, by making switchdev infrastructure propagate this setting to the switch driver. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 3 +++ net/switchdev/switchdev.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net/switchdev/switchdev.c') diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt index 0714fe5550165..ce510e1a3e87c 100644 --- a/Documentation/networking/switchdev.txt +++ b/Documentation/networking/switchdev.txt @@ -298,6 +298,9 @@ packets up to the bridge driver for flooding. This is not ideal as the number of ports scale in the L2 domain as the device is much more efficient at flooding packets that software. +If supported by the device, flood control can be offloaded to it, preventing +certain netdevs from flooding unicast traffic for which there is no FDB entry. + IGMP Snooping ^^^^^^^^^^^^^ diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 1eb76956b4390..8950d39af3418 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -746,7 +746,7 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, }; u16 mode = BRIDGE_MODE_UNDEF; - u32 mask = BR_LEARNING | BR_LEARNING_SYNC; + u32 mask = BR_LEARNING | BR_LEARNING_SYNC | BR_FLOOD; int err; err = switchdev_port_attr_get(dev, &attr); @@ -817,6 +817,9 @@ static int switchdev_port_br_setlink_protinfo(struct net_device *dev, err = switchdev_port_br_setflag(dev, attr, BR_LEARNING_SYNC); break; + case IFLA_BRPORT_UNICAST_FLOOD: + err = switchdev_port_br_setflag(dev, attr, BR_FLOOD); + break; default: err = -EOPNOTSUPP; break; -- cgit v1.2.3 From 3a7bde55a11c4a22a6ccfc487993d621ae8e3688 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 28 Oct 2015 23:17:30 -0700 Subject: switchdev: fix: erasing too much of vlan obj when handling multiple vlan specs When adding vlans with multiple IFLA_BRIDGE_VLAN_INFO attrs set in AFSPEC, we would wipe the vlan obj struct after the first IFLA_BRIDGE_VLAN_INFO. Fix this by only clearing what's necessary on each IFLA_BRIDGE_VLAN_INFO iteration. Fixes: 9e8f4a54 ("switchdev: push object ID back to object structure") Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 8950d39af3418..d6b4a84a4a797 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -869,7 +869,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, err = f(dev, &vlan.obj); if (err) return err; - memset(&vlan, 0, sizeof(vlan)); + vlan.vid_begin = 0; } else { if (vlan.vid_begin) return -EINVAL; @@ -878,7 +878,7 @@ static int switchdev_port_br_afspec(struct net_device *dev, err = f(dev, &vlan.obj); if (err) return err; - memset(&vlan, 0, sizeof(vlan)); + vlan.vid_begin = 0; } } -- cgit v1.2.3 From e258d919b175e0160a694a20fb309e29fc93d7b1 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 28 Oct 2015 23:17:31 -0700 Subject: switchdev: fix: pass correct obj size when deferring obj add Fixes: 4d429c5dd ("switchdev: introduce possibility to defer obj_add/del") Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index d6b4a84a4a797..6dfd19e529387 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -337,6 +337,21 @@ int switchdev_port_attr_set(struct net_device *dev, } EXPORT_SYMBOL_GPL(switchdev_port_attr_set); +static size_t switchdev_obj_size(const struct switchdev_obj *obj) +{ + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + return sizeof(struct switchdev_obj_port_vlan); + case SWITCHDEV_OBJ_ID_IPV4_FIB: + return sizeof(struct switchdev_obj_ipv4_fib); + case SWITCHDEV_OBJ_ID_PORT_FDB: + return sizeof(struct switchdev_obj_port_fdb); + default: + BUG(); + } + return 0; +} + static int __switchdev_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans) @@ -422,7 +437,7 @@ static void switchdev_port_obj_add_deferred(struct net_device *dev, static int switchdev_port_obj_add_defer(struct net_device *dev, const struct switchdev_obj *obj) { - return switchdev_deferred_enqueue(dev, obj, sizeof(*obj), + return switchdev_deferred_enqueue(dev, obj, switchdev_obj_size(obj), switchdev_port_obj_add_deferred); } @@ -490,7 +505,7 @@ static void switchdev_port_obj_del_deferred(struct net_device *dev, static int switchdev_port_obj_del_defer(struct net_device *dev, const struct switchdev_obj *obj) { - return switchdev_deferred_enqueue(dev, obj, sizeof(*obj), + return switchdev_deferred_enqueue(dev, obj, switchdev_obj_size(obj), switchdev_port_obj_del_deferred); } -- cgit v1.2.3 From 0c63d80c3fac4e6eb0f01dff756e47bc7cd50092 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 3 Nov 2015 17:40:53 +0100 Subject: switchdev: respect SKIP_EOPNOTSUPP flag in case there is no recursion Caller passing down the SKIP_EOPNOTSUPP switchdev flag expects that -EOPNOTSUPP cannot be returned. But in case of direct op call without recurtion, this may happen. So fix this by checking it always on the end of __switchdev_port_attr_set function. Fixes: 464314ea6c11 ("switchdev: skip over ports returning -EOPNOTSUPP when recursing ports") Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'net/switchdev/switchdev.c') diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 6dfd19e529387..f34e535e93bdf 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -225,8 +225,10 @@ static int __switchdev_port_attr_set(struct net_device *dev, struct list_head *iter; int err = -EOPNOTSUPP; - if (ops && ops->switchdev_port_attr_set) - return ops->switchdev_port_attr_set(dev, attr, trans); + if (ops && ops->switchdev_port_attr_set) { + err = ops->switchdev_port_attr_set(dev, attr, trans); + goto done; + } if (attr->flags & SWITCHDEV_F_NO_RECURSE) goto done; @@ -238,9 +240,6 @@ static int __switchdev_port_attr_set(struct net_device *dev, netdev_for_each_lower_dev(dev, lower_dev, iter) { err = __switchdev_port_attr_set(lower_dev, attr, trans); - if (err == -EOPNOTSUPP && - attr->flags & SWITCHDEV_F_SKIP_EOPNOTSUPP) - continue; if (err) break; } -- cgit v1.2.3