Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7bfbe51 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'netdevsync'



Alexander Duyck says:

====================
Provide common means for device address sync

The following series implements a means for synchronizing both unicast and
multicast addresses on a device interface.  The code is based on the original
implementation of dev_uc_sync that was available for syncing a VLAN to the
lower dev.

The original reason for coming up for this patch is a driver that is still in
the early stages of development.  The nearest driver I could find that
appeared to have the same limitations as the driver I was working on was the
Cisco enic driver.  For this reason I chose it as the first driver to make use
of this interface publicly.

However, I do not have a Cisco enic interface so I have only been able to
compile test any changes made to the driver.  I tried to keep this change as
simple as possible to avoid any issues.  Any help with testing would be
greatly appreciated.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3e820811 f009618a
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -114,8 +114,6 @@ struct enic {
	u32 msg_enable;
	u32 msg_enable;
	spinlock_t devcmd_lock;
	spinlock_t devcmd_lock;
	u8 mac_addr[ETH_ALEN];
	u8 mac_addr[ETH_ALEN];
	u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
	u8 uc_addr[ENIC_UNICAST_PERFECT_FILTERS][ETH_ALEN];
	unsigned int flags;
	unsigned int flags;
	unsigned int priv_flags;
	unsigned int priv_flags;
	unsigned int mc_count;
	unsigned int mc_count;
+2 −2
Original line number Original line Diff line number Diff line
@@ -88,7 +88,7 @@ int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
	return err;
	return err;
}
}


int enic_dev_add_addr(struct enic *enic, u8 *addr)
int enic_dev_add_addr(struct enic *enic, const u8 *addr)
{
{
	int err;
	int err;


@@ -99,7 +99,7 @@ int enic_dev_add_addr(struct enic *enic, u8 *addr)
	return err;
	return err;
}
}


int enic_dev_del_addr(struct enic *enic, u8 *addr)
int enic_dev_del_addr(struct enic *enic, const u8 *addr)
{
{
	int err;
	int err;


+2 −2
Original line number Original line Diff line number Diff line
@@ -45,8 +45,8 @@ int enic_dev_add_station_addr(struct enic *enic);
int enic_dev_del_station_addr(struct enic *enic);
int enic_dev_del_station_addr(struct enic *enic);
int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
	int broadcast, int promisc, int allmulti);
	int broadcast, int promisc, int allmulti);
int enic_dev_add_addr(struct enic *enic, u8 *addr);
int enic_dev_add_addr(struct enic *enic, const u8 *addr);
int enic_dev_del_addr(struct enic *enic, u8 *addr);
int enic_dev_del_addr(struct enic *enic, const u8 *addr);
int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
int enic_dev_notify_unset(struct enic *enic);
int enic_dev_notify_unset(struct enic *enic);
+65 −108
Original line number Original line Diff line number Diff line
@@ -616,8 +616,71 @@ static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev,
	return net_stats;
	return net_stats;
}
}


static int enic_mc_sync(struct net_device *netdev, const u8 *mc_addr)
{
	struct enic *enic = netdev_priv(netdev);

	if (enic->mc_count == ENIC_MULTICAST_PERFECT_FILTERS) {
		unsigned int mc_count = netdev_mc_count(netdev);

		netdev_warn(netdev, "Registering only %d out of %d multicast addresses\n",
			    ENIC_MULTICAST_PERFECT_FILTERS, mc_count);

		return -ENOSPC;
	}

	enic_dev_add_addr(enic, mc_addr);
	enic->mc_count++;

	return 0;
}

static int enic_mc_unsync(struct net_device *netdev, const u8 *mc_addr)
{
	struct enic *enic = netdev_priv(netdev);

	enic_dev_del_addr(enic, mc_addr);
	enic->mc_count--;

	return 0;
}

static int enic_uc_sync(struct net_device *netdev, const u8 *uc_addr)
{
	struct enic *enic = netdev_priv(netdev);

	if (enic->uc_count == ENIC_UNICAST_PERFECT_FILTERS) {
		unsigned int uc_count = netdev_uc_count(netdev);

		netdev_warn(netdev, "Registering only %d out of %d unicast addresses\n",
			    ENIC_UNICAST_PERFECT_FILTERS, uc_count);

		return -ENOSPC;
	}

	enic_dev_add_addr(enic, uc_addr);
	enic->uc_count++;

	return 0;
}

static int enic_uc_unsync(struct net_device *netdev, const u8 *uc_addr)
{
	struct enic *enic = netdev_priv(netdev);

	enic_dev_del_addr(enic, uc_addr);
	enic->uc_count--;

	return 0;
}

void enic_reset_addr_lists(struct enic *enic)
void enic_reset_addr_lists(struct enic *enic)
{
{
	struct net_device *netdev = enic->netdev;

	__dev_uc_unsync(netdev, NULL);
	__dev_mc_unsync(netdev, NULL);

	enic->mc_count = 0;
	enic->mc_count = 0;
	enic->uc_count = 0;
	enic->uc_count = 0;
	enic->flags = 0;
	enic->flags = 0;
@@ -684,112 +747,6 @@ static int enic_set_mac_address(struct net_device *netdev, void *p)
	return enic_dev_add_station_addr(enic);
	return enic_dev_add_station_addr(enic);
}
}


