aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-10-15 09:09:58 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-15 09:09:58 -0400
commit74661bee1f524ca970086748291b3ca1b4c21ffe (patch)
tree7d6671c6e2f27c0b04ce775d913f09384b89e07f
parentadc9048c607a08320e87befc940955d6ffe51fac (diff)
parent771acac2ffa5957b91e881908cd4c9657978a209 (diff)
Merge branch 'switchdev-locking'
Jiri Pirko says: ==================== switchdev: change locking This is something which I'm currently struggling with. Callers of attr_set and obj_add/del often hold not only RTNL, but also spinlock (bridge). So in that case, the driver implementing the op cannot sleep. The way rocker is dealing with this now is just to invoke driver operation and go out, without any checking or reporting of the operation status. Since it would be nice to at least put a warning in case the operation fails, it makes sense to do this in delayed work directly in switchdev core instead of implementing this in separate drivers. And that is what this patchset is introducing. So from now on, the locking of switchdev mod ops is consistent. Caller either holds rtnl mutex or in case it does not, caller sets defer flag, telling switchdev core to process the op later, in deferred queue. Function to force to process switchdev deferred ops can be called by op caller in appropriate location, for example after it releases spin lock, to force switchdev core to process pending ops. v1->v2: - rebased on current net-next head (including Scott's ageing patchset) v2->v3: - fixed comment s/of/or/ typo suggested by Nik v3->v4: - the actual patchset is sent instead of different branch I send in v3 :/ v4->v5: - added patch to "const" attr param - reworked deferred ops infrastructure (mainly patch number 1 and internal users (patch 3 and 5)) - resolves the issue pointed out by John ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/rocker/rocker.c15
-rw-r--r--include/net/switchdev.h20
-rw-r--r--net/bridge/br_fdb.c7
-rw-r--r--net/bridge/br_if.c3
-rw-r--r--net/bridge/br_stp.c3
-rw-r--r--net/dsa/slave.c4
-rw-r--r--net/switchdev/switchdev.c315
7 files changed, 254 insertions, 113 deletions
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index eafa907965ec..32a80d2df7ff 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -3672,7 +3672,7 @@ static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
3672 rocker_port->stp_state == BR_STATE_FORWARDING) 3672 rocker_port->stp_state == BR_STATE_FORWARDING)
3673 return 0; 3673 return 0;
3674 3674
3675 flags |= ROCKER_OP_FLAG_REMOVE; 3675 flags |= ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
3676 3676
3677 spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags); 3677 spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
3678 3678
@@ -4374,7 +4374,7 @@ static int rocker_port_bridge_ageing_time(struct rocker_port *rocker_port,
4374} 4374}
4375 4375
4376static int rocker_port_attr_set(struct net_device *dev, 4376static int rocker_port_attr_set(struct net_device *dev,
4377 struct switchdev_attr *attr, 4377 const struct switchdev_attr *attr,
4378 struct switchdev_trans *trans) 4378 struct switchdev_trans *trans)
4379{ 4379{
4380 struct rocker_port *rocker_port = netdev_priv(dev); 4380 struct rocker_port *rocker_port = netdev_priv(dev);
@@ -4382,8 +4382,7 @@ static int rocker_port_attr_set(struct net_device *dev,
4382 4382
4383 switch (attr->id) { 4383 switch (attr->id) {
4384 case SWITCHDEV_ATTR_ID_PORT_STP_STATE: 4384 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
4385 err = rocker_port_stp_update(rocker_port, trans, 4385 err = rocker_port_stp_update(rocker_port, trans, 0,
4386 ROCKER_OP_FLAG_NOWAIT,
4387 attr->u.stp_state); 4386 attr->u.stp_state);
4388 break; 4387 break;
4389 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: 4388 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
@@ -4469,7 +4468,7 @@ static int rocker_port_obj_add(struct net_device *dev,
4469 fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); 4468 fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
4470 err = rocker_port_fib_ipv4(rocker_port, trans, 4469 err = rocker_port_fib_ipv4(rocker_port, trans,
4471 htonl(fib4->dst), fib4->dst_len, 4470 htonl(fib4->dst), fib4->dst_len,
4472 fib4->fi, fib4->tb_id, 0); 4471 &fib4->fi, fib4->tb_id, 0);
4473 break; 4472 break;
4474 case SWITCHDEV_OBJ_ID_PORT_FDB: 4473 case SWITCHDEV_OBJ_ID_PORT_FDB:
4475 err = rocker_port_fdb_add(rocker_port, trans, 4474 err = rocker_port_fdb_add(rocker_port, trans,
@@ -4517,7 +4516,7 @@ static int rocker_port_fdb_del(struct rocker_port *rocker_port,
4517 const struct switchdev_obj_port_fdb *fdb) 4516 const struct switchdev_obj_port_fdb *fdb)
4518{ 4517{
4519 __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL); 4518 __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
4520 int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE; 4519 int flags = ROCKER_OP_FLAG_REMOVE;
4521 4520
4522 if (!rocker_port_is_bridged(rocker_port)) 4521 if (!rocker_port_is_bridged(rocker_port))
4523 return -EINVAL; 4522 return -EINVAL;
@@ -4541,7 +4540,7 @@ static int rocker_port_obj_del(struct net_device *dev,
4541 fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj); 4540 fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
4542 err = rocker_port_fib_ipv4(rocker_port, NULL, 4541 err = rocker_port_fib_ipv4(rocker_port, NULL,
4543 htonl(fib4->dst), fib4->dst_len, 4542 htonl(fib4->dst), fib4->dst_len,
4544 fib4->fi, fib4->tb_id, 4543 &fib4->fi, fib4->tb_id,
4545 ROCKER_OP_FLAG_REMOVE); 4544 ROCKER_OP_FLAG_REMOVE);
4546 break; 4545 break;
4547 case SWITCHDEV_OBJ_ID_PORT_FDB: 4546 case SWITCHDEV_OBJ_ID_PORT_FDB:
@@ -4571,7 +4570,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
4571 hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) { 4570 hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
4572 if (found->key.rocker_port != rocker_port) 4571 if (found->key.rocker_port != rocker_port)
4573 continue; 4572 continue;
4574 fdb->addr = found->key.addr; 4573 ether_addr_copy(fdb->addr, found->key.addr);
4575 fdb->ndm_state = NUD_REACHABLE; 4574 fdb->ndm_state = NUD_REACHABLE;
4576 fdb->vid = rocker_port_vlan_to_vid(rocker_port, 4575 fdb->vid = rocker_port_vlan_to_vid(rocker_port,
4577 found->key.vlan_id); 4576 found->key.vlan_id);
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index 1ce70830357d..bc865e244efe 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -14,9 +14,11 @@
14#include <linux/netdevice.h> 14#include <linux/netdevice.h>
15#include <linux/notifier.h> 15#include <linux/notifier.h>
16#include <linux/list.h> 16#include <linux/list.h>
17#include <net/ip_fib.h>
17 18
18#define SWITCHDEV_F_NO_RECURSE BIT(0) 19#define SWITCHDEV_F_NO_RECURSE BIT(0)
19#define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) 20#define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1)
21#define SWITCHDEV_F_DEFER BIT(2)
20 22
21struct switchdev_trans_item { 23struct switchdev_trans_item {
22 struct list_head list; 24 struct list_head list;
@@ -58,8 +60,6 @@ struct switchdev_attr {
58 } u; 60 } u;
59}; 61};
60 62
61struct fib_info;
62
63enum switchdev_obj_id { 63enum switchdev_obj_id {
64 SWITCHDEV_OBJ_ID_UNDEFINED, 64 SWITCHDEV_OBJ_ID_UNDEFINED,
65 SWITCHDEV_OBJ_ID_PORT_VLAN, 65 SWITCHDEV_OBJ_ID_PORT_VLAN,
@@ -69,6 +69,7 @@ enum switchdev_obj_id {
69 69
70struct switchdev_obj { 70struct switchdev_obj {
71 enum switchdev_obj_id id; 71 enum switchdev_obj_id id;
72 u32 flags;
72}; 73};
73 74
74/* SWITCHDEV_OBJ_ID_PORT_VLAN */ 75/* SWITCHDEV_OBJ_ID_PORT_VLAN */
@@ -87,7 +88,7 @@ struct switchdev_obj_ipv4_fib {
87 struct switchdev_obj obj; 88 struct switchdev_obj obj;
88 u32 dst; 89 u32 dst;
89 int dst_len; 90 int dst_len;
90 struct fib_info *fi; 91 struct fib_info fi;
91 u8 tos; 92 u8 tos;
92 u8 type; 93 u8 type;
93 u32 nlflags; 94 u32 nlflags;
@@ -100,7 +101,7 @@ struct switchdev_obj_ipv4_fib {
100/* SWITCHDEV_OBJ_ID_PORT_FDB */ 101/* SWITCHDEV_OBJ_ID_PORT_FDB */
101struct switchdev_obj_port_fdb { 102struct switchdev_obj_port_fdb {
102 struct switchdev_obj obj; 103 struct switchdev_obj obj;
103 const unsigned char *addr; 104 unsigned char addr[ETH_ALEN];
104 u16 vid; 105 u16 vid;
105 u16 ndm_state; 106 u16 ndm_state;
106}; 107};
@@ -132,7 +133,7 @@ struct switchdev_ops {
132 int (*switchdev_port_attr_get)(struct net_device *dev, 133 int (*switchdev_port_attr_get)(struct net_device *dev,
133 struct switchdev_attr *attr); 134 struct switchdev_attr *attr);
134 int (*switchdev_port_attr_set)(struct net_device *dev, 135 int (*switchdev_port_attr_set)(struct net_device *dev,
135 struct switchdev_attr *attr, 136 const struct switchdev_attr *attr,
136 struct switchdev_trans *trans); 137 struct switchdev_trans *trans);
137 int (*switchdev_port_obj_add)(struct net_device *dev, 138 int (*switchdev_port_obj_add)(struct net_device *dev,
138 const struct switchdev_obj *obj, 139 const struct switchdev_obj *obj,
@@ -167,10 +168,11 @@ switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info)
167 168
168#ifdef CONFIG_NET_SWITCHDEV 169#ifdef CONFIG_NET_SWITCHDEV
169 170
171void switchdev_deferred_process(void);
170int switchdev_port_attr_get(struct net_device *dev, 172int switchdev_port_attr_get(struct net_device *dev,
171 struct switchdev_attr *attr); 173 struct switchdev_attr *attr);
172int switchdev_port_attr_set(struct net_device *dev, 174int switchdev_port_attr_set(struct net_device *dev,
173 struct switchdev_attr *attr); 175 const struct switchdev_attr *attr);
174int switchdev_port_obj_add(struct net_device *dev, 176int switchdev_port_obj_add(struct net_device *dev,
175 const struct switchdev_obj *obj); 177 const struct switchdev_obj *obj);
176int switchdev_port_obj_del(struct net_device *dev, 178int switchdev_port_obj_del(struct net_device *dev,
@@ -208,6 +210,10 @@ void switchdev_port_fwd_mark_set(struct net_device *dev,
208 210
209#else 211#else
210 212
213static inline void switchdev_deferred_process(void)
214{
215}
216
211static inline int switchdev_port_attr_get(struct net_device *dev, 217static inline int switchdev_port_attr_get(struct net_device *dev,
212 struct switchdev_attr *attr) 218 struct switchdev_attr *attr)
213{ 219{
@@ -215,7 +221,7 @@ static inline int switchdev_port_attr_get(struct net_device *dev,
215} 221}
216 222
217static inline int switchdev_port_attr_set(struct net_device *dev, 223static inline int switchdev_port_attr_set(struct net_device *dev,
218 struct switchdev_attr *attr) 224 const struct switchdev_attr *attr)
219{ 225{
220 return -EOPNOTSUPP; 226 return -EOPNOTSUPP;
221} 227}
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index f43ce05c66a6..c88bd8e8937e 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -134,11 +134,14 @@ static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr)
134static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) 134static void fdb_del_external_learn(struct net_bridge_fdb_entry *f)
135{ 135{
136 struct switchdev_obj_port_fdb fdb = { 136 struct switchdev_obj_port_fdb fdb = {
137 .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, 137 .obj = {
138 .addr = f->addr.addr, 138 .id = SWITCHDEV_OBJ_ID_PORT_FDB,
139 .flags = SWITCHDEV_F_DEFER,
140 },
139 .vid = f->vlan_id, 141 .vid = f->vlan_id,
140 }; 142 };
141 143
144 ether_addr_copy(fdb.addr, f->addr.addr);
142 switchdev_port_obj_del(f->dst->dev, &fdb.obj); 145 switchdev_port_obj_del(f->dst->dev, &fdb.obj);
143} 146}
144 147
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 45e4757c6fd2..ec02f5869a78 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -24,6 +24,7 @@
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <net/sock.h> 25#include <net/sock.h>
26#include <linux/if_vlan.h> 26#include <linux/if_vlan.h>
27#include <net/switchdev.h>
27 28
28#include "br_private.h" 29#include "br_private.h"
29 30
@@ -250,6 +251,8 @@ static void del_nbp(struct net_bridge_port *p)
250 251
251 nbp_vlan_flush(p); 252 nbp_vlan_flush(p);
252 br_fdb_delete_by_port(br, p, 0, 1); 253 br_fdb_delete_by_port(br, p, 0, 1);
254 switchdev_deferred_process();
255
253 nbp_update_port_count(br); 256 nbp_update_port_count(br);
254 257
255 netdev_upper_dev_unlink(dev, br->dev); 258 netdev_upper_dev_unlink(dev, br->dev);
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index db6d243defb2..80c34d70218c 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)
41{ 41{
42 struct switchdev_attr attr = { 42 struct switchdev_attr attr = {
43 .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE, 43 .id = SWITCHDEV_ATTR_ID_PORT_STP_STATE,
44 .flags = SWITCHDEV_F_DEFER,
44 .u.stp_state = state, 45 .u.stp_state = state,
45 }; 46 };
46 int err; 47 int err;
47 48
48 p->state = state; 49 p->state = state;
49 err = switchdev_port_attr_set(p->dev, &attr); 50 err = switchdev_port_attr_set(p->dev, &attr);
50 if (err && err != -EOPNOTSUPP) 51 if (err)
51 br_warn(p->br, "error setting offload STP state on port %u(%s)\n", 52 br_warn(p->br, "error setting offload STP state on port %u(%s)\n",
52 (unsigned int) p->port_no, p->dev->name); 53 (unsigned int) p->port_no, p->dev->name);
53} 54}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 43d7342e7527..b0b8da0f5af8 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,
393 if (ret < 0) 393 if (ret < 0)
394 break; 394 break;
395 395
396 fdb->addr = addr; 396 ether_addr_copy(fdb->addr, addr);
397 fdb->vid = vid; 397 fdb->vid = vid;
398 fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; 398 fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
399 399
@@ -453,7 +453,7 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state)
453} 453}
454 454
455static int dsa_slave_port_attr_set(struct net_device *dev, 455static int dsa_slave_port_attr_set(struct net_device *dev,
456 struct switchdev_attr *attr, 456 const struct switchdev_attr *attr,
457 struct switchdev_trans *trans) 457 struct switchdev_trans *trans)
458{ 458{
459 struct dsa_slave_priv *p = netdev_priv(dev); 459 struct dsa_slave_priv *p = netdev_priv(dev);
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index b8aaf820ef65..73e3895175cf 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -15,8 +15,10 @@
15#include <linux/mutex.h> 15#include <linux/mutex.h>
16#include <linux/notifier.h> 16#include <linux/notifier.h>
17#include <linux/netdevice.h> 17#include <linux/netdevice.h>
18#include <linux/etherdevice.h>
18#include <linux/if_bridge.h> 19#include <linux/if_bridge.h>
19#include <linux/list.h> 20#include <linux/list.h>
21#include <linux/workqueue.h>
20#include <net/ip_fib.h> 22#include <net/ip_fib.h>
21#include <net/switchdev.h> 23#include <net/switchdev.h>
22 24
@@ -92,6 +94,85 @@ static void switchdev_trans_items_warn_destroy(struct net_device *dev,
92 switchdev_trans_items_destroy(trans); 94 switchdev_trans_items_destroy(trans);
93} 95}
94 96
97static LIST_HEAD(deferred);
98static DEFINE_SPINLOCK(deferred_lock);
99
100typedef void switchdev_deferred_func_t(struct net_device *dev,
101 const void *data);
102
103struct switchdev_deferred_item {
104 struct list_head list;
105 struct net_device *dev;
106 switchdev_deferred_func_t *func;
107 unsigned long data[0];
108};
109
110static struct switchdev_deferred_item *switchdev_deferred_dequeue(void)
111{
112 struct switchdev_deferred_item *dfitem;
113
114 spin_lock_bh(&deferred_lock);
115 if (list_empty(&deferred)) {
116 dfitem = NULL;
117 goto unlock;
118 }
119 dfitem = list_first_entry(&deferred,
120 struct switchdev_deferred_item, list);
121 list_del(&dfitem->list);
122unlock:
123 spin_unlock_bh(&deferred_lock);
124 return dfitem;
125}
126
127/**
128 * switchdev_deferred_process - Process ops in deferred queue
129 *
130 * Called to flush the ops currently queued in deferred ops queue.
131 * rtnl_lock must be held.
132 */
133void switchdev_deferred_process(void)
134{
135 struct switchdev_deferred_item *dfitem;
136
137 ASSERT_RTNL();
138
139 while ((dfitem = switchdev_deferred_dequeue())) {
140 dfitem->func(dfitem->dev, dfitem->data);
141 dev_put(dfitem->dev);
142 kfree(dfitem);
143 }
144}
145EXPORT_SYMBOL_GPL(switchdev_deferred_process);
146
147static void switchdev_deferred_process_work(struct work_struct *work)
148{
149 rtnl_lock();
150 switchdev_deferred_process();
151 rtnl_unlock();
152}
153
154static DECLARE_WORK(deferred_process_work, switchdev_deferred_process_work);
155
156static int switchdev_deferred_enqueue(struct net_device *dev,
157 const void *data, size_t data_len,
158 switchdev_deferred_func_t *func)
159{
160 struct switchdev_deferred_item *dfitem;
161
162 dfitem = kmalloc(sizeof(*dfitem) + data_len, GFP_ATOMIC);
163 if (!dfitem)
164 return -ENOMEM;
165 dfitem->dev = dev;
166 dfitem->func = func;
167 memcpy(dfitem->data, data, data_len);
168 dev_hold(dev);
169 spin_lock_bh(&deferred_lock);
170 list_add_tail(&dfitem->list, &deferred);
171 spin_unlock_bh(&deferred_lock);
172 schedule_work(&deferred_process_work);
173 return 0;
174}
175
95/** 176/**
96 * switchdev_port_attr_get - Get port attribute 177 * switchdev_port_attr_get - Get port attribute
97 * 178 *
@@ -135,7 +216,7 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr)
135EXPORT_SYMBOL_GPL(switchdev_port_attr_get); 216EXPORT_SYMBOL_GPL(switchdev_port_attr_get);
136 217
137static int __switchdev_port_attr_set(struct net_device *dev, 218static int __switchdev_port_attr_set(struct net_device *dev,
138 struct switchdev_attr *attr, 219 const struct switchdev_attr *attr,
139 struct switchdev_trans *trans) 220 struct switchdev_trans *trans)
140{ 221{
141 const struct switchdev_ops *ops = dev->switchdev_ops; 222 const struct switchdev_ops *ops = dev->switchdev_ops;
@@ -170,74 +251,12 @@ done:
170 return err; 251 return err;
171} 252}
172 253
173struct switchdev_attr_set_work { 254static int switchdev_port_attr_set_now(struct net_device *dev,
174 struct work_struct work; 255 const struct switchdev_attr *attr)
175 struct net_device *dev;
176 struct switchdev_attr attr;
177};
178
179static void switchdev_port_attr_set_work(struct work_struct *work)
180{
181 struct switchdev_attr_set_work *asw =
182 container_of(work, struct switchdev_attr_set_work, work);
183 int err;
184
185 rtnl_lock();
186 err = switchdev_port_attr_set(asw->dev, &asw->attr);
187 if (err && err != -EOPNOTSUPP)
188 netdev_err(asw->dev, "failed (err=%d) to set attribute (id=%d)\n",
189 err, asw->attr.id);
190 rtnl_unlock();
191
192 dev_put(asw->dev);
193 kfree(work);
194}
195
196static int switchdev_port_attr_set_defer(struct net_device *dev,
197 struct switchdev_attr *attr)
198{
199 struct switchdev_attr_set_work *asw;
200
201 asw = kmalloc(sizeof(*asw), GFP_ATOMIC);
202 if (!asw)
203 return -ENOMEM;
204
205 INIT_WORK(&asw->work, switchdev_port_attr_set_work);
206
207 dev_hold(dev);
208 asw->dev = dev;
209 memcpy(&asw->attr, attr, sizeof(asw->attr));
210
211 schedule_work(&asw->work);
212
213 return 0;
214}
215
216/**
217 * switchdev_port_attr_set - Set port attribute
218 *
219 * @dev: port device
220 * @attr: attribute to set
221 *
222 * Use a 2-phase prepare-commit transaction model to ensure
223 * system is not left in a partially updated state due to
224 * failure from driver/device.
225 */
226int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
227{ 256{
228 struct switchdev_trans trans; 257 struct switchdev_trans trans;
229 int err; 258 int err;
230 259
231 if (!rtnl_is_locked()) {
232 /* Running prepare-commit transaction across stacked
233 * devices requires nothing moves, so if rtnl_lock is
234 * not held, schedule a worker thread to hold rtnl_lock
235 * while setting attr.
236 */
237
238 return switchdev_port_attr_set_defer(dev, attr);
239 }
240
241 switchdev_trans_init(&trans); 260 switchdev_trans_init(&trans);
242 261
243 /* Phase I: prepare for attr set. Driver/device should fail 262 /* Phase I: prepare for attr set. Driver/device should fail
@@ -274,6 +293,47 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
274 293
275 return err; 294 return err;
276} 295}
296
297static void switchdev_port_attr_set_deferred(struct net_device *dev,
298 const void *data)
299{
300 const struct switchdev_attr *attr = data;
301 int err;
302
303 err = switchdev_port_attr_set_now(dev, attr);
304 if (err && err != -EOPNOTSUPP)
305 netdev_err(dev, "failed (err=%d) to set attribute (id=%d)\n",
306 err, attr->id);
307}
308
309static int switchdev_port_attr_set_defer(struct net_device *dev,
310 const struct switchdev_attr *attr)
311{
312 return switchdev_deferred_enqueue(dev, attr, sizeof(*attr),
313 switchdev_port_attr_set_deferred);
314}
315
316/**
317 * switchdev_port_attr_set - Set port attribute
318 *
319 * @dev: port device
320 * @attr: attribute to set
321 *
322 * Use a 2-phase prepare-commit transaction model to ensure
323 * system is not left in a partially updated state due to
324 * failure from driver/device.
325 *
326 * rtnl_lock must be held and must not be in atomic section,
327 * in case SWITCHDEV_F_DEFER flag is not set.
328 */
329int switchdev_port_attr_set(struct net_device *dev,
330 const struct switchdev_attr *attr)
331{
332 if (attr->flags & SWITCHDEV_F_DEFER)
333 return switchdev_port_attr_set_defer(dev, attr);
334 ASSERT_RTNL();
335 return switchdev_port_attr_set_now(dev, attr);
336}
277EXPORT_SYMBOL_GPL(switchdev_port_attr_set); 337EXPORT_SYMBOL_GPL(switchdev_port_attr_set);
278 338
279static int __switchdev_port_obj_add(struct net_device *dev, 339static int __switchdev_port_obj_add(struct net_device *dev,
@@ -302,21 +362,8 @@ static int __switchdev_port_obj_add(struct net_device *dev,
302 return err; 362 return err;
303} 363}
304 364
305/** 365static int switchdev_port_obj_add_now(struct net_device *dev,
306 * switchdev_port_obj_add - Add port object 366 const struct switchdev_obj *obj)
307 *
308 * @dev: port device
309 * @id: object ID
310 * @obj: object to add
311 *
312 * Use a 2-phase prepare-commit transaction model to ensure
313 * system is not left in a partially updated state due to
314 * failure from driver/device.
315 *
316 * rtnl_lock must be held.
317 */
318int switchdev_port_obj_add(struct net_device *dev,
319 const struct switchdev_obj *obj)
320{ 367{
321 struct switchdev_trans trans; 368 struct switchdev_trans trans;
322 int err; 369 int err;
@@ -358,18 +405,53 @@ int switchdev_port_obj_add(struct net_device *dev,
358 405
359 return err; 406 return err;
360} 407}
361EXPORT_SYMBOL_GPL(switchdev_port_obj_add); 408
409static void switchdev_port_obj_add_deferred(struct net_device *dev,
410 const void *data)
411{
412 const struct switchdev_obj *obj = data;
413 int err;
414
415 err = switchdev_port_obj_add_now(dev, obj);
416 if (err && err != -EOPNOTSUPP)
417 netdev_err(dev, "failed (err=%d) to add object (id=%d)\n",
418 err, obj->id);
419}
420
421static int switchdev_port_obj_add_defer(struct net_device *dev,
422 const struct switchdev_obj *obj)
423{
424 return switchdev_deferred_enqueue(dev, obj, sizeof(*obj),
425 switchdev_port_obj_add_deferred);
426}
362 427
363/** 428/**
364 * switchdev_port_obj_del - Delete port object 429 * switchdev_port_obj_add - Add port object
365 * 430 *
366 * @dev: port device 431 * @dev: port device
367 * @id: object ID 432 * @id: object ID
368 * @obj: object to delete 433 * @obj: object to add
434 *
435 * Use a 2-phase prepare-commit transaction model to ensure
436 * system is not left in a partially updated state due to
437 * failure from driver/device.
438 *
439 * rtnl_lock must be held and must not be in atomic section,
440 * in case SWITCHDEV_F_DEFER flag is not set.
369 */ 441 */
370int switchdev_port_obj_del(struct net_device *dev, 442int switchdev_port_obj_add(struct net_device *dev,
371 const struct switchdev_obj *obj) 443 const struct switchdev_obj *obj)
372{ 444{
445 if (obj->flags & SWITCHDEV_F_DEFER)
446 return switchdev_port_obj_add_defer(dev, obj);
447 ASSERT_RTNL();
448 return switchdev_port_obj_add_now(dev, obj);
449}
450EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
451
452static int switchdev_port_obj_del_now(struct net_device *dev,
453 const struct switchdev_obj *obj)
454{
373 const struct switchdev_ops *ops = dev->switchdev_ops; 455 const struct switchdev_ops *ops = dev->switchdev_ops;
374 struct net_device *lower_dev; 456 struct net_device *lower_dev;
375 struct list_head *iter; 457 struct list_head *iter;
@@ -384,13 +466,51 @@ int switchdev_port_obj_del(struct net_device *dev,
384 */ 466 */
385 467
386 netdev_for_each_lower_dev(dev, lower_dev, iter) { 468 netdev_for_each_lower_dev(dev, lower_dev, iter) {
387 err = switchdev_port_obj_del(lower_dev, obj); 469 err = switchdev_port_obj_del_now(lower_dev, obj);
388 if (err) 470 if (err)
389 break; 471 break;
390 } 472 }
391 473
392 return err; 474 return err;
393} 475}
476
477static void switchdev_port_obj_del_deferred(struct net_device *dev,
478 const void *data)
479{
480 const struct switchdev_obj *obj = data;
481 int err;
482
483 err = switchdev_port_obj_del_now(dev, obj);
484 if (err && err != -EOPNOTSUPP)
485 netdev_err(dev, "failed (err=%d) to del object (id=%d)\n",
486 err, obj->id);
487}
488
489static int switchdev_port_obj_del_defer(struct net_device *dev,
490 const struct switchdev_obj *obj)
491{
492 return switchdev_deferred_enqueue(dev, obj, sizeof(*obj),
493 switchdev_port_obj_del_deferred);
494}
495
496/**
497 * switchdev_port_obj_del - Delete port object
498 *
499 * @dev: port device
500 * @id: object ID
501 * @obj: object to delete
502 *
503 * rtnl_lock must be held and must not be in atomic section,
504 * in case SWITCHDEV_F_DEFER flag is not set.
505 */
506int switchdev_port_obj_del(struct net_device *dev,
507 const struct switchdev_obj *obj)
508{
509 if (obj->flags & SWITCHDEV_F_DEFER)
510 return switchdev_port_obj_del_defer(dev, obj);
511 ASSERT_RTNL();
512 return switchdev_port_obj_del_now(dev, obj);
513}
394EXPORT_SYMBOL_GPL(switchdev_port_obj_del); 514EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
395 515
396/** 516/**
@@ -400,6 +520,8 @@ EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
400 * @id: object ID 520 * @id: object ID
401 * @obj: object to dump 521 * @obj: object to dump
402 * @cb: function to call with a filled object 522 * @cb: function to call with a filled object
523 *
524 * rtnl_lock must be held.
403 */ 525 */
404int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, 526int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj,
405 switchdev_obj_dump_cb_t *cb) 527 switchdev_obj_dump_cb_t *cb)
@@ -409,6 +531,8 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj,
409 struct list_head *iter; 531 struct list_head *iter;
410 int err = -EOPNOTSUPP; 532 int err = -EOPNOTSUPP;
411 533
534 ASSERT_RTNL();
535
412 if (ops && ops->switchdev_port_obj_dump) 536 if (ops && ops->switchdev_port_obj_dump)
413 return ops->switchdev_port_obj_dump(dev, obj, cb); 537 return ops->switchdev_port_obj_dump(dev, obj, cb);
414 538
@@ -832,10 +956,10 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
832{ 956{
833 struct switchdev_obj_port_fdb fdb = { 957 struct switchdev_obj_port_fdb fdb = {
834 .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, 958 .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB,
835 .addr = addr,
836 .vid = vid, 959 .vid = vid,
837 }; 960 };
838 961
962 ether_addr_copy(fdb.addr, addr);
839 return switchdev_port_obj_add(dev, &fdb.obj); 963 return switchdev_port_obj_add(dev, &fdb.obj);
840} 964}
841EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); 965EXPORT_SYMBOL_GPL(switchdev_port_fdb_add);
@@ -857,10 +981,10 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
857{ 981{
858 struct switchdev_obj_port_fdb fdb = { 982 struct switchdev_obj_port_fdb fdb = {
859 .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB, 983 .obj.id = SWITCHDEV_OBJ_ID_PORT_FDB,
860 .addr = addr,
861 .vid = vid, 984 .vid = vid,
862 }; 985 };
863 986
987 ether_addr_copy(fdb.addr, addr);
864 return switchdev_port_obj_del(dev, &fdb.obj); 988 return switchdev_port_obj_del(dev, &fdb.obj);
865} 989}
866EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); 990EXPORT_SYMBOL_GPL(switchdev_port_fdb_del);
@@ -977,6 +1101,8 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi)
977 struct net_device *dev = NULL; 1101 struct net_device *dev = NULL;
978 int nhsel; 1102 int nhsel;
979 1103
1104 ASSERT_RTNL();
1105
980 /* For this route, all nexthop devs must be on the same switch. */ 1106 /* For this route, all nexthop devs must be on the same switch. */
981 1107
982 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { 1108 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
@@ -1022,7 +1148,6 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
1022 .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, 1148 .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB,
1023 .dst = dst, 1149 .dst = dst,
1024 .dst_len = dst_len, 1150 .dst_len = dst_len,
1025 .fi = fi,
1026 .tos = tos, 1151 .tos = tos,
1027 .type = type, 1152 .type = type,
1028 .nlflags = nlflags, 1153 .nlflags = nlflags,
@@ -1031,6 +1156,8 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
1031 struct net_device *dev; 1156 struct net_device *dev;
1032 int err = 0; 1157 int err = 0;
1033 1158
1159 memcpy(&ipv4_fib.fi, fi, sizeof(ipv4_fib.fi));
1160
1034 /* Don't offload route if using custom ip rules or if 1161 /* Don't offload route if using custom ip rules or if
1035 * IPv4 FIB offloading has been disabled completely. 1162 * IPv4 FIB offloading has been disabled completely.
1036 */ 1163 */
@@ -1074,7 +1201,6 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
1074 .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB, 1201 .obj.id = SWITCHDEV_OBJ_ID_IPV4_FIB,
1075 .dst = dst, 1202 .dst = dst,
1076 .dst_len = dst_len, 1203 .dst_len = dst_len,
1077 .fi = fi,
1078 .tos = tos, 1204 .tos = tos,
1079 .type = type, 1205 .type = type,
1080 .nlflags = 0, 1206 .nlflags = 0,
@@ -1083,6 +1209,8 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
1083 struct net_device *dev; 1209 struct net_device *dev;
1084 int err = 0; 1210 int err = 0;
1085 1211
1212 memcpy(&ipv4_fib.fi, fi, sizeof(ipv4_fib.fi));
1213
1086 if (!(fi->fib_flags & RTNH_F_OFFLOAD)) 1214 if (!(fi->fib_flags & RTNH_F_OFFLOAD))
1087 return 0; 1215 return 0;
1088 1216
@@ -1205,10 +1333,11 @@ void switchdev_port_fwd_mark_set(struct net_device *dev,
1205 u32 mark = dev->ifindex; 1333 u32 mark = dev->ifindex;
1206 u32 reset_mark = 0; 1334 u32 reset_mark = 0;
1207 1335
1208 if (group_dev && joining) { 1336 if (group_dev) {
1209 mark = switchdev_port_fwd_mark_get(dev, group_dev); 1337 ASSERT_RTNL();
1210 } else if (group_dev && !joining) { 1338 if (joining)
1211 if (dev->offload_fwd_mark == mark) 1339 mark = switchdev_port_fwd_mark_get(dev, group_dev);
1340 else if (dev->offload_fwd_mark == mark)
1212 /* Ohoh, this port was the mark reference port, 1341 /* Ohoh, this port was the mark reference port,
1213 * but it's leaving the group, so reset the 1342 * but it's leaving the group, so reset the
1214 * mark for the remaining ports in the group. 1343 * mark for the remaining ports in the group.