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

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

Merge branch 'mlx4'



Amir Vadai says:

====================
This series from Yan Burman adds support for unicast MAC address filtering and
ndo FDB operations.  It also includes some optimizations to loopback related
decisions and checks in the TX/RX fast path and one cleanup, all in separate
patches.

Today, when adding macvlan devices, the NIC goes into promiscuous mode, since
unicast MAC filtering is not supported. With these changes, macvlan devices can
be added without the penalty of promiscuous mode.

If for some reason adding a unicast address filter fails e.g as of missing space in
the HW mac table, the device forces itself into promiscuous mode (and out of this
forced state when enough space is available).

Also, now it is possible to have bridge under multi-function configuration that include
PF and VFs.  In order to use bridge over PF/VFs, VM MAC fdb entries must be added e.g.
using 'bridge fdb add' command.

Changes from v1 - based on more comments from Eric Dumazet:
* added failure handling when adding unicast address filter

Changes from v0 - based on comments from Eric Dumazet:
* Removed unneeded synchronize_rcu()
* Use kfree_rcu() instead of synchronize_rcu() + kfree()
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c6edfe10 0ccddcd1
Loading
Loading
Loading
Loading
+3 −6
Original line number Original line Diff line number Diff line
@@ -712,16 +712,13 @@ static int mlx4_en_ethtool_add_mac_rule_by_ipv4(struct mlx4_en_priv *priv,
						__be32 ipv4_dst)
						__be32 ipv4_dst)
{
{
#ifdef CONFIG_INET
#ifdef CONFIG_INET
	__be64 be_mac = 0;
	unsigned char mac[ETH_ALEN];
	unsigned char mac[ETH_ALEN];


	if (!ipv4_is_multicast(ipv4_dst)) {
	if (!ipv4_is_multicast(ipv4_dst)) {
		if (cmd->fs.flow_type & FLOW_MAC_EXT) {
		if (cmd->fs.flow_type & FLOW_MAC_EXT)
			memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
			memcpy(&mac, cmd->fs.h_ext.h_dest, ETH_ALEN);
		} else {
		else
			be_mac = cpu_to_be64((priv->mac & MLX4_MAC_MASK) << 16);
			memcpy(&mac, priv->dev->dev_addr, ETH_ALEN);
			memcpy(&mac, &be_mac, ETH_ALEN);
		}
	} else {
	} else {
		ip_eth_mc_map(ipv4_dst, mac);
		ip_eth_mc_map(ipv4_dst, mac);
	}
	}
+22 −0
Original line number Original line Diff line number Diff line
@@ -95,6 +95,28 @@ int en_print(const char *level, const struct mlx4_en_priv *priv,
	return i;
	return i;
}
}


void mlx4_en_update_loopback_state(struct net_device *dev,
				   netdev_features_t features)
{
	struct mlx4_en_priv *priv = netdev_priv(dev);

	priv->flags &= ~(MLX4_EN_FLAG_RX_FILTER_NEEDED|
			MLX4_EN_FLAG_ENABLE_HW_LOOPBACK);

	/* Drop the packet if SRIOV is not enabled
	 * and not performing the selftest or flb disabled
	 */
	if (mlx4_is_mfunc(priv->mdev->dev) &&
	    !(features & NETIF_F_LOOPBACK) && !priv->validate_loopback)
		priv->flags |= MLX4_EN_FLAG_RX_FILTER_NEEDED;

	/* Set dmac in Tx WQE if we are in SRIOV mode or if loopback selftest
	 * is requested
	 */
	if (mlx4_is_mfunc(priv->mdev->dev) || priv->validate_loopback)
		priv->flags |= MLX4_EN_FLAG_ENABLE_HW_LOOPBACK;
}

static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
{
{
	struct mlx4_en_profile *params = &mdev->profile;
	struct mlx4_en_profile *params = &mdev->profile;
+606 −159

File changed.

Preview size limit exceeded, changes collapsed.

+35 −18
Original line number Original line Diff line number Diff line
@@ -563,9 +563,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
	unsigned int length;
	unsigned int length;
	int polled = 0;
	int polled = 0;
	int ip_summed;
	int ip_summed;
	struct ethhdr *ethh;
	dma_addr_t dma;
	u64 s_mac;
	int factor = priv->cqe_factor;
	int factor = priv->cqe_factor;


	if (!priv->port_up)
	if (!priv->port_up)
@@ -603,21 +600,41 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
			goto next;
			goto next;
		}
		}


		/* Get pointer to first fragment since we haven't skb yet and
		/* Check if we need to drop the packet if SRIOV is not enabled
		 * cast it to ethhdr struct */
		 * and not performing the selftest or flb disabled
		 */
		if (priv->flags & MLX4_EN_FLAG_RX_FILTER_NEEDED) {
			struct ethhdr *ethh;
			dma_addr_t dma;
			/* Get pointer to first fragment since we haven't
			 * skb yet and cast it to ethhdr struct
			 */
			dma = be64_to_cpu(rx_desc->data[0].addr);
			dma = be64_to_cpu(rx_desc->data[0].addr);
			dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
			dma_sync_single_for_cpu(priv->ddev, dma, sizeof(*ethh),
						DMA_FROM_DEVICE);
						DMA_FROM_DEVICE);
			ethh = (struct ethhdr *)(page_address(frags[0].page) +
			ethh = (struct ethhdr *)(page_address(frags[0].page) +
						 frags[0].offset);
						 frags[0].offset);
		s_mac = mlx4_en_mac_to_u64(ethh->h_source);


		/* If source MAC is equal to our own MAC and not performing
			if (is_multicast_ether_addr(ethh->h_dest)) {
		 * the selftest or flb disabled - drop the packet */
				struct mlx4_mac_entry *entry;
		if (s_mac == priv->mac &&
				struct hlist_node *n;
		    !((dev->features & NETIF_F_LOOPBACK) ||
				struct hlist_head *bucket;
		      priv->validate_loopback))
				unsigned int mac_hash;

				/* Drop the packet, since HW loopback-ed it */
				mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
				bucket = &priv->mac_hash[mac_hash];
				rcu_read_lock();
				hlist_for_each_entry_rcu(entry, n, bucket, hlist) {
					if (ether_addr_equal_64bits(entry->mac,
								    ethh->h_source)) {
						rcu_read_unlock();
						goto next;
						goto next;
					}
				}
				rcu_read_unlock();
			}
		}


		/*
		/*
		 * Packet is OK - process it.
		 * Packet is OK - process it.
+3 −0
Original line number Original line Diff line number Diff line
@@ -87,6 +87,8 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
        priv->loopback_ok = 0;
        priv->loopback_ok = 0;
	priv->validate_loopback = 1;
	priv->validate_loopback = 1;


	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);

	/* xmit */
	/* xmit */
	if (mlx4_en_test_loopback_xmit(priv)) {
	if (mlx4_en_test_loopback_xmit(priv)) {
		en_err(priv, "Transmitting loopback packet failed\n");
		en_err(priv, "Transmitting loopback packet failed\n");
@@ -107,6 +109,7 @@ static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
mlx4_en_test_loopback_exit:
mlx4_en_test_loopback_exit:


	priv->validate_loopback = 0;
	priv->validate_loopback = 0;
	mlx4_en_update_loopback_state(priv->dev, priv->dev->features);
	return !loopback_ok;
	return !loopback_ok;
}
}


Loading