static void enic_update_multicast_addr_list(struct enic *enic)
{
	struct net_device *netdev = enic->netdev;
	struct netdev_hw_addr *ha;
	unsigned int mc_count = netdev_mc_count(netdev);
	u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
	unsigned int i, j;

	if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS) {
		netdev_warn(netdev, "Registering only %d out of %d "
			"multicast addresses\n",
			ENIC_MULTICAST_PERFECT_FILTERS, mc_count);
		mc_count = ENIC_MULTICAST_PERFECT_FILTERS;
	}

	/* Is there an easier way?  Trying to minimize to
	 * calls to add/del multicast addrs.  We keep the
	 * addrs from the last call in enic->mc_addr and
	 * look for changes to add/del.
	 */

	i = 0;
	netdev_for_each_mc_addr(ha, netdev) {
		if (i == mc_count)
			break;
		memcpy(mc_addr[i++], ha->addr, ETH_ALEN);
	}

	for (i = 0; i < enic->mc_count; i++) {
		for (j = 0; j < mc_count; j++)
			if (ether_addr_equal(enic->mc_addr[i], mc_addr[j]))
				break;
		if (j == mc_count)
			enic_dev_del_addr(enic, enic->mc_addr[i]);
	}

	for (i = 0; i < mc_count; i++) {
		for (j = 0; j < enic->mc_count; j++)
			if (ether_addr_equal(mc_addr[i], enic->mc_addr[j]))
				break;
		if (j == enic->mc_count)
			enic_dev_add_addr(enic, mc_addr[i]);
	}

	/* Save the list to compare against next time
	 */

	for (i = 0; i < mc_count; i++)
		memcpy(enic->mc_addr[i], mc_addr[i], ETH_ALEN);

	enic->mc_count = mc_count;
}

static void enic_update_unicast_addr_list(struct enic *enic)
{
	struct net_device *netdev = enic->netdev;
	struct netdev_hw_addr *ha;
	unsigned int uc_count = netdev_uc_count(netdev);
	u8 uc_addr[ENIC_UNICAST_PERFECT_FILTERS][ETH_ALEN];
	unsigned int i, j;

	if (uc_count > ENIC_UNICAST_PERFECT_FILTERS) {
		netdev_warn(netdev, "Registering only %d out of %d "
			"unicast addresses\n",
			ENIC_UNICAST_PERFECT_FILTERS, uc_count);
		uc_count = ENIC_UNICAST_PERFECT_FILTERS;
	}

	/* Is there an easier way?  Trying to minimize to
	 * calls to add/del unicast addrs.  We keep the
	 * addrs from the last call in enic->uc_addr and
	 * look for changes to add/del.
	 */

	i = 0;
	netdev_for_each_uc_addr(ha, netdev) {
		if (i == uc_count)
			break;
		memcpy(uc_addr[i++], ha->addr, ETH_ALEN);
	}

	for (i = 0; i < enic->uc_count; i++) {
		for (j = 0; j < uc_count; j++)
			if (ether_addr_equal(enic->uc_addr[i], uc_addr[j]))
				break;
		if (j == uc_count)
			enic_dev_del_addr(enic, enic->uc_addr[i]);
	}

	for (i = 0; i < uc_count; i++) {
		for (j = 0; j < enic->uc_count; j++)
			if (ether_addr_equal(uc_addr[i], enic->uc_addr[j]))
				break;
		if (j == enic->uc_count)
			enic_dev_add_addr(enic, uc_addr[i]);
	}

	/* Save the list to compare against next time
	 */

	for (i = 0; i < uc_count; i++)
		memcpy(enic->uc_addr[i], uc_addr[i], ETH_ALEN);

	enic->uc_count = uc_count;
}

/* netif_tx_lock held, BHs disabled */
/* netif_tx_lock held, BHs disabled */
static void enic_set_rx_mode(struct net_device *netdev)
static void enic_set_rx_mode(struct net_device *netdev)
{
{
@@ -812,9 +769,9 @@ static void enic_set_rx_mode(struct net_device *netdev)
	}
	}


	if (!promisc) {
	if (!promisc) {
		enic_update_unicast_addr_list(enic);
		__dev_uc_sync(netdev, enic_uc_sync, enic_uc_unsync);
		if (!allmulti)
		if (!allmulti)
			enic_update_multicast_addr_list(enic);
			__dev_mc_sync(netdev, enic_mc_sync, enic_mc_unsync);
	}
	}
}
}


+2 −2
Original line number Original line Diff line number Diff line
@@ -657,7 +657,7 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
	return err;
	return err;
}
}


int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
int vnic_dev_add_addr(struct vnic_dev *vdev, const u8 *addr)
{
{
	u64 a0 = 0, a1 = 0;
	u64 a0 = 0, a1 = 0;
	int wait = 1000;
	int wait = 1000;
@@ -674,7 +674,7 @@ int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
	return err;
	return err;
}
}


int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
int vnic_dev_del_addr(struct vnic_dev *vdev, const u8 *addr)
{
{
	u64 a0 = 0, a1 = 0;
	u64 a0 = 0, a1 = 0;
	int wait = 1000;
	int wait = 1000;
Loading