linux/net/switchdev/switchdev.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * net/switchdev/switchdev.c - Switch device API
 * Copyright (c) 2014-2015 Jiri Pirko <[email protected]>
 * Copyright (c) 2014-2015 Scott Feldman <[email protected]>
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/if_vlan.h>
#include <linux/rtnetlink.h>
#include <net/switchdev.h>

static bool switchdev_obj_eq(const struct switchdev_obj *a,
			     const struct switchdev_obj *b)
{}

static LIST_HEAD(deferred);
static DEFINE_SPINLOCK(deferred_lock);

switchdev_deferred_func_t;

struct switchdev_deferred_item {};

static struct switchdev_deferred_item *switchdev_deferred_dequeue(void)
{}

/**
 *	switchdev_deferred_process - Process ops in deferred queue
 *
 *	Called to flush the ops currently queued in deferred ops queue.
 *	rtnl_lock must be held.
 */
void switchdev_deferred_process(void)
{}
EXPORT_SYMBOL_GPL();

static void switchdev_deferred_process_work(struct work_struct *work)
{}

static DECLARE_WORK(deferred_process_work, switchdev_deferred_process_work);

static int switchdev_deferred_enqueue(struct net_device *dev,
				      const void *data, size_t data_len,
				      switchdev_deferred_func_t *func)
{}

static int switchdev_port_attr_notify(enum switchdev_notifier_type nt,
				      struct net_device *dev,
				      const struct switchdev_attr *attr,
				      struct netlink_ext_ack *extack)
{}

static int switchdev_port_attr_set_now(struct net_device *dev,
				       const struct switchdev_attr *attr,
				       struct netlink_ext_ack *extack)
{}

static void switchdev_port_attr_set_deferred(struct net_device *dev,
					     const void *data)
{}

static int switchdev_port_attr_set_defer(struct net_device *dev,
					 const struct switchdev_attr *attr)
{}

/**
 *	switchdev_port_attr_set - Set port attribute
 *
 *	@dev: port device
 *	@attr: attribute to set
 *	@extack: netlink extended ack, for error message propagation
 *
 *	rtnl_lock must be held and must not be in atomic section,
 *	in case SWITCHDEV_F_DEFER flag is not set.
 */
