lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20151023192824.GA21943@ketchup.mtl.sfl>
Date:	Fri, 23 Oct 2015 15:28:24 -0400
From:	Vivien Didelot <vivien.didelot@...oirfairelinux.com>
To:	Florian Fainelli <f.fainelli@...il.com>
Cc:	netdev@...r.kernel.org, davem@...emloft.net, jiri@...nulli.us,
	andrew@...n.ch, linux@...ck-us.net
Subject: Re: [PATCH net-next] net: dsa: bcm_sf2: Implement FDB operations

On Oct. Friday 23 (43) 11:38 AM, Florian Fainelli wrote:
> Add support for the FDB add, delete, and dump operations. The add and
> delete operations are implemented using directed ARL operations using
> the specified MAC address and consist in a read operation, write and
> readback operation.
> 
> The dump operation consists in using the ARL search and software
> filtering entries which are not for the desired port.
> 
> Signed-off-by: Florian Fainelli <f.fainelli@...il.com>
> ---
>  drivers/net/dsa/bcm_sf2.c      | 236 +++++++++++++++++++++++++++++++++++++++++
>  drivers/net/dsa/bcm_sf2.h      |  56 ++++++++++
>  drivers/net/dsa/bcm_sf2_regs.h |  43 ++++++++
>  3 files changed, 335 insertions(+)
> 
> diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
> index 9d56515f4c4d..4f32b8a530bf 100644
> --- a/drivers/net/dsa/bcm_sf2.c
> +++ b/drivers/net/dsa/bcm_sf2.c
> @@ -25,6 +25,8 @@
>  #include <linux/ethtool.h>
>  #include <linux/if_bridge.h>
>  #include <linux/brcmphy.h>
> +#include <linux/etherdevice.h>
> +#include <net/switchdev.h>
>  
>  #include "bcm_sf2.h"
>  #include "bcm_sf2_regs.h"
> @@ -555,6 +557,236 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
>  	return 0;
>  }
>  
> +/* Address Resolution Logic routines */
> +static int bcm_sf2_arl_op_wait(struct bcm_sf2_priv *priv)
> +{
> +	unsigned int timeout = 10;
> +	u32 reg;
> +
> +	do {
> +		reg = core_readl(priv, CORE_ARLA_RWCTL);
> +		if (!(reg & ARL_STRTDN))
> +			return 0;
> +
> +		usleep_range(1000, 2000);
> +	} while (timeout--);
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int bcm_sf2_arl_rw_op(struct bcm_sf2_priv *priv, unsigned int op)
> +{
> +	u32 cmd;
> +
> +	if (op > ARL_RW)
> +		return -EINVAL;
> +
> +	cmd = core_readl(priv, CORE_ARLA_RWCTL);
> +	cmd &= ~IVL_SVL_SELECT;
> +	cmd |= ARL_STRTDN;
> +	if (op)
> +		cmd |= ARL_RW;
> +	else
> +		cmd &= ~ARL_RW;
> +	core_writel(priv, cmd, CORE_ARLA_RWCTL);
> +
> +	return bcm_sf2_arl_op_wait(priv);
> +}
> +
> +static int bcm_sf2_arl_read(struct bcm_sf2_priv *priv, u64 mac,
> +			    u16 vid, struct bcm_sf2_arl_entry *ent, u8 *idx,
> +			    bool is_valid)
> +{
> +	unsigned int i;
> +	int ret;
> +
> +	ret = bcm_sf2_arl_op_wait(priv);
> +	if (ret)
> +		return ret;
> +
> +	/* Read the 4 bins */
> +	for (i = 0; i < 4; i++) {
> +		u64 mac_vid;
> +		u32 fwd_entry;
> +
> +		mac_vid = core_readq(priv, CORE_ARLA_MACVID_ENTRY(i));
> +		fwd_entry = core_readl(priv, CORE_ARLA_FWD_ENTRY(i));
> +		bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry);
> +
> +		if (ent->is_valid && is_valid) {
> +			*idx = i;
> +			return 0;
> +		}
> +
> +		/* This is the MAC we just deleted */
> +		if (!is_valid && (mac_vid & mac))
> +			return 0;
> +	}
> +
> +	return -ENOENT;
> +}

