switchdev.c (4b4193256c8d3bc3a5397b5cd9494c2ad386317d) switchdev.c (ffb68fc58e9640762be891f9aebe4f5aac615ab3)
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>

--- 207 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,
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>

--- 207 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,
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,
224 struct netlink_ext_ack *extack)
225{
226 int rc;
227 int err;
228
229 struct switchdev_notifier_port_obj_info obj_info = {
230 .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
247static int switchdev_port_obj_add_now(struct net_device *dev,
248 const struct switchdev_obj *obj,
249 struct netlink_ext_ack *extack)
250{
231 .handled = false,
232 };
233
234 rc = call_switchdev_blocking_notifiers(nt, dev, &obj_info.info, extack);
235 err = notifier_to_errno(rc);
236 if (err) {
237 WARN_ON(!obj_info.handled);
238 return err;
239 }
240 if (!obj_info.handled)
241 return -EOPNOTSUPP;
242 return 0;
243}
244
245static int switchdev_port_obj_add_now(struct net_device *dev,
246 const struct switchdev_obj *obj,
247 struct netlink_ext_ack *extack)
248{
251 struct switchdev_trans trans;
252 int err;
253
254 ASSERT_RTNL();
255
249 ASSERT_RTNL();
250
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;
251 return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
252 dev, obj, extack);
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

--- 14 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 *
253}
254
255static void switchdev_port_obj_add_deferred(struct net_device *dev,
256 const void *data)
257{
258 const struct switchdev_obj *obj = data;
259 int err;
260

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

275
276/**
277 * switchdev_port_obj_add - Add port object
278 *
279 * @dev: port device
280 * @obj: object to add
281 * @extack: netlink extended ack
282 *
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();
324 return switchdev_port_obj_add_now(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,
283 * rtnl_lock must be held and must not be in atomic section,
284 * in case SWITCHDEV_F_DEFER flag is not set.
285 */
286int switchdev_port_obj_add(struct net_device *dev,
287 const struct switchdev_obj *obj,
288 struct netlink_ext_ack *extack)
289{
290 if (obj->flags & SWITCHDEV_F_DEFER)
291 return switchdev_port_obj_add_defer(dev, obj);
292 ASSERT_RTNL();
293 return switchdev_port_obj_add_now(dev, obj, extack);
294}
295EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
296
297static int switchdev_port_obj_del_now(struct net_device *dev,
298 const struct switchdev_obj *obj)
299{
300 return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_DEL,
332 dev, obj, NULL, NULL);
301 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,
302}
303
304static void switchdev_port_obj_del_deferred(struct net_device *dev,
305 const void *data)
306{
307 const struct switchdev_obj *obj = data;
308 int err;
309

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

413}
414EXPORT_SYMBOL_GPL(call_switchdev_blocking_notifiers);
415
416static int __switchdev_handle_port_obj_add(struct net_device *dev,
417 struct switchdev_notifier_port_obj_info *port_obj_info,
418 bool (*check_cb)(const struct net_device *dev),
419 int (*add_cb)(struct net_device *dev,
420 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)) {
463 /* This flag is only checked if the return value is success. */
464 port_obj_info->handled = true;
421 struct netlink_ext_ack *extack))
422{
423 struct netlink_ext_ack *extack;
424 struct net_device *lower_dev;
425 struct list_head *iter;
426 int err = -EOPNOTSUPP;
427
428 extack = switchdev_notifier_info_to_extack(&port_obj_info->info);
429
430 if (check_cb(dev)) {
431 /* This flag is only checked if the return value is success. */
432 port_obj_info->handled = true;
465 return add_cb(dev, port_obj_info->obj, port_obj_info->trans,
466 extack);
433 return add_cb(dev, port_obj_info->obj, extack);
467 }
468
469 /* Switch ports might be stacked under e.g. a LAG. Ignore the
470 * unsupported devices, another driver might be able to handle them. But
471 * propagate to the callers any hard errors.
472 *
473 * If the driver does its own bookkeeping of stacked ports, it's not
474 * necessary to go through this helper.

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

486 return err;
487}
488
489int switchdev_handle_port_obj_add(struct net_device *dev,
490 struct switchdev_notifier_port_obj_info *port_obj_info,
491 bool (*check_cb)(const struct net_device *dev),
492 int (*add_cb)(struct net_device *dev,
493 const struct switchdev_obj *obj,
434 }
435
436 /* Switch ports might be stacked under e.g. a LAG. Ignore the
437 * unsupported devices, another driver might be able to handle them. But
438 * propagate to the callers any hard errors.
439 *
440 * If the driver does its own bookkeeping of stacked ports, it's not
441 * necessary to go through this helper.

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

453 return err;
454}
455
456int switchdev_handle_port_obj_add(struct net_device *dev,
457 struct switchdev_notifier_port_obj_info *port_obj_info,
458 bool (*check_cb)(const struct net_device *dev),
459 int (*add_cb)(struct net_device *dev,
460 const struct switchdev_obj *obj,
494 struct switchdev_trans *trans,
495 struct netlink_ext_ack *extack))
496{
497 int err;
498
499 err = __switchdev_handle_port_obj_add(dev, port_obj_info, check_cb,
500 add_cb);
501 if (err == -EOPNOTSUPP)
502 err = 0;

--- 109 unchanged lines hidden ---
461 struct netlink_ext_ack *extack))
462{
463 int err;
464
465 err = __switchdev_handle_port_obj_add(dev, port_obj_info, check_cb,
466 add_cb);
467 if (err == -EOPNOTSUPP)
468 err = 0;

--- 109 unchanged lines hidden ---