Commit 716a30a9 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

net: switchdev: merge switchdev_handle_fdb_{add,del}_to_device



To reduce code churn, the same patch makes multiple changes, since they
all touch the same lines:

1. The implementations for these two are identical, just with different
   function pointers. Reduce duplications and name the function pointers
   "mod_cb" instead of "add_cb" and "del_cb". Pass the event as argument.

2. Drop the "const" attribute from "orig_dev". If the driver needs to
   check whether orig_dev belongs to itself and then
   call_switchdev_notifiers(orig_dev, SWITCHDEV_FDB_OFFLOADED), it
   can't, because call_switchdev_notifiers takes a non-const struct
   net_device *.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fab9eca8
Loading
Loading
Loading
Loading
+10 −38
Original line number Diff line number Diff line
@@ -299,28 +299,16 @@ void switchdev_port_fwd_mark_set(struct net_device *dev,
				 struct net_device *group_dev,
				 bool joining);

int switchdev_handle_fdb_add_to_device(struct net_device *dev,
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 (*add_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
		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 (*lag_add_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
				  const struct switchdev_notifier_fdb_info *fdb_info));

int switchdev_handle_fdb_del_to_device(struct net_device *dev,
		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 (*del_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
			      const struct switchdev_notifier_fdb_info *fdb_info),
		int (*lag_del_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
		int (*lag_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_port_obj_add(struct net_device *dev,
@@ -426,32 +414,16 @@ call_switchdev_blocking_notifiers(unsigned long val,
}

static inline int
switchdev_handle_fdb_add_to_device(struct net_device *dev,
		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 (*add_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
			      const struct switchdev_notifier_fdb_info *fdb_info),
		int (*lag_add_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
				  const struct switchdev_notifier_fdb_info *fdb_info))
{
	return 0;
}

static inline int
switchdev_handle_fdb_del_to_device(struct net_device *dev,
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 (*del_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
		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 (*lag_del_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
		int (*lag_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))
{
	return 0;
+8 −33
Original line number Diff line number Diff line
@@ -2468,10 +2468,9 @@ static bool dsa_foreign_dev_check(const struct net_device *dev,
}

static int dsa_slave_fdb_event(struct net_device *dev,
			       const struct net_device *orig_dev,
			       const void *ctx,
			       const struct switchdev_notifier_fdb_info *fdb_info,
			       unsigned long event)
			       struct net_device *orig_dev,
			       unsigned long event, const void *ctx,
			       const struct switchdev_notifier_fdb_info *fdb_info)
{
	struct dsa_switchdev_event_work *switchdev_work;
	struct dsa_port *dp = dsa_slave_to_port(dev);
@@ -2525,24 +2524,6 @@ static int dsa_slave_fdb_event(struct net_device *dev,
	return 0;
}

static int
dsa_slave_fdb_add_to_device(struct net_device *dev,
			    const struct net_device *orig_dev, const void *ctx,
			    const struct switchdev_notifier_fdb_info *fdb_info)
{
	return dsa_slave_fdb_event(dev, orig_dev, ctx, fdb_info,
				   SWITCHDEV_FDB_ADD_TO_DEVICE);
}

static int
dsa_slave_fdb_del_to_device(struct net_device *dev,
			    const struct net_device *orig_dev, const void *ctx,
			    const struct switchdev_notifier_fdb_info *fdb_info)
{
	return dsa_slave_fdb_event(dev, orig_dev, ctx, fdb_info,
				   SWITCHDEV_FDB_DEL_TO_DEVICE);
}

/* Called under rcu_read_lock() */
static int dsa_slave_switchdev_event(struct notifier_block *unused,
				     unsigned long event, void *ptr)
@@ -2557,17 +2538,11 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
						     dsa_slave_port_attr_set);
		return notifier_from_errno(err);
	case SWITCHDEV_FDB_ADD_TO_DEVICE:
		err = switchdev_handle_fdb_add_to_device(dev, ptr,
							 dsa_slave_dev_check,
							 dsa_foreign_dev_check,
							 dsa_slave_fdb_add_to_device,
							 NULL);
		return notifier_from_errno(err);
	case SWITCHDEV_FDB_DEL_TO_DEVICE:
		err = switchdev_handle_fdb_del_to_device(dev, ptr,
		err = switchdev_handle_fdb_event_to_device(dev, event, ptr,
							   dsa_slave_dev_check,
							   dsa_foreign_dev_check,
							 dsa_slave_fdb_del_to_device,
							   dsa_slave_fdb_event,
							   NULL);
		return notifier_from_errno(err);
	default:
+25 −131
Original line number Diff line number Diff line
@@ -428,17 +428,17 @@ switchdev_lower_dev_find(struct net_device *dev,
	return switchdev_priv.lower_dev;
}

static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
		const struct net_device *orig_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 (*add_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
		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 (*lag_add_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
		int (*lag_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))
{
	const struct switchdev_notifier_info *info = &fdb_info->info;
@@ -447,17 +447,17 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
	int err = -EOPNOTSUPP;

	if (check_cb(dev))
		return add_cb(dev, orig_dev, info->ctx, fdb_info);
		return mod_cb(dev, orig_dev, event, info->ctx, fdb_info);

	if (netif_is_lag_master(dev)) {
		if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb))
			goto maybe_bridged_with_us;

		/* This is a LAG interface that we offload */
		if (!lag_add_cb)
		if (!lag_mod_cb)
			return -EOPNOTSUPP;

		return lag_add_cb(dev, orig_dev, info->ctx, fdb_info);
		return lag_mod_cb(dev, orig_dev, event, info->ctx, fdb_info);
	}

	/* Recurse through lower interfaces in case the FDB entry is pointing
@@ -481,10 +481,10 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
						      foreign_dev_check_cb))
				continue;

			err = __switchdev_handle_fdb_add_to_device(lower_dev, orig_dev,
								   fdb_info, check_cb,
			err = __switchdev_handle_fdb_event_to_device(lower_dev, orig_dev,
								     event, fdb_info, check_cb,
								     foreign_dev_check_cb,
								   add_cb, lag_add_cb);
								     mod_cb, lag_mod_cb);
			if (err && err != -EOPNOTSUPP)
				return err;
		}
@@ -503,140 +503,34 @@ static int __switchdev_handle_fdb_add_to_device(struct net_device *dev,
	if (!switchdev_lower_dev_find(br, check_cb, foreign_dev_check_cb))
		return 0;

	return __switchdev_handle_fdb_add_to_device(br, orig_dev, fdb_info,
	return __switchdev_handle_fdb_event_to_device(br, orig_dev, event, fdb_info,
						      check_cb, foreign_dev_check_cb,
						    add_cb, lag_add_cb);
						      mod_cb, lag_mod_cb);
}

int switchdev_handle_fdb_add_to_device(struct net_device *dev,
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 (*add_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
		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 (*lag_add_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
		int (*lag_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 err;

	err = __switchdev_handle_fdb_add_to_device(dev, dev, fdb_info,
						   check_cb,
						   foreign_dev_check_cb,
						   add_cb, lag_add_cb);
	if (err == -EOPNOTSUPP)
		err = 0;

	return err;
}
EXPORT_SYMBOL_GPL(switchdev_handle_fdb_add_to_device);

static int __switchdev_handle_fdb_del_to_device(struct net_device *dev,
		const struct net_device *orig_dev,
		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 (*del_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
			      const struct switchdev_notifier_fdb_info *fdb_info),
		int (*lag_del_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
				  const struct switchdev_notifier_fdb_info *fdb_info))
{
	const struct switchdev_notifier_info *info = &fdb_info->info;
	struct net_device *br, *lower_dev;
	struct list_head *iter;
	int err = -EOPNOTSUPP;

	if (check_cb(dev))
		return del_cb(dev, orig_dev, info->ctx, fdb_info);

	if (netif_is_lag_master(dev)) {
		if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb))
			goto maybe_bridged_with_us;

		/* This is a LAG interface that we offload */
		if (!lag_del_cb)
			return -EOPNOTSUPP;

		return lag_del_cb(dev, orig_dev, info->ctx, fdb_info);
	}

	/* Recurse through lower interfaces in case the FDB entry is pointing
	 * towards a bridge device.
	 */
	if (netif_is_bridge_master(dev)) {
		if (!switchdev_lower_dev_find(dev, check_cb, foreign_dev_check_cb))
			return 0;

		/* This is a bridge interface that we offload */
		netdev_for_each_lower_dev(dev, lower_dev, iter) {
			/* Do not propagate FDB entries across bridges */
			if (netif_is_bridge_master(lower_dev))
				continue;

			/* Bridge ports might be either us, or LAG interfaces
			 * that we offload.
			 */
			if (!check_cb(lower_dev) &&
			    !switchdev_lower_dev_find(lower_dev, check_cb,
						      foreign_dev_check_cb))
				continue;

			err = __switchdev_handle_fdb_del_to_device(lower_dev, orig_dev,
								   fdb_info, check_cb,
								   foreign_dev_check_cb,
								   del_cb, lag_del_cb);
			if (err && err != -EOPNOTSUPP)
				return err;
		}

		return 0;
	}

maybe_bridged_with_us:
	/* Event is neither on a bridge nor a LAG. Check whether it is on an
	 * interface that is in a bridge with us.
	 */
	br = netdev_master_upper_dev_get_rcu(dev);
	if (!br || !netif_is_bridge_master(br))
		return 0;

	if (!switchdev_lower_dev_find(br, check_cb, foreign_dev_check_cb))
		return 0;

	return __switchdev_handle_fdb_del_to_device(br, orig_dev, fdb_info,
	err = __switchdev_handle_fdb_event_to_device(dev, dev, event, fdb_info,
						     check_cb, foreign_dev_check_cb,
						    del_cb, lag_del_cb);
}

int switchdev_handle_fdb_del_to_device(struct net_device *dev,
		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 (*del_cb)(struct net_device *dev,
			      const struct net_device *orig_dev, const void *ctx,
			      const struct switchdev_notifier_fdb_info *fdb_info),
		int (*lag_del_cb)(struct net_device *dev,
				  const struct net_device *orig_dev, const void *ctx,
				  const struct switchdev_notifier_fdb_info *fdb_info))
{
	int err;

	err = __switchdev_handle_fdb_del_to_device(dev, dev, fdb_info,
						   check_cb,
						   foreign_dev_check_cb,
						   del_cb, lag_del_cb);
						     mod_cb, lag_mod_cb);
	if (err == -EOPNOTSUPP)
		err = 0;

	return err;
}
EXPORT_SYMBOL_GPL(switchdev_handle_fdb_del_to_device);
EXPORT_SYMBOL_GPL(switchdev_handle_fdb_event_to_device);

static int __switchdev_handle_port_obj_add(struct net_device *dev,
			struct switchdev_notifier_port_obj_info *port_obj_info,