diff options
-rw-r--r-- | Documentation/networking/switchdev.txt | 19 | ||||
-rw-r--r-- | include/net/switchdev.h | 12 | ||||
-rw-r--r-- | net/switchdev/switchdev.c | 100 |
3 files changed, 2 insertions, 129 deletions
diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt index 633dd1fd81b7..86174ce8cd13 100644 --- a/Documentation/networking/switchdev.txt +++ b/Documentation/networking/switchdev.txt | |||
@@ -371,22 +371,3 @@ The driver can monitor for updates to arp_tbl using the netevent notifier | |||
371 | NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops | 371 | NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops |
372 | for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy | 372 | for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy |
373 | to know when arp_tbl neighbor entries are purged from the port. | 373 | to know when arp_tbl neighbor entries are purged from the port. |
374 | |||
375 | Transaction item queue | ||
376 | ^^^^^^^^^^^^^^^^^^^^^^ | ||
377 | |||
378 | For switchdev ops attr_set and obj_add, there is a 2 phase transaction model | ||
379 | used. First phase is to "prepare" anything needed, including various checks, | ||
380 | memory allocation, etc. The goal is to handle the stuff that is not unlikely | ||
381 | to fail here. The second phase is to "commit" the actual changes. | ||
382 | |||
383 | Switchdev provides an infrastructure for sharing items (for example memory | ||
384 | allocations) between the two phases. | ||
385 | |||
386 | The object created by a driver in "prepare" phase and it is queued up by: | ||
387 | switchdev_trans_item_enqueue() | ||
388 | During the "commit" phase, the driver gets the object by: | ||
389 | switchdev_trans_item_dequeue() | ||
390 | |||
391 | If a transaction is aborted during "prepare" phase, switchdev code will handle | ||
392 | cleanup of the queued-up objects. | ||
diff --git a/include/net/switchdev.h b/include/net/switchdev.h index e4f751e19ecf..0ebd67ae7012 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h | |||
@@ -20,14 +20,7 @@ | |||
20 | #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) | 20 | #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) |
21 | #define SWITCHDEV_F_DEFER BIT(2) | 21 | #define SWITCHDEV_F_DEFER BIT(2) |
22 | 22 | ||
23 | struct switchdev_trans_item { | ||
24 | struct list_head list; | ||
25 | void *data; | ||
26 | void (*destructor)(const void *data); | ||
27 | }; | ||
28 | |||
29 | struct switchdev_trans { | 23 | struct switchdev_trans { |
30 | struct list_head item_list; | ||
31 | bool ph_prepare; | 24 | bool ph_prepare; |
32 | }; | 25 | }; |
33 | 26 | ||
@@ -105,11 +98,6 @@ struct switchdev_obj_port_mdb { | |||
105 | #define SWITCHDEV_OBJ_PORT_MDB(OBJ) \ | 98 | #define SWITCHDEV_OBJ_PORT_MDB(OBJ) \ |
106 | container_of((OBJ), struct switchdev_obj_port_mdb, obj) | 99 | container_of((OBJ), struct switchdev_obj_port_mdb, obj) |
107 | 100 | ||
108 | void switchdev_trans_item_enqueue(struct switchdev_trans *trans, | ||
109 | void *data, void (*destructor)(void const *), | ||
110 | struct switchdev_trans_item *tritem); | ||
111 | void *switchdev_trans_item_dequeue(struct switchdev_trans *trans); | ||
112 | |||
113 | typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); | 101 | typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); |
114 | 102 | ||
115 | enum switchdev_notifier_type { | 103 | enum switchdev_notifier_type { |
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index d81cfcee9ad9..90ba4a1f0a6d 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -23,78 +23,6 @@ | |||
23 | #include <linux/rtnetlink.h> | 23 | #include <linux/rtnetlink.h> |
24 | #include <net/switchdev.h> | 24 | #include <net/switchdev.h> |
25 | 25 | ||
26 | /** | ||
27 | * switchdev_trans_item_enqueue - Enqueue data item to transaction queue | ||
28 | * | ||
29 | * @trans: transaction | ||
30 | * @data: pointer to data being queued | ||
31 | * @destructor: data destructor | ||
32 | * @tritem: transaction item being queued | ||
33 | * | ||
34 | * Enqeueue data item to transaction queue. tritem is typically placed in | ||
35 | * cointainter pointed at by data pointer. Destructor is called on | ||
36 | * transaction abort and after successful commit phase in case | ||
37 | * the caller did not dequeue the item before. | ||
38 | */ | ||
39 | void switchdev_trans_item_enqueue(struct switchdev_trans *trans, | ||
40 | void *data, void (*destructor)(void const *), | ||
41 | struct switchdev_trans_item *tritem) | ||
42 | { | ||
43 | tritem->data = data; | ||
44 | tritem->destructor = destructor; | ||
45 | list_add_tail(&tritem->list, &trans->item_list); | ||
46 | } | ||
47 | EXPORT_SYMBOL_GPL(switchdev_trans_item_enqueue); | ||
48 | |||
49 | static struct switchdev_trans_item * | ||
50 | __switchdev_trans_item_dequeue(struct switchdev_trans *trans) | ||
51 | { | ||
52 | struct switchdev_trans_item *tritem; | ||
53 | |||
54 | if (list_empty(&trans->item_list)) | ||
55 | return NULL; | ||
56 | tritem = list_first_entry(&trans->item_list, | ||
57 | struct switchdev_trans_item, list); | ||
58 | list_del(&tritem->list); | ||
59 | return tritem; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * switchdev_trans_item_dequeue - Dequeue data item from transaction queue | ||
64 | * | ||
65 | * @trans: transaction | ||
66 | */ | ||
67 | void *switchdev_trans_item_dequeue(struct switchdev_trans *trans) | ||
68 | { | ||
69 | struct switchdev_trans_item *tritem; | ||
70 | |||
71 | tritem = __switchdev_trans_item_dequeue(trans); | ||
72 | BUG_ON(!tritem); | ||
73 | return tritem->data; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(switchdev_trans_item_dequeue); | ||
76 | |||
77 | static void switchdev_trans_init(struct switchdev_trans *trans) | ||
78 | { | ||
79 | INIT_LIST_HEAD(&trans->item_list); | ||
80 | } | ||
81 | |||
82 | static void switchdev_trans_items_destroy(struct switchdev_trans *trans) | ||
83 | { | ||
84 | struct switchdev_trans_item *tritem; | ||
85 | |||
86 | while ((tritem = __switchdev_trans_item_dequeue(trans))) | ||
87 | tritem->destructor(tritem->data); | ||
88 | } | ||
89 | |||
90 | static void switchdev_trans_items_warn_destroy(struct net_device *dev, | ||
91 | struct switchdev_trans *trans) | ||
92 | { | ||
93 | WARN(!list_empty(&trans->item_list), "%s: transaction item queue is not empty.\n", | ||
94 | dev->name); | ||
95 | switchdev_trans_items_destroy(trans); | ||
96 | } | ||
97 | |||
98 | static LIST_HEAD(deferred); | 26 | static LIST_HEAD(deferred); |
99 | static DEFINE_SPINLOCK(deferred_lock); | 27 | static DEFINE_SPINLOCK(deferred_lock); |
100 | 28 | ||
@@ -208,8 +136,6 @@ static int switchdev_port_attr_set_now(struct net_device *dev, | |||
208 | struct switchdev_trans trans; | 136 | struct switchdev_trans trans; |
209 | int err; | 137 | int err; |
210 | 138 | ||
211 | switchdev_trans_init(&trans); | ||
212 | |||
213 | /* Phase I: prepare for attr set. Driver/device should fail | 139 | /* Phase I: prepare for attr set. Driver/device should fail |
214 | * here if there are going to be issues in the commit phase, | 140 | * here if there are going to be issues in the commit phase, |
215 | * such as lack of resources or support. The driver/device | 141 | * such as lack of resources or support. The driver/device |
@@ -220,17 +146,8 @@ static int switchdev_port_attr_set_now(struct net_device *dev, | |||
220 | trans.ph_prepare = true; | 146 | trans.ph_prepare = true; |
221 | err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr, | 147 | err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr, |
222 | &trans); | 148 | &trans); |
223 | if (err) { | 149 | if (err) |
224 | /* Prepare phase failed: abort the transaction. Any | ||
225 | * resources reserved in the prepare phase are | ||
226 | * released. | ||
227 | */ | ||
228 | |||
229 | if (err != -EOPNOTSUPP) | ||
230 | switchdev_trans_items_destroy(&trans); | ||
231 | |||
232 | return err; | 150 | return err; |
233 | } | ||
234 | 151 | ||
235 | /* Phase II: commit attr set. This cannot fail as a fault | 152 | /* Phase II: commit attr set. This cannot fail as a fault |
236 | * of driver/device. If it does, it's a bug in the driver/device | 153 | * of driver/device. If it does, it's a bug in the driver/device |
@@ -242,7 +159,6 @@ static int switchdev_port_attr_set_now(struct net_device *dev, | |||
242 | &trans); | 159 | &trans); |
243 | WARN(err, "%s: Commit of attribute (id=%d) failed.\n", | 160 | WARN(err, "%s: Commit of attribute (id=%d) failed.\n", |
244 | dev->name, attr->id); | 161 | dev->name, attr->id); |
245 | switchdev_trans_items_warn_destroy(dev, &trans); | ||
246 | 162 | ||
247 | return err; | 163 | return err; |
248 | } | 164 | } |
@@ -341,8 +257,6 @@ static int switchdev_port_obj_add_now(struct net_device *dev, | |||
341 | 257 | ||
342 | ASSERT_RTNL(); | 258 | ASSERT_RTNL(); |
343 | 259 | ||
344 | switchdev_trans_init(&trans); | ||
345 | |||
346 | /* Phase I: prepare for obj add. Driver/device should fail | 260 | /* Phase I: prepare for obj add. Driver/device should fail |
347 | * here if there are going to be issues in the commit phase, | 261 | * here if there are going to be issues in the commit phase, |
348 | * such as lack of resources or support. The driver/device | 262 | * such as lack of resources or support. The driver/device |
@@ -353,17 +267,8 @@ static int switchdev_port_obj_add_now(struct net_device *dev, | |||
353 | trans.ph_prepare = true; | 267 | trans.ph_prepare = true; |
354 | err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD, | 268 | err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD, |
355 | dev, obj, &trans, extack); | 269 | dev, obj, &trans, extack); |
356 | if (err) { | 270 | if (err) |
357 | /* Prepare phase failed: abort the transaction. Any | ||
358 | * resources reserved in the prepare phase are | ||
359 | * released. | ||
360 | */ | ||
361 | |||
362 | if (err != -EOPNOTSUPP) | ||
363 | switchdev_trans_items_destroy(&trans); | ||
364 | |||
365 | return err; | 271 | return err; |
366 | } | ||
367 | 272 | ||
368 | /* Phase II: commit obj add. This cannot fail as a fault | 273 | /* Phase II: commit obj add. This cannot fail as a fault |
369 | * of driver/device. If it does, it's a bug in the driver/device | 274 | * of driver/device. If it does, it's a bug in the driver/device |
@@ -374,7 +279,6 @@ static int switchdev_port_obj_add_now(struct net_device *dev, | |||
374 | err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD, | 279 | err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD, |
375 | dev, obj, &trans, extack); | 280 | dev, obj, &trans, extack); |
376 | WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); | 281 | WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id); |
377 | switchdev_trans_items_warn_destroy(dev, &trans); | ||
378 | 282 | ||
379 | return err; | 283 | return err; |
380 | } | 284 | } |