aboutsummaryrefslogtreecommitdiffstats
path: root/net/switchdev
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2015-09-24 04:02:41 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-25 01:59:21 -0400
commit7ea6eb3f56f45cf4babae8b9a7421868e5005f17 (patch)
treee5e4d816edc8e6254f35ffc689678b9cd59185db /net/switchdev
parent69f5df491e0becb75d2d795add7481a35218d657 (diff)
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 <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/switchdev')
-rw-r--r--net/switchdev/switchdev.c111
1 files changed, 98 insertions, 13 deletions
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index df5a5446ff4c..35e2967ffa18 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * net/switchdev/switchdev.c - Switch device API 2 * net/switchdev/switchdev.c - Switch device API
3 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us> 3 * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us>
4 * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com> 4 * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,83 @@
16#include <linux/notifier.h> 16#include <linux/notifier.h>
17#include <linux/netdevice.h> 17#include <linux/netdevice.h>
18#include <linux/if_bridge.h> 18#include <linux/if_bridge.h>
19#include <linux/list.h>
19#include <net/ip_fib.h> 20#include <net/ip_fib.h>
20#include <net/switchdev.h> 21#include <net/switchdev.h>
21 22
22/** 23/**
24 * switchdev_trans_item_enqueue - Enqueue data item to transaction queue
25 *
26 * @trans: transaction
27 * @data: pointer to data being queued
28 * @destructor: data destructor
29 * @tritem: transaction item being queued
30 *
31 * Enqeueue data item to transaction queue. tritem is typically placed in
32 * cointainter pointed at by data pointer. Destructor is called on
33 * transaction abort and after successful commit phase in case
34 * the caller did not dequeue the item before.
35 */
36void switchdev_trans_item_enqueue(struct switchdev_trans *trans,
37 void *data, void (*destructor)(void const *),
38 struct switchdev_trans_item *tritem)
39{
40 tritem->data = data;
41 tritem->destructor = destructor;
42 list_add_tail(&tritem->list, &trans->item_list);
43}
44EXPORT_SYMBOL_GPL(switchdev_trans_item_enqueue);
45
46static struct switchdev_trans_item *
47__switchdev_trans_item_dequeue(struct switchdev_trans *trans)
48{
49 struct switchdev_trans_item *tritem;
50
51 if (list_empty(&trans->item_list))
52 return NULL;
53 tritem = list_first_entry(&trans->item_list,
54 struct switchdev_trans_item, list);
55 list_del(&tritem->list);
56 return tritem;
57}
58
59/**
60 * switchdev_trans_item_dequeue - Dequeue data item from transaction queue
61 *
62 * @trans: transaction
63 */
64void *switchdev_trans_item_dequeue(struct switchdev_trans *trans)
65{
66 struct switchdev_trans_item *tritem;
67
68 tritem = __switchdev_trans_item_dequeue(trans);
69 BUG_ON(!tritem);
70 return tritem->data;
71}
72EXPORT_SYMBOL_GPL(switchdev_trans_item_dequeue);
73
74static void switchdev_trans_init(struct switchdev_trans *trans)
75{
76 INIT_LIST_HEAD(&trans->item_list);
77}
78
79static void switchdev_trans_items_destroy(struct switchdev_trans *trans)
80{
81 struct switchdev_trans_item *tritem;
82
83 while ((tritem = __switchdev_trans_item_dequeue(trans)))
84 tritem->destructor(tritem->data);
85}
86
87static void switchdev_trans_items_warn_destroy(struct net_device *dev,
88 struct switchdev_trans *trans)
89{
90 WARN(!list_empty(&trans->item_list), "%s: transaction item queue is not empty.\n",
91 dev->name);
92 switchdev_trans_items_destroy(trans);
93}
94
95/**
23 * switchdev_port_attr_get - Get port attribute 96 * switchdev_port_attr_get - Get port attribute
24 * 97 *
25 * @dev: port device 98 * @dev: port device
@@ -62,7 +135,8 @@ int switchdev_port_attr_get(struct net_device *dev, struct switchdev_attr *attr)
62EXPORT_SYMBOL_GPL(switchdev_port_attr_get); 135EXPORT_SYMBOL_GPL(switchdev_port_attr_get);
63 136
64static int __switchdev_port_attr_set(struct net_device *dev, 137static int __switchdev_port_attr_set(struct net_device *dev,
65 struct switchdev_attr *attr) 138 struct switchdev_attr *attr,
139 struct switchdev_trans *trans)
66{ 140{
67 const struct switchdev_ops *ops = dev->switchdev_ops; 141 const struct switchdev_ops *ops = dev->switchdev_ops;
68 struct net_device *lower_dev; 142 struct net_device *lower_dev;
@@ -70,7 +144,7 @@ static int __switchdev_port_attr_set(struct net_device *dev,
70 int err = -EOPNOTSUPP; 144 int err = -EOPNOTSUPP;
71 145
72 if (ops && ops->switchdev_port_attr_set) 146 if (ops && ops->switchdev_port_attr_set)
73 return ops->switchdev_port_attr_set(dev, attr); 147 return ops->switchdev_port_attr_set(dev, attr, trans);
74 148
75 if (attr->flags & SWITCHDEV_F_NO_RECURSE) 149 if (attr->flags & SWITCHDEV_F_NO_RECURSE)
76 return err; 150 return err;
@@ -81,7 +155,7 @@ static int __switchdev_port_attr_set(struct net_device *dev,
81 */ 155 */
82 156
83 netdev_for_each_lower_dev(dev, lower_dev, iter) { 157 netdev_for_each_lower_dev(dev, lower_dev, iter) {
84 err = __switchdev_port_attr_set(lower_dev, attr); 158 err = __switchdev_port_attr_set(lower_dev, attr, trans);
85 if (err) 159 if (err)
86 break; 160 break;
87 } 161 }
@@ -144,6 +218,7 @@ static int switchdev_port_attr_set_defer(struct net_device *dev,
144 */ 218 */
145int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr) 219int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
146{ 220{
221 struct switchdev_trans trans;
147 int err; 222 int err;
148 223
149 if (!rtnl_is_locked()) { 224 if (!rtnl_is_locked()) {
@@ -156,6 +231,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
156 return switchdev_port_attr_set_defer(dev, attr); 231 return switchdev_port_attr_set_defer(dev, attr);
157 } 232 }
158 233
234 switchdev_trans_init(&trans);
235
159 /* Phase I: prepare for attr set. Driver/device should fail 236 /* Phase I: prepare for attr set. Driver/device should fail
160 * here if there are going to be issues in the commit phase, 237 * here if there are going to be issues in the commit phase,
161 * such as lack of resources or support. The driver/device 238 * 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)
164 */ 241 */
165 242
166 attr->trans_ph = SWITCHDEV_TRANS_PREPARE; 243 attr->trans_ph = SWITCHDEV_TRANS_PREPARE;
167 err = __switchdev_port_attr_set(dev, attr); 244 err = __switchdev_port_attr_set(dev, attr, &trans);
168 if (err) { 245 if (err) {
169 /* Prepare phase failed: abort the transaction. Any 246 /* Prepare phase failed: abort the transaction. Any
170 * resources reserved in the prepare phase are 247 * resources reserved in the prepare phase are
@@ -173,7 +250,8 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
173 250
174 if (err != -EOPNOTSUPP) { 251 if (err != -EOPNOTSUPP) {
175 attr->trans_ph = SWITCHDEV_TRANS_ABORT; 252 attr->trans_ph = SWITCHDEV_TRANS_ABORT;
176 __switchdev_port_attr_set(dev, attr); 253 __switchdev_port_attr_set(dev, attr, &trans);
254 switchdev_trans_items_destroy(&trans);
177 } 255 }
178 256
179 return err; 257 return err;
@@ -185,16 +263,18 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
185 */ 263 */
186 264
187 attr->trans_ph = SWITCHDEV_TRANS_COMMIT; 265 attr->trans_ph = SWITCHDEV_TRANS_COMMIT;
188 err = __switchdev_port_attr_set(dev, attr); 266 err = __switchdev_port_attr_set(dev, attr, &trans);
189 WARN(err, "%s: Commit of attribute (id=%d) failed.\n", 267 WARN(err, "%s: Commit of attribute (id=%d) failed.\n",
190 dev->name, attr->id); 268 dev->name, attr->id);
269 switchdev_trans_items_warn_destroy(dev, &trans);
191 270
192 return err; 271 return err;
193} 272}
194EXPORT_SYMBOL_GPL(switchdev_port_attr_set); 273EXPORT_SYMBOL_GPL(switchdev_port_attr_set);
195 274
196static int __switchdev_port_obj_add(struct net_device *dev, 275static int __switchdev_port_obj_add(struct net_device *dev,
197 struct switchdev_obj *obj) 276 struct switchdev_obj *obj,
277 struct switchdev_trans *trans)
198{ 278{
199 const struct switchdev_ops *ops = dev->switchdev_ops; 279 const struct switchdev_ops *ops = dev->switchdev_ops;
200 struct net_device *lower_dev; 280 struct net_device *lower_dev;
@@ -202,7 +282,7 @@ static int __switchdev_port_obj_add(struct net_device *dev,
202 int err = -EOPNOTSUPP; 282 int err = -EOPNOTSUPP;
203 283
204 if (ops && ops->switchdev_port_obj_add) 284 if (ops && ops->switchdev_port_obj_add)
205 return ops->switchdev_port_obj_add(dev, obj); 285 return ops->switchdev_port_obj_add(dev, obj, trans);
206 286
207 /* Switch device port(s) may be stacked under 287 /* Switch device port(s) may be stacked under
208 * bond/team/vlan dev, so recurse down to add object on 288 * 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,
210 */ 290 */
211 291
212 netdev_for_each_lower_dev(dev, lower_dev, iter) { 292 netdev_for_each_lower_dev(dev, lower_dev, iter) {
213 err = __switchdev_port_obj_add(lower_dev, obj); 293 err = __switchdev_port_obj_add(lower_dev, obj, trans);
214 if (err) 294 if (err)
215 break; 295 break;
216 } 296 }
@@ -232,10 +312,13 @@ static int __switchdev_port_obj_add(struct net_device *dev,
232 */ 312 */
233int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj) 313int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
234{ 314{
315 struct switchdev_trans trans;
235 int err; 316 int err;
236 317
237 ASSERT_RTNL(); 318 ASSERT_RTNL();
238 319
320 switchdev_trans_init(&trans);
321
239 /* Phase I: prepare for obj add. Driver/device should fail 322 /* Phase I: prepare for obj add. Driver/device should fail
240 * here if there are going to be issues in the commit phase, 323 * here if there are going to be issues in the commit phase,
241 * such as lack of resources or support. The driver/device 324 * 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)
244 */ 327 */
245 328
246 obj->trans_ph = SWITCHDEV_TRANS_PREPARE; 329 obj->trans_ph = SWITCHDEV_TRANS_PREPARE;
247 err = __switchdev_port_obj_add(dev, obj); 330 err = __switchdev_port_obj_add(dev, obj, &trans);
248 if (err) { 331 if (err) {
249 /* Prepare phase failed: abort the transaction. Any 332 /* Prepare phase failed: abort the transaction. Any
250 * resources reserved in the prepare phase are 333 * resources reserved in the prepare phase are
@@ -253,7 +336,8 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
253 336
254 if (err != -EOPNOTSUPP) { 337 if (err != -EOPNOTSUPP) {
255 obj->trans_ph = SWITCHDEV_TRANS_ABORT; 338 obj->trans_ph = SWITCHDEV_TRANS_ABORT;
256 __switchdev_port_obj_add(dev, obj); 339 __switchdev_port_obj_add(dev, obj, &trans);
340 switchdev_trans_items_destroy(&trans);
257 } 341 }
258 342
259 return err; 343 return err;
@@ -265,8 +349,9 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
265 */ 349 */
266 350
267 obj->trans_ph = SWITCHDEV_TRANS_COMMIT; 351 obj->trans_ph = SWITCHDEV_TRANS_COMMIT;
268 err = __switchdev_port_obj_add(dev, obj); 352 err = __switchdev_port_obj_add(dev, obj, &trans);
269 WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); 353 WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id);
354 switchdev_trans_items_warn_destroy(dev, &trans);
270 355
271 return err; 356 return err;
272} 357}