What is the purpose of the "vid" parameter in bcm_sf2_arl_read?

> +
> +static int bcm_sf2_arl_op(struct bcm_sf2_priv *priv, int op, int port,
> +			  const unsigned char *addr, u16 vid, bool is_valid)
> +{
> +	struct bcm_sf2_arl_entry ent;
> +	u32 fwd_entry;
> +	u64 mac, mac_vid = 0;
> +	u8 idx = 0;
> +	int ret;
> +
> +	/* Convert the array into a 64-bit MAC */
> +	mac = bcm_sf2_mac_to_u64(addr);
> +
> +	/* Perform a read for the given MAC and VID */
> +	core_writeq(priv, mac, CORE_ARLA_MAC);
> +	core_writel(priv, vid, CORE_ARLA_VID);
> +
> +	/* Issue a read operation for this MAC */
> +	ret = bcm_sf2_arl_rw_op(priv, 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
> +	/* If this is a read, just finish now */
> +	if (op)
> +		return ret;
> +
> +	/* We could not find a matching MAC, so reset to a new entry */
> +	if (ret) {
> +		fwd_entry = 0;
> +		idx = 0;
> +	}
> +
> +	memset(&ent, 0, sizeof(ent));
> +	ent.port = port;
> +	ent.is_valid = is_valid;
> +	ent.vid = vid;
> +	ent.is_static = true;
> +	memcpy(ent.mac, addr, ETH_ALEN);
> +	bcm_sf2_arl_from_entry(&mac_vid, &fwd_entry, &ent);
> +
> +	core_writeq(priv, mac_vid, CORE_ARLA_MACVID_ENTRY(idx));
> +	core_writel(priv, fwd_entry, CORE_ARLA_FWD_ENTRY(idx));
> +
> +	ret = bcm_sf2_arl_rw_op(priv, 0);
> +	if (ret)
> +		return ret;
> +
> +	/* Re-read the entry to check */
> +	return bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
> +}
> +
> +static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port,
> +				  const struct switchdev_obj_port_fdb *fdb,
> +				  struct switchdev_trans *trans)
> +{
> +	/* We do not need to do anything specific here yet */
> +	return 0;
> +}
> +
> +static int bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port,
> +			      const struct switchdev_obj_port_fdb *fdb,
> +			      struct switchdev_trans *trans)
> +{
> +	struct bcm_sf2_priv *priv = ds_to_priv(ds);
> +
> +	return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, true);
> +}
> +
> +static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, int port,
> +			      const struct switchdev_obj_port_fdb *fdb)
> +{
> +	struct bcm_sf2_priv *priv = ds_to_priv(ds);
> +
> +	return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, false);
> +}

I'm wondering if you are populating the FDB of the invalid VLAN 0 here.

Does your ARL consider that fdb->vid == 0 means "this port's FDB" and
not "FDB of VLAN 0"?