int switchdev_port_attr_set(struct net_device *dev,
			    const struct switchdev_attr *attr,
			    struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();

static size_t switchdev_obj_size(const struct switchdev_obj *obj)
{}

static int switchdev_port_obj_notify(enum switchdev_notifier_type nt,
				     struct net_device *dev,
				     const struct switchdev_obj *obj,
				     struct netlink_ext_ack *extack)
{}

static void switchdev_obj_id_to_helpful_msg(struct net_device *dev,
					    enum switchdev_obj_id obj_id,
					    int err, bool add)
{}

static void switchdev_port_obj_add_deferred(struct net_device *dev,
					    const void *data)
{}

static int switchdev_port_obj_add_defer(struct net_device *dev,
					const struct switchdev_obj *obj)
{}

/**
 *	switchdev_port_obj_add - Add port object
 *
 *	@dev: port device
 *	@obj: object to add
 *	@extack: netlink extended ack
 *
 *	rtnl_lock must be held and must not be in atomic section,
 *	in case SWITCHDEV_F_DEFER flag is not set.
 */
int switchdev_port_obj_add(struct net_device *dev,
			   const struct switchdev_obj *obj,
			   struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();

static int switchdev_port_obj_del_now(struct net_device *dev,
				      const struct switchdev_obj *obj)
{}

static void switchdev_port_obj_del_deferred(struct net_device *dev,
					    const void *data)
{}

static int switchdev_port_obj_del_defer(struct net_device *dev,
					const struct switchdev_obj *obj)
{}

/**
 *	switchdev_port_obj_del - Delete port object
 *
 *	@dev: port device
 *	@obj: object to delete
 *
 *	rtnl_lock must be held and must not be in atomic section,
 *	in case SWITCHDEV_F_DEFER flag is not set.
 */
int switchdev_port_obj_del(struct net_device *dev,
			   const struct switchdev_obj *obj)
{}
EXPORT_SYMBOL_GPL();

/**
 *	switchdev_port_obj_act_is_deferred - Is object action pending?
 *
 *	@dev: port device
 *	@nt: type of action; add or delete
 *	@obj: object to test
 *
 *	Returns true if a deferred item is pending, which is
 *	equivalent to the action @nt on an object @obj.
 *
 *	rtnl_lock must be held.
 */
bool switchdev_port_obj_act_is_deferred(struct net_device *dev,
					enum switchdev_notifier_type nt,
					const struct switchdev_obj *obj)
{}
EXPORT_SYMBOL_GPL();

static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain);
static BLOCKING_NOTIFIER_HEAD(switchdev_blocking_notif_chain);

/**
 *	register_switchdev_notifier - Register notifier
 *	@nb: notifier_block
 *
 *	Register switch device notifier.
 */
int register_switchdev_notifier(struct notifier_block *nb)
{}
EXPORT_SYMBOL_GPL();

/**
 *	unregister_switchdev_notifier - Unregister notifier
 *	@nb: notifier_block
 *
 *	Unregister switch device notifier.
 */
int unregister_switchdev_notifier(struct notifier_block *nb)
{}
EXPORT_SYMBOL_GPL();

/**
 *	call_switchdev_notifiers - Call notifiers
 *	@val: value passed unmodified to notifier function
 *	@dev: port device
 *	@info: notifier information data
 *	@extack: netlink extended ack
 *	Call all network notifier blocks.
 */
int call_switchdev_notifiers(unsigned long val, struct net_device *dev,
			     struct switchdev_notifier_info *info,
			     struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();

int register_switchdev_blocking_notifier(struct notifier_block *nb)
{}
EXPORT_SYMBOL_GPL();

int unregister_switchdev_blocking_notifier(struct notifier_block *nb)
{}
EXPORT_SYMBOL_GPL();

int call_switchdev_blocking_notifiers(unsigned long val, struct net_device *dev,
				      struct switchdev_notifier_info *info,
				      struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();

struct switchdev_nested_priv {};

static int switchdev_lower_dev_walk(struct net_device *lower_dev,
				    struct netdev_nested_priv *priv)
{}

static struct net_device *
switchdev_lower_dev_find_rcu(struct net_device *dev,
			     bool (*check_cb)(const struct net_device *dev),
			     bool (*foreign_dev_check_cb)(const struct net_device *dev,
							  const struct net_device *foreign_dev))
{}

static struct net_device *
switchdev_lower_dev_find(struct net_device *dev,
			 bool (*check_cb)(const struct net_device *dev),
			 bool (*foreign_dev_check_cb)(const struct net_device *dev,
						      const struct net_device *foreign_dev))
{}

static int __switchdev_handle_fdb_event_to_device(struct net_device *dev,
		struct net_device *orig_dev, unsigned long event,
		const struct switchdev_notifier_fdb_info *fdb_info,
		bool (*check_cb)(const struct net_device *dev),
		bool (*foreign_dev_check_cb)(const struct net_device *dev,
					     const struct net_device *foreign_dev),
		int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev,
			      unsigned long event, const void *ctx,
			      const struct switchdev_notifier_fdb_info *fdb_info))
{}

int switchdev_handle_fdb_event_to_device(struct net_device *dev, unsigned long event,
		const struct switchdev_notifier_fdb_info *fdb_info,
		bool (*check_cb)(const struct net_device *dev),
		bool (*foreign_dev_check_cb)(const struct net_device *dev,
					     const struct net_device *foreign_dev),
		int (*mod_cb)(struct net_device *dev, struct net_device *orig_dev,
			      unsigned long event, const void *ctx,
			      const struct switchdev_notifier_fdb_info *fdb_info))
{}
EXPORT_SYMBOL_GPL();

static int __switchdev_handle_port_obj_add(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,
			bool (*check_cb)(const struct net_device *dev),
			bool (*foreign_dev_check_cb)(const struct net_device *dev,
						     const struct net_device *foreign_dev),
			int (*add_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_obj *obj,
				      struct netlink_ext_ack *extack))
{}

/* Pass through a port object addition, if @dev passes @check_cb, or replicate
 * it towards all lower interfaces of @dev that pass @check_cb, if @dev is a
 * bridge or a LAG.
 */
int switchdev_handle_port_obj_add(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,
			bool (*check_cb)(const struct net_device *dev),
			int (*add_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_obj *obj,
				      struct netlink_ext_ack *extack))
{}
EXPORT_SYMBOL_GPL();

/* Same as switchdev_handle_port_obj_add(), except if object is notified on a
 * @dev that passes @foreign_dev_check_cb, it is replicated towards all devices
 * that pass @check_cb and are in the same bridge as @dev.
 */
int switchdev_handle_port_obj_add_foreign(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,
			bool (*check_cb)(const struct net_device *dev),
			bool (*foreign_dev_check_cb)(const struct net_device *dev,
						     const struct net_device *foreign_dev),
			int (*add_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_obj *obj,
				      struct netlink_ext_ack *extack))
{}
EXPORT_SYMBOL_GPL();

static int __switchdev_handle_port_obj_del(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,
			bool (*check_cb)(const struct net_device *dev),
			bool (*foreign_dev_check_cb)(const struct net_device *dev,
						     const struct net_device *foreign_dev),
			int (*del_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_obj *obj))
{}

/* Pass through a port object deletion, if @dev passes @check_cb, or replicate
 * it towards all lower interfaces of @dev that pass @check_cb, if @dev is a
 * bridge or a LAG.
 */
int switchdev_handle_port_obj_del(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,
			bool (*check_cb)(const struct net_device *dev),
			int (*del_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_obj *obj))
{}
EXPORT_SYMBOL_GPL();

/* Same as switchdev_handle_port_obj_del(), except if object is notified on a
 * @dev that passes @foreign_dev_check_cb, it is replicated towards all devices
 * that pass @check_cb and are in the same bridge as @dev.
 */
int switchdev_handle_port_obj_del_foreign(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,
			bool (*check_cb)(const struct net_device *dev),
			bool (*foreign_dev_check_cb)(const struct net_device *dev,
						     const struct net_device *foreign_dev),
			int (*del_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_obj *obj))
{}
EXPORT_SYMBOL_GPL();

static int __switchdev_handle_port_attr_set(struct net_device *dev,
			struct switchdev_notifier_port_attr_info *port_attr_info,
			bool (*check_cb)(const struct net_device *dev),
			int (*set_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_attr *attr,
				      struct netlink_ext_ack *extack))
{}

int switchdev_handle_port_attr_set(struct net_device *dev,
			struct switchdev_notifier_port_attr_info *port_attr_info,
			bool (*check_cb)(const struct net_device *dev),
			int (*set_cb)(struct net_device *dev, const void *ctx,
				      const struct switchdev_attr *attr,
				      struct netlink_ext_ack *extack))
{}
EXPORT_SYMBOL_GPL();

int switchdev_bridge_port_offload(struct net_device *brport_dev,
				  struct net_device *dev, const void *ctx,
				  struct notifier_block *atomic_nb,
				  struct notifier_block *blocking_nb,
				  bool tx_fwd_offload,
				  struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();

void switchdev_bridge_port_unoffload(struct net_device *brport_dev,
				     const void *ctx,
				     struct notifier_block *atomic_nb,
				     struct notifier_block *blocking_nb)
{}
EXPORT_SYMBOL_GPL();

int switchdev_bridge_port_replay(struct net_device *brport_dev,
				 struct net_device *dev, const void *ctx,
				 struct notifier_block *atomic_nb,
				 struct notifier_block *blocking_nb,
				 struct netlink_ext_ack *extack)
{}
EXPORT_SYMBOL_GPL();