aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/switchdev.txt19
-rw-r--r--include/net/switchdev.h12
-rw-r--r--net/switchdev/switchdev.c100
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
371NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops 371NETEVENT_NEIGH_UPDATE. The device can be programmed with resolved nexthops
372for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy 372for the routes as arp_tbl updates. The driver implements ndo_neigh_destroy
373to know when arp_tbl neighbor entries are purged from the port. 373to know when arp_tbl neighbor entries are purged from the port.
374
375Transaction item queue
376^^^^^^^^^^^^^^^^^^^^^^
377
378For switchdev ops attr_set and obj_add, there is a 2 phase transaction model
379used. First phase is to "prepare" anything needed, including various checks,
380memory allocation, etc. The goal is to handle the stuff that is not unlikely
381to fail here. The second phase is to "commit" the actual changes.
382
383Switchdev provides an infrastructure for sharing items (for example memory
384allocations) between the two phases.
385
386The object created by a driver in "prepare" phase and it is queued up by:
387switchdev_trans_item_enqueue()
388During the "commit" phase, the driver gets the object by:
389switchdev_trans_item_dequeue()
390
391If a transaction is aborted during "prepare" phase, switchdev code will handle
392cleanup 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
23struct switchdev_trans_item {
24 struct list_head list;
25 void *data;
26 void (*destructor)(const void *data);
27};
28
29struct switchdev_trans { 23struct 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
108void switchdev_trans_item_enqueue(struct switchdev_trans *trans,
109 void *data, void (*destructor)(void const *),
110 struct switchdev_trans_item *tritem);
111void *switchdev_trans_item_dequeue(struct switchdev_trans *trans);
112
113typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); 101typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj);
114 102
115enum switchdev_notifier_type { 103enum 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 */
39void 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}
47EXPORT_SYMBOL_GPL(switchdev_trans_item_enqueue);
48
49static 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 */
67void *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}
75EXPORT_SYMBOL_GPL(switchdev_trans_item_dequeue);
76
77static void switchdev_trans_init(struct switchdev_trans *trans)
78{
79 INIT_LIST_HEAD(&trans->item_list);
80}
81
82static 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
90static 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
98static LIST_HEAD(deferred); 26static LIST_HEAD(deferred);
99static DEFINE_SPINLOCK(deferred_lock); 27static 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}