Commit 3f9bb030 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Jakub Kicinski
Browse files

net: dsa: make dp->bridge_num one-based



I have seen too many bugs already due to the fact that we must encode an
invalid dp->bridge_num as a negative value, because the natural tendency
is to check that invalid value using (!dp->bridge_num). Latest example
can be seen in commit 1bec0f05 ("net: dsa: fix bridge_num not
getting cleared after ports leaving the bridge").

Convert the existing users to assume that dp->bridge_num == 0 is the
encoding for invalid, and valid bridge numbers start from 1.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarAlvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 1fe5b012
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -1250,10 +1250,10 @@ static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port)
	/* dev is a virtual bridge */
	} else {
		list_for_each_entry(dp, &dst->ports, list) {
			if (dp->bridge_num < 0)
			if (!dp->bridge_num)
				continue;

			if (dp->bridge_num + 1 + dst->last_switch != dev)
			if (dp->bridge_num + dst->last_switch != dev)
				continue;

			br = dp->bridge_dev;
@@ -2527,9 +2527,9 @@ static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
 * physical switches, so start from beyond that range.
 */
static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
					       int bridge_num)
					       unsigned int bridge_num)
{
	u8 dev = bridge_num + ds->dst->last_switch + 1;
	u8 dev = bridge_num + ds->dst->last_switch;
	struct mv88e6xxx_chip *chip = ds->priv;
	int err;

@@ -2542,14 +2542,14 @@ static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,

static int mv88e6xxx_bridge_tx_fwd_offload(struct dsa_switch *ds, int port,
					   struct net_device *br,
					   int bridge_num)
					   unsigned int bridge_num)
{
	return mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num);
}

static void mv88e6xxx_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
					      struct net_device *br,
					      int bridge_num)
					      unsigned int bridge_num)
{
	int err;

+3 −3
Original line number Diff line number Diff line
@@ -38,13 +38,13 @@ void dsa_8021q_rcv(struct sk_buff *skb, int *source_port, int *switch_id);

int dsa_tag_8021q_bridge_tx_fwd_offload(struct dsa_switch *ds, int port,
					struct net_device *br,
					int bridge_num);
					unsigned int bridge_num);

void dsa_tag_8021q_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
					   struct net_device *br,
					   int bridge_num);
					   unsigned int bridge_num);

u16 dsa_8021q_bridge_tx_fwd_offload_vid(int bridge_num);
u16 dsa_8021q_bridge_tx_fwd_offload_vid(unsigned int bridge_num);

u16 dsa_tag_8021q_tx_vid(const struct dsa_port *dp);

+3 −3
Original line number Diff line number Diff line
@@ -257,7 +257,7 @@ struct dsa_port {
	bool			learning;
	u8			stp_state;
	struct net_device	*bridge_dev;
	int			bridge_num;
	unsigned int		bridge_num;
	struct devlink_port	devlink_port;
	bool			devlink_port_setup;
	struct phylink		*pl;
@@ -754,11 +754,11 @@ struct dsa_switch_ops {
	/* Called right after .port_bridge_join() */
	int	(*port_bridge_tx_fwd_offload)(struct dsa_switch *ds, int port,
					      struct net_device *bridge,
					      int bridge_num);
					      unsigned int bridge_num);
	/* Called right before .port_bridge_leave() */
	void	(*port_bridge_tx_fwd_unoffload)(struct dsa_switch *ds, int port,
						struct net_device *bridge,
						int bridge_num);
						unsigned int bridge_num);
	void	(*port_stp_state_set)(struct dsa_switch *ds, int port,
				      u8 state);
	void	(*port_fast_age)(struct dsa_switch *ds, int port);
+12 −12
Original line number Diff line number Diff line
@@ -141,23 +141,23 @@ static int dsa_bridge_num_find(const struct net_device *bridge_dev)
	 */
	list_for_each_entry(dst, &dsa_tree_list, list)
		list_for_each_entry(dp, &dst->ports, list)
			if (dp->bridge_dev == bridge_dev &&
			    dp->bridge_num != -1)
			if (dp->bridge_dev == bridge_dev && dp->bridge_num)
				return dp->bridge_num;

	return -1;
	return 0;
}

int dsa_bridge_num_get(const struct net_device *bridge_dev, int max)
unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max)
{
	int bridge_num = dsa_bridge_num_find(bridge_dev);
	unsigned int bridge_num = dsa_bridge_num_find(bridge_dev);

	if (bridge_num < 0) {
	if (!bridge_num) {
		/* First port that offloads TX forwarding for this bridge */
		bridge_num = find_first_zero_bit(&dsa_fwd_offloading_bridges,
						 DSA_MAX_NUM_OFFLOADING_BRIDGES);
		bridge_num = find_next_zero_bit(&dsa_fwd_offloading_bridges,
						DSA_MAX_NUM_OFFLOADING_BRIDGES,
						1);
		if (bridge_num >= max)
			return -1;
			return 0;

		set_bit(bridge_num, &dsa_fwd_offloading_bridges);
	}
@@ -165,12 +165,13 @@ int dsa_bridge_num_get(const struct net_device *bridge_dev, int max)
	return bridge_num;
}

void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num)
void dsa_bridge_num_put(const struct net_device *bridge_dev,
			unsigned int bridge_num)
{
	/* Check if the bridge is still in use, otherwise it is time
	 * to clean it up so we can reuse this bridge_num later.
	 */
	if (dsa_bridge_num_find(bridge_dev) < 0)
	if (!dsa_bridge_num_find(bridge_dev))
		clear_bit(bridge_num, &dsa_fwd_offloading_bridges);
}

@@ -1184,7 +1185,6 @@ static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)

	dp->ds = ds;
	dp->index = index;
	dp->bridge_num = -1;

	INIT_LIST_HEAD(&dp->list);
	list_add_tail(&dp->list, &dst->ports);
+3 −2
Original line number Diff line number Diff line
@@ -546,8 +546,9 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
			      struct net_device *master,
			      const struct dsa_device_ops *tag_ops,
			      const struct dsa_device_ops *old_tag_ops);
int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num);
unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
void dsa_bridge_num_put(const struct net_device *bridge_dev,
			unsigned int bridge_num);

/* tag_8021q.c */
int dsa_tag_8021q_bridge_join(struct dsa_switch *ds,
Loading