> +
> +static int bcm_sf2_arl_search_wait(struct bcm_sf2_priv *priv)
> +{
> +	unsigned timeout = 1000;
> +	u32 reg;
> +
> +	do {
> +		reg = core_readl(priv, CORE_ARLA_SRCH_CTL);
> +		if (!(reg & ARLA_SRCH_STDN))
> +			return 0;
> +
> +		if (reg & ARLA_SRCH_VLID)
> +			return 0;
> +
> +		usleep_range(1000, 2000);
> +	} while (timeout--);
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static void bcm_sf2_arl_search_rd(struct bcm_sf2_priv *priv, u8 idx,
> +				  struct bcm_sf2_arl_entry *ent)
> +{
> +	u64 mac_vid;
> +	u32 fwd_entry;
> +
> +	mac_vid = core_readq(priv, CORE_ARLA_SRCH_RSLT_MACVID(idx));
> +	fwd_entry = core_readl(priv, CORE_ARLA_SRCH_RSLT(idx));
> +	bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry);
> +}
> +
> +static int bcm_sf2_sw_fdb_copy(struct net_device *dev, int port,
> +			       const struct bcm_sf2_arl_entry *ent,
> +			       struct switchdev_obj_port_fdb *fdb,
> +			       int (*cb)(struct switchdev_obj *obj))
> +{
> +	if (!ent->is_valid)
> +		return 0;
> +
> +	if (port != ent->port)
> +		return 0;
> +
> +	ether_addr_copy(fdb->addr, ent->mac);
> +	fdb->vid = ent->vid;
> +	fdb->ndm_state = ent->is_static ? NUD_NOARP : NUD_REACHABLE;
> +
> +	return cb(&fdb->obj);
> +}
> +
> +static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
> +			       struct switchdev_obj_port_fdb *fdb,
> +			       int (*cb)(struct switchdev_obj *obj))
> +{
> +	struct bcm_sf2_priv *priv = ds_to_priv(ds);
> +	struct net_device *dev = ds->ports[port];
> +	struct bcm_sf2_arl_entry results[2];
> +	unsigned int count = 0;
> +	int ret;
> +
> +	/* Start search operation */
> +	core_writel(priv, ARLA_SRCH_STDN, CORE_ARLA_SRCH_CTL);
> +
> +	do {
> +		ret = bcm_sf2_arl_search_wait(priv);
> +		if (ret)
> +			return ret;
> +
> +		/* Read both entries, then return their values back */
> +		bcm_sf2_arl_search_rd(priv, 0, &results[0]);
> +		ret = bcm_sf2_sw_fdb_copy(dev, port, &results[0], fdb, cb);
> +		if (ret)
> +			return ret;
> +
> +		bcm_sf2_arl_search_rd(priv, 1, &results[1]);
> +		ret = bcm_sf2_sw_fdb_copy(dev, port, &results[1], fdb, cb);
> +		if (ret)
> +			return ret;
> +
> +		if (!results[0].is_valid && !results[1].is_valid)
> +			break;
> +
> +	} while (count++ < CORE_ARLA_NUM_ENTRIES);
> +
> +	return 0;
> +}
> +
>  static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
>  {
>  	struct bcm_sf2_priv *priv = dev_id;
> @@ -1076,6 +1308,10 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
>  	.port_join_bridge	= bcm_sf2_sw_br_join,
>  	.port_leave_bridge	= bcm_sf2_sw_br_leave,
>  	.port_stp_update	= bcm_sf2_sw_br_set_stp_state,
> +	.port_fdb_prepare	= bcm_sf2_sw_fdb_prepare,
> +	.port_fdb_add		= bcm_sf2_sw_fdb_add,
> +	.port_fdb_del		= bcm_sf2_sw_fdb_del,
> +	.port_fdb_dump		= bcm_sf2_sw_fdb_dump,
>  };
>  
>  static int __init bcm_sf2_init(void)
> diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
> index 789d7b7737da..cc98abc0aaf3 100644
> --- a/drivers/net/dsa/bcm_sf2.h
> +++ b/drivers/net/dsa/bcm_sf2.h
> @@ -19,6 +19,8 @@
>  #include <linux/mutex.h>
>  #include <linux/mii.h>
>  #include <linux/ethtool.h>
> +#include <linux/types.h>
> +#include <linux/bitops.h>
>  
>  #include <net/dsa.h>
>  
> @@ -50,6 +52,60 @@ struct bcm_sf2_port_status {
>  	u32 vlan_ctl_mask;
>  };
>  
> +struct bcm_sf2_arl_entry {
> +	u8 port;
> +	u8 mac[ETH_ALEN];
> +	u16 vid;
> +	u8 is_valid:1;
> +	u8 is_age:1;
> +	u8 is_static:1;
> +};
> +
> +static inline void bcm_sf2_mac_from_u64(u64 src, u8 *dst)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		dst[ETH_ALEN - 1 - i] = (src >> (8 * i)) & 0xff;
> +}
> +
> +static inline u64 bcm_sf2_mac_to_u64(const u8 *src)
> +{
> +	unsigned int i;
> +	u64 dst = 0;
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		dst |= (u64)src[ETH_ALEN - 1 - i] << (8 * i);
> +
> +	return dst;
> +}
> +
> +static inline void bcm_sf2_arl_to_entry(struct bcm_sf2_arl_entry *ent,
> +					u64 mac_vid, u32 fwd_entry)
> +{
> +	memset(ent, 0, sizeof(*ent));
> +	ent->port = fwd_entry & PORTID_MASK;
> +	ent->is_valid = !!(fwd_entry & ARL_VALID);
> +	ent->is_age = !!(fwd_entry & ARL_AGE);
> +	ent->is_static = !!(fwd_entry & ARL_STATIC);
> +	bcm_sf2_mac_from_u64(mac_vid, ent->mac);
> +	ent->vid = mac_vid >> VID_SHIFT;
> +}
> +
> +static inline void bcm_sf2_arl_from_entry(u64 *mac_vid, u32 *fwd_entry,
> +					  const struct bcm_sf2_arl_entry *ent)
> +{
> +	*mac_vid = bcm_sf2_mac_to_u64(ent->mac);
> +	*mac_vid |= (u64)(ent->vid & VID_MASK) << VID_SHIFT;
> +	*fwd_entry = ent->port & PORTID_MASK;
> +	if (ent->is_valid)
> +		*fwd_entry |= ARL_VALID;
> +	if (ent->is_static)
> +		*fwd_entry |= ARL_STATIC;
> +	if (ent->is_age)
> +		*fwd_entry |= ARL_AGE;
> +}
> +
>  struct bcm_sf2_priv {
>  	/* Base registers, keep those in order with BCM_SF2_REGS_NAME */
>  	void __iomem			*core;
> diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
> index fa4e6e78c9ea..97780d43b5c0 100644
> --- a/drivers/net/dsa/bcm_sf2_regs.h
> +++ b/drivers/net/dsa/bcm_sf2_regs.h
> @@ -231,6 +231,49 @@
>  #define CORE_BRCM_HDR_RX_DIS		0x0980
>  #define CORE_BRCM_HDR_TX_DIS		0x0988
>  
> +#define CORE_ARLA_NUM_ENTRIES		1024
> +
> +#define CORE_ARLA_RWCTL			0x1400
> +#define  ARL_RW				(1 << 0)
> +#define  IVL_SVL_SELECT			(1 << 6)
> +#define  ARL_STRTDN			(1 << 7)
> +
> +#define CORE_ARLA_MAC			0x1408
> +#define CORE_ARLA_VID			0x1420
> +#define  ARLA_VIDTAB_INDX_MASK		0x1fff
> +
> +#define CORE_ARLA_MACVID0		0x1440
> +#define  MAC_MASK			0xffffffffff
> +#define  VID_SHIFT			48
> +#define  VID_MASK			0xfff
> +
> +#define CORE_ARLA_FWD_ENTRY0		0x1460
> +#define  PORTID_MASK			0x1ff
> +#define  ARL_CON_SHIFT			9
> +#define  ARL_CON_MASK			0x3
> +#define  ARL_PRI_SHIFT			11
> +#define  ARL_PRI_MASK			0x7
> +#define  ARL_AGE			(1 << 14)
> +#define  ARL_STATIC			(1 << 15)
> +#define  ARL_VALID			(1 << 16)
> +
> +#define CORE_ARLA_MACVID_ENTRY(x)	(CORE_ARLA_MACVID0 + ((x) * 0x40))
> +#define CORE_ARLA_FWD_ENTRY(x)		(CORE_ARLA_FWD_ENTRY0 + ((x) * 0x40))
> +
> +#define CORE_ARLA_SRCH_CTL		0x1540
> +#define  ARLA_SRCH_VLID			(1 << 0)
> +#define  IVL_SVL_SELECT			(1 << 6)
> +#define  ARLA_SRCH_STDN			(1 << 7)
> +
> +#define CORE_ARLA_SRCH_ADR		0x1544
> +#define  ARLA_SRCH_ADR_VALID		(1 << 15)
> +
> +#define CORE_ARLA_SRCH_RSLT_0_MACVID	0x1580
> +#define CORE_ARLA_SRCH_RSLT_0		0x15a0
> +
> +#define CORE_ARLA_SRCH_RSLT_MACVID(x)	(CORE_ARLA_SRCH_RSLT_0_MACVID + ((x) * 0x40))
> +#define CORE_ARLA_SRCH_RSLT(x)		(CORE_ARLA_SRCH_RSLT_0 + ((x) * 0x40))
> +
>  #define CORE_MEM_PSM_VDD_CTRL		0x2380
>  #define  P_TXQ_PSM_VDD_SHIFT		2
>  #define  P_TXQ_PSM_VDD_MASK		0x3
> -- 
> 2.1.0
> 
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