switchdev.c (a3251c1a36f595046bea03935ebe37a1e1f1f1d7) switchdev.c (4c08c586ff29bda47e3db14da096331d84933f48)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * net/switchdev/switchdev.c - Switch device API
4 * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us>
5 * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com>
6 */
7
8#include <linux/kernel.h>

--- 86 unchanged lines hidden (view full) ---

95 list_add_tail(&dfitem->list, &deferred);
96 spin_unlock_bh(&deferred_lock);
97 schedule_work(&deferred_process_work);
98 return 0;
99}
100
101static int switchdev_port_attr_notify(enum switchdev_notifier_type nt,
102 struct net_device *dev,
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * net/switchdev/switchdev.c - Switch device API
4 * Copyright (c) 2014-2015 Jiri Pirko <jiri@resnulli.us>
5 * Copyright (c) 2014-2015 Scott Feldman <sfeldma@gmail.com>
6 */
7
8#include <linux/kernel.h>

--- 86 unchanged lines hidden (view full) ---

95 list_add_tail(&dfitem->list, &deferred);
96 spin_unlock_bh(&deferred_lock);
97 schedule_work(&deferred_process_work);
98 return 0;
99}
100
101static int switchdev_port_attr_notify(enum switchdev_notifier_type nt,
102 struct net_device *dev,
103 const struct switchdev_attr *attr,
104 struct switchdev_trans *trans)
103 const struct switchdev_attr *attr)
105{
106 int err;
107 int rc;
108
109 struct switchdev_notifier_port_attr_info attr_info = {
110 .attr = attr,
104{
105 int err;
106 int rc;
107
108 struct switchdev_notifier_port_attr_info attr_info = {
109 .attr = attr,
111 .trans = trans,
112 .handled = false,
113 };
114
115 rc = call_switchdev_blocking_notifiers(nt, dev,
116 &attr_info.info, NULL);
117 err = notifier_to_errno(rc);
118 if (err) {
119 WARN_ON(!attr_info.handled);

--- 4 unchanged lines hidden (view full) ---

124 return -EOPNOTSUPP;
125
126 return 0;
127}
128
129static int switchdev_port_attr_set_now(struct net_device *dev,
130 const struct switchdev_attr *attr)
131{
110 .handled = false,
111 };
112
113 rc = call_switchdev_blocking_notifiers(nt, dev,
114 &attr_info.info, NULL);
115 err = notifier_to_errno(rc);
116 if (err) {
117 WARN_ON(!attr_info.handled);

--- 4 unchanged lines hidden (view full) ---

122 return -EOPNOTSUPP;
123
124 return 0;
125}
126
127static int switchdev_port_attr_set_now(struct net_device *dev,
128 const struct switchdev_attr *attr)
129{
132 struct switchdev_trans trans;
133 int err;
134
135 /* Phase I: prepare for attr set. Driver/device should fail
136 * here if there are going to be issues in the commit phase,
137 * such as lack of resources or support. The driver/device
138 * should reserve resources needed for the commit phase here,
139 * but should not commit the attr.
140 */
141
142 trans.ph_prepare = true;
143 err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr,
144 &trans);
145 if (err)
146 return err;
147
148 /* Phase II: commit attr set. This cannot fail as a fault
149 * of driver/device. If it does, it's a bug in the driver/device
150 * because the driver said everythings was OK in phase I.
151 */
152
153 trans.ph_prepare = false;
154 err = switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr,
155 &trans);
156 WARN(err, "%s: Commit of attribute (id=%d) failed.\n",
157 dev->name, attr->id);
158
159 return err;
130 return switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr);
160}
161
162static void switchdev_port_attr_set_deferred(struct net_device *dev,
163 const void *data)
164{
165 const struct switchdev_attr *attr = data;
166 int err;
167

--- 13 unchanged lines hidden (view full) ---

181}
182
183/**
184 * switchdev_port_attr_set - Set port attribute
185 *
186 * @dev: port device
187 * @attr: attribute to set
188 *
131}
132
133static void switchdev_port_attr_set_deferred(struct net_device *dev,
134 const void *data)
135{
136 const struct switchdev_attr *attr = data;
137 int err;
138

--- 13 unchanged lines hidden (view full) ---

152}
153
154/**
155 * switchdev_port_attr_set - Set port attribute
156 *
157 * @dev: port device
158 * @attr: attribute to set
159 *
189 * Use a 2-phase prepare-commit transaction model to ensure
190 * system is not left in a partially updated state due to
191 * failure from driver/device.
192 *
193 * rtnl_lock must be held and must not be in atomic section,
194 * in case SWITCHDEV_F_DEFER flag is not set.
195 */
196int switchdev_port_attr_set(struct net_device *dev,
197 const struct switchdev_attr *attr)
198{
199 if (attr->flags & SWITCHDEV_F_DEFER)
200 return switchdev_port_attr_set_defer(dev, attr);

--- 15 unchanged lines hidden (view full) ---

216 BUG();
217 }
218 return 0;
219}
220
221static int switchdev_port_obj_notify(enum switchdev_notifier_type nt,
222 struct net_device *dev,
223 const struct switchdev_obj *obj,
160 * rtnl_lock must be held and must not be in atomic section,
161 * in case SWITCHDEV_F_DEFER flag is not set.
162 */
163int switchdev_port_attr_set(struct net_device *dev,
164 const struct switchdev_attr *attr)
165{
166 if (attr->flags & SWITCHDEV_F_DEFER)
167 return switchdev_port_attr_set_defer(dev, attr);

--- 15 unchanged lines hidden (view full) ---

183 BUG();
184 }
185 return 0;
186}
187
188static int switchdev_port_obj_notify(enum switchdev_notifier_type nt,
189 struct net_device *dev,
190 const struct switchdev_obj *obj,
224 struct switchdev_trans *trans,
225 struct netlink_ext_ack *extack)
226{
227 int rc;
228 int err;
229
230 struct switchdev_notifier_port_obj_info obj_info = {
231 .obj = obj,
191 struct netlink_ext_ack *extack)
192{
193 int rc;
194 int err;
195
196 struct switchdev_notifier_port_obj_info obj_info = {
197 .obj = obj,
232 .trans = trans,
233 .handled = false,
234 };
235
236 rc = call_switchdev_blocking_notifiers(nt, dev, &obj_info.info, extack);
237 err = notifier_to_errno(rc);
238 if (err) {
239 WARN_ON(!obj_info.handled);
240 return err;
241 }
242 if (!obj_info.handled)
243 return -EOPNOTSUPP;
244 return 0;
245}
246
198 .handled = false,
199 };
200
201 rc = call_switchdev_blocking_notifiers(nt, dev, &obj_info.info, extack);
202 err = notifier_to_errno(rc);
203 if (err) {
204 WARN_ON(!obj_info.handled);
205 return err;
206 }
207 if (!obj_info.handled)
208 return -EOPNOTSUPP;
209 return 0;
210}
211
247static int switchdev_port_obj_add_now(struct net_device *dev,
248 const struct switchdev_obj *obj,
249 struct netlink_ext_ack *extack)
250{
251 struct switchdev_trans trans;
252 int err;
253
254 ASSERT_RTNL();
255
256 /* Phase I: prepare for obj add. Driver/device should fail
257 * here if there are going to be issues in the commit phase,
258 * such as lack of resources or support. The driver/device
259 * should reserve resources needed for the commit phase here,
260 * but should not commit the obj.
261 */
262
263 trans.ph_prepare = true;
264 err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
265 dev, obj, &trans, extack);
266 if (err)
267 return err;
268
269 /* Phase II: commit obj add. This cannot fail as a fault
270 * of driver/device. If it does, it's a bug in the driver/device
271 * because the driver said everythings was OK in phase I.
272 */
273
274 trans.ph_prepare = false;
275 err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
276 dev, obj, &trans, extack);
277 WARN(err, "%s: Commit of object (id=%d) failed.\n", dev->name, obj->id);
278
279 return err;
280}
281
282static void switchdev_port_obj_add_deferred(struct net_device *dev,
283 const void *data)
284{
285 const struct switchdev_obj *obj = data;
286 int err;
287
212static void switchdev_port_obj_add_deferred(struct net_device *dev,
213 const void *data)
214{
215 const struct switchdev_obj *obj = data;
216 int err;
217
288 err = switchdev_port_obj_add_now(dev, obj, NULL);
218 ASSERT_RTNL();
219 err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
220 dev, obj, NULL);
289 if (err && err != -EOPNOTSUPP)
290 netdev_err(dev, "failed (err=%d) to add object (id=%d)\n",
291 err, obj->id);
292 if (obj->complete)
293 obj->complete(dev, err, obj->complete_priv);
294}
295
296static int switchdev_port_obj_add_defer(struct net_device *dev,

--- 5 unchanged lines hidden (view full) ---

302
303/**
304 * switchdev_port_obj_add - Add port object
305 *
306 * @dev: port device
307 * @obj: object to add
308 * @extack: netlink extended ack
309 *
221 if (err && err != -EOPNOTSUPP)
222 netdev_err(dev, "failed (err=%d) to add object (id=%d)\n",
223 err, obj->id);
224 if (obj->complete)
225 obj->complete(dev, err, obj->complete_priv);
226}
227
228static int switchdev_port_obj_add_defer(struct net_device *dev,

--- 5 unchanged lines hidden (view full) ---

234
235/**
236 * switchdev_port_obj_add - Add port object
237 *
238 * @dev: port device
239 * @obj: object to add
240 * @extack: netlink extended ack
241 *
310 * Use a 2-phase prepare-commit transaction model to ensure
311 * system is not left in a partially updated state due to
312 * failure from driver/device.
313 *
314 * rtnl_lock must be held and must not be in atomic section,
315 * in case SWITCHDEV_F_DEFER flag is not set.
316 */
317int switchdev_port_obj_add(struct net_device *dev,
318 const struct switchdev_obj *obj,
319 struct netlink_ext_ack *extack)
320{
321 if (obj->flags & SWITCHDEV_F_DEFER)
322 return switchdev_port_obj_add_defer(dev, obj);
323 ASSERT_RTNL();
242 * rtnl_lock must be held and must not be in atomic section,
243 * in case SWITCHDEV_F_DEFER flag is not set.
244 */
245int switchdev_port_obj_add(struct net_device *dev,
246 const struct switchdev_obj *obj,
247 struct netlink_ext_ack *extack)
248{
249 if (obj->flags & SWITCHDEV_F_DEFER)
250 return switchdev_port_obj_add_defer(dev, obj);
251 ASSERT_RTNL();
324 return switchdev_port_obj_add_now(dev, obj, extack);
252 return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
253 dev, obj, extack);
325}
326EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
327
328static int switchdev_port_obj_del_now(struct net_device *dev,
329 const struct switchdev_obj *obj)
330{
331 return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_DEL,
254}
255EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
256
257static int switchdev_port_obj_del_now(struct net_device *dev,
258 const struct switchdev_obj *obj)
259{
260 return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_DEL,
332 dev, obj, NULL, NULL);
261 dev, obj, NULL);
333}
334
335static void switchdev_port_obj_del_deferred(struct net_device *dev,
336 const void *data)
337{
338 const struct switchdev_obj *obj = data;
339 int err;
340

--- 103 unchanged lines hidden (view full) ---

444}
445EXPORT_SYMBOL_GPL(call_switchdev_blocking_notifiers);
446
447static int __switchdev_handle_port_obj_add(struct net_device *dev,
448 struct switchdev_notifier_port_obj_info *port_obj_info,
449 bool (*check_cb)(const struct net_device *dev),
450 int (*add_cb)(struct net_device *dev,
451 const struct switchdev_obj *obj,
262}
263
264static void switchdev_port_obj_del_deferred(struct net_device *dev,
265 const void *data)
266{
267 const struct switchdev_obj *obj = data;
268 int err;
269

--- 103 unchanged lines hidden (view full) ---

373}
374EXPORT_SYMBOL_GPL(call_switchdev_blocking_notifiers);
375
376static int __switchdev_handle_port_obj_add(struct net_device *dev,
377 struct switchdev_notifier_port_obj_info *port_obj_info,
378 bool (*check_cb)(const struct net_device *dev),
379 int (*add_cb)(struct net_device *dev,
380 const struct switchdev_obj *obj,
452 struct switchdev_trans *trans,
453 struct netlink_ext_ack *extack))
454{
455 struct netlink_ext_ack *extack;
456 struct net_device *lower_dev;
457 struct list_head *iter;
458 int err = -EOPNOTSUPP;
459
460 extack = switchdev_notifier_info_to_extack(&port_obj_info->info);
461
462 if (check_cb(dev)) {
381 struct netlink_ext_ack *extack))
382{
383 struct netlink_ext_ack *extack;
384 struct net_device *lower_dev;
385 struct list_head *iter;
386 int err = -EOPNOTSUPP;
387
388 extack = switchdev_notifier_info_to_extack(&port_obj_info->info);
389
390 if (check_cb(dev)) {
463 err = add_cb(dev, port_obj_info->obj, port_obj_info->trans,
464 extack);
391 err = add_cb(dev, port_obj_info->obj, extack);
465 if (err != -EOPNOTSUPP)
466 port_obj_info->handled = true;
467 return err;
468 }
469
470 /* Switch ports might be stacked under e.g. a LAG. Ignore the
471 * unsupported devices, another driver might be able to handle them. But
472 * propagate to the callers any hard errors.

--- 14 unchanged lines hidden (view full) ---

487 return err;
488}
489
490int switchdev_handle_port_obj_add(struct net_device *dev,
491 struct switchdev_notifier_port_obj_info *port_obj_info,
492 bool (*check_cb)(const struct net_device *dev),
493 int (*add_cb)(struct net_device *dev,
494 const struct switchdev_obj *obj,
392 if (err != -EOPNOTSUPP)
393 port_obj_info->handled = true;
394 return err;
395 }
396
397 /* Switch ports might be stacked under e.g. a LAG. Ignore the
398 * unsupported devices, another driver might be able to handle them. But
399 * propagate to the callers any hard errors.

--- 14 unchanged lines hidden (view full) ---

414 return err;
415}
416
417int switchdev_handle_port_obj_add(struct net_device *dev,
418 struct switchdev_notifier_port_obj_info *port_obj_info,
419 bool (*check_cb)(const struct net_device *dev),
420 int (*add_cb)(struct net_device *dev,
421 const struct switchdev_obj *obj,
495 struct switchdev_trans *trans,
496 struct netlink_ext_ack *extack))
497{
498 int err;
499
500 err = __switchdev_handle_port_obj_add(dev, port_obj_info, check_cb,
501 add_cb);
502 if (err == -EOPNOTSUPP)
503 err = 0;

--- 54 unchanged lines hidden (view full) ---

558}
559EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del);
560
561static int __switchdev_handle_port_attr_set(struct net_device *dev,
562 struct switchdev_notifier_port_attr_info *port_attr_info,
563 bool (*check_cb)(const struct net_device *dev),
564 int (*set_cb)(struct net_device *dev,
565 const struct switchdev_attr *attr,
422 struct netlink_ext_ack *extack))
423{
424 int err;
425
426 err = __switchdev_handle_port_obj_add(dev, port_obj_info, check_cb,
427 add_cb);
428 if (err == -EOPNOTSUPP)
429 err = 0;

--- 54 unchanged lines hidden (view full) ---

484}
485EXPORT_SYMBOL_GPL(switchdev_handle_port_obj_del);
486
487static int __switchdev_handle_port_attr_set(struct net_device *dev,
488 struct switchdev_notifier_port_attr_info *port_attr_info,
489 bool (*check_cb)(const struct net_device *dev),
490 int (*set_cb)(struct net_device *dev,
491 const struct switchdev_attr *attr,
566 struct switchdev_trans *trans))
492 struct netlink_ext_ack *extack))
567{
493{
494 struct netlink_ext_ack *extack;
568 struct net_device *lower_dev;
569 struct list_head *iter;
570 int err = -EOPNOTSUPP;
571
495 struct net_device *lower_dev;
496 struct list_head *iter;
497 int err = -EOPNOTSUPP;
498
499 extack = switchdev_notifier_info_to_extack(&port_attr_info->info);
500
572 if (check_cb(dev)) {
501 if (check_cb(dev)) {
573 err = set_cb(dev, port_attr_info->attr, port_attr_info->trans);
502 err = set_cb(dev, port_attr_info->attr, extack);
574 if (err != -EOPNOTSUPP)
575 port_attr_info->handled = true;
576 return err;
577 }
578
579 /* Switch ports might be stacked under e.g. a LAG. Ignore the
580 * unsupported devices, another driver might be able to handle them. But
581 * propagate to the callers any hard errors.

--- 14 unchanged lines hidden (view full) ---

596 return err;
597}
598
599int switchdev_handle_port_attr_set(struct net_device *dev,
600 struct switchdev_notifier_port_attr_info *port_attr_info,
601 bool (*check_cb)(const struct net_device *dev),
602 int (*set_cb)(struct net_device *dev,
603 const struct switchdev_attr *attr,
503 if (err != -EOPNOTSUPP)
504 port_attr_info->handled = true;
505 return err;
506 }
507
508 /* Switch ports might be stacked under e.g. a LAG. Ignore the
509 * unsupported devices, another driver might be able to handle them. But
510 * propagate to the callers any hard errors.

--- 14 unchanged lines hidden (view full) ---

525 return err;
526}
527
528int switchdev_handle_port_attr_set(struct net_device *dev,
529 struct switchdev_notifier_port_attr_info *port_attr_info,
530 bool (*check_cb)(const struct net_device *dev),
531 int (*set_cb)(struct net_device *dev,
532 const struct switchdev_attr *attr,
604 struct switchdev_trans *trans))
533 struct netlink_ext_ack *extack))
605{
606 int err;
607
608 err = __switchdev_handle_port_attr_set(dev, port_attr_info, check_cb,
609 set_cb);
610 if (err == -EOPNOTSUPP)
611 err = 0;
612 return err;
613}
614EXPORT_SYMBOL_GPL(switchdev_handle_port_attr_set);
534{
535 int err;
536
537 err = __switchdev_handle_port_attr_set(dev, port_attr_info, check_cb,
538 set_cb);
539 if (err == -EOPNOTSUPP)
540 err = 0;
541 return err;
542}
543EXPORT_SYMBOL_GPL(switchdev_handle_port_attr_set);