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

Commit 883ce97d authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller
Browse files

bnx2x: Add Geneve inner-RSS support



This adds the ability to perform RSS hashing based on encapsulated
headers for a geneve-encapsulated packet.

This also changes the Vxlan implementation in bnx2x to be uniform
for both vxlan and geneve [from configuration perspective].

Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarAriel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 44520464
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -1277,8 +1277,7 @@ enum sp_rtnl_flag {
	BNX2X_SP_RTNL_HYPERVISOR_VLAN,
	BNX2X_SP_RTNL_TX_STOP,
	BNX2X_SP_RTNL_GET_DRV_VERSION,
	BNX2X_SP_RTNL_ADD_VXLAN_PORT,
	BNX2X_SP_RTNL_DEL_VXLAN_PORT,
	BNX2X_SP_RTNL_CHANGE_UDP_PORT,
};

enum bnx2x_iov_flag {
@@ -1327,6 +1326,17 @@ struct bnx2x_vlan_entry {
	bool hw;
};

enum bnx2x_udp_port_type {
	BNX2X_UDP_PORT_VXLAN,
	BNX2X_UDP_PORT_GENEVE,
	BNX2X_UDP_PORT_MAX,
};

struct bnx2x_udp_tunnel {
	u16 dst_port;
	u8 count;
};

struct bnx2x {
	/* Fields used in the tx and intr/napi performance paths
	 * are grouped together in the beginning of the structure
@@ -1830,9 +1840,10 @@ struct bnx2x {
	struct list_head vlan_reg;
	u16 vlan_cnt;
	u16 vlan_credit;
	u16 vxlan_dst_port;
	u8 vxlan_dst_port_count;
	bool accept_any_vlan;

	/* Vxlan/Geneve related information */
	struct bnx2x_udp_tunnel udp_tunnel_ports[BNX2X_UDP_PORT_MAX];
};

/* Tx queues may be less or equal to Rx queues */
+9 −2
Original line number Diff line number Diff line
@@ -923,6 +923,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
	struct bnx2x_func_state_params func_params = {NULL};
	struct bnx2x_func_start_params *start_params =
		&func_params.params.start;
	u16 port;

	/* Prepare parameters for function state transitions */
	__set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
@@ -959,8 +960,14 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
		start_params->network_cos_mode = STATIC_COS;
	else /* CHIP_IS_E1X */
		start_params->network_cos_mode = FW_WRR;

	start_params->vxlan_dst_port = bp->vxlan_dst_port;
	if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].count) {
		port = bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].dst_port;
		start_params->vxlan_dst_port = port;
	}
	if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].count) {
		port = bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].dst_port;
		start_params->geneve_dst_port = port;
	}

	start_params->inner_rss = 1;

+122 −53
Original line number Diff line number Diff line
@@ -59,7 +59,9 @@
#include <linux/semaphore.h>
#include <linux/stringify.h>
#include <linux/vmalloc.h>

#if IS_ENABLED(CONFIG_GENEVE)
#include <net/geneve.h>
#endif
#include "bnx2x.h"
#include "bnx2x_init.h"
#include "bnx2x_init_ops.h"
@@ -10076,11 +10078,13 @@ static void bnx2x_parity_recover(struct bnx2x *bp)
	}
}

#ifdef CONFIG_BNX2X_VXLAN
static int bnx2x_vxlan_port_update(struct bnx2x *bp, u16 port)
#if defined(CONFIG_BNX2X_VXLAN) || IS_ENABLED(CONFIG_GENEVE)
static int bnx2x_udp_port_update(struct bnx2x *bp)
{
	struct bnx2x_func_switch_update_params *switch_update_params;
	struct bnx2x_func_state_params func_params = {NULL};
	struct bnx2x_udp_tunnel *udp_tunnel;
	u16 vxlan_port = 0, geneve_port = 0;
	int rc;

	switch_update_params = &func_params.params.switch_update;
@@ -10095,69 +10099,125 @@ static int bnx2x_vxlan_port_update(struct bnx2x *bp, u16 port)
	/* Function parameters */
	__set_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
		  &switch_update_params->changes);
	switch_update_params->vxlan_dst_port = port;

	if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].count) {
		udp_tunnel = &bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE];
		geneve_port = udp_tunnel->dst_port;
		switch_update_params->geneve_dst_port = geneve_port;
	}

	if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].count) {
		udp_tunnel = &bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN];
		vxlan_port = udp_tunnel->dst_port;
		switch_update_params->vxlan_dst_port = vxlan_port;
	}

	/* Re-enable inner-rss for the offloaded UDP tunnels */
	__set_bit(BNX2X_F_UPDATE_TUNNEL_INNER_RSS,
		  &switch_update_params->changes);

	rc = bnx2x_func_state_change(bp, &func_params);
	if (rc)
		BNX2X_ERR("failed to change vxlan dst port to %d (rc = 0x%x)\n",
			  port, rc);
		BNX2X_ERR("failed to set UDP dst port to %04x %04x (rc = 0x%x)\n",
			  vxlan_port, geneve_port, rc);
	else
		DP(BNX2X_MSG_SP,
		   "Configured UDP ports: Vxlan [%04x] Geneve [%04x]\n",
		   vxlan_port, geneve_port);

	return rc;
}

static void __bnx2x_add_vxlan_port(struct bnx2x *bp, u16 port)
static void __bnx2x_add_udp_port(struct bnx2x *bp, u16 port,
				 enum bnx2x_udp_port_type type)
{
	if (!netif_running(bp->dev))
	struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];

	if (!netif_running(bp->dev) || !IS_PF(bp))
		return;

	if (bp->vxlan_dst_port_count && bp->vxlan_dst_port == port) {
		bp->vxlan_dst_port_count++;
	if (udp_port->count && udp_port->dst_port == port) {
		udp_port->count++;
		return;
	}

	if (bp->vxlan_dst_port_count || !IS_PF(bp)) {
		DP(BNX2X_MSG_SP, "Vxlan destination port limit reached\n");
	if (udp_port->count) {
		DP(BNX2X_MSG_SP,
		   "UDP tunnel [%d] -  destination port limit reached\n",
		   type);
		return;
	}

	bp->vxlan_dst_port = port;
	bp->vxlan_dst_port_count = 1;
	bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_ADD_VXLAN_PORT, 0);
	udp_port->dst_port = port;
	udp_port->count = 1;
	bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_CHANGE_UDP_PORT, 0);
}

static void __bnx2x_del_udp_port(struct bnx2x *bp, u16 port,
				 enum bnx2x_udp_port_type type)
{
	struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];

	if (!IS_PF(bp))
		return;

	if (!udp_port->count || udp_port->dst_port != port) {
		DP(BNX2X_MSG_SP, "Invalid UDP tunnel [%d] port\n",
		   type);
		return;
	}

	/* Remove reference, and make certain it's no longer in use */
	udp_port->count--;
	if (udp_port->count)
		return;
	udp_port->dst_port = 0;

	if (netif_running(bp->dev))
		bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_CHANGE_UDP_PORT, 0);
	else
		DP(BNX2X_MSG_SP, "Deleted UDP tunnel [%d] port %d\n",
		   type, port);
}
#endif

#ifdef CONFIG_BNX2X_VXLAN
static void bnx2x_add_vxlan_port(struct net_device *netdev,
				 sa_family_t sa_family, __be16 port)
{
	struct bnx2x *bp = netdev_priv(netdev);
	u16 t_port = ntohs(port);

	__bnx2x_add_vxlan_port(bp, t_port);
	__bnx2x_add_udp_port(bp, t_port, BNX2X_UDP_PORT_VXLAN);
}

static void __bnx2x_del_vxlan_port(struct bnx2x *bp, u16 port)
static void bnx2x_del_vxlan_port(struct net_device *netdev,
				 sa_family_t sa_family, __be16 port)
{
	if (!bp->vxlan_dst_port_count || bp->vxlan_dst_port != port ||
	    !IS_PF(bp)) {
		DP(BNX2X_MSG_SP, "Invalid vxlan port\n");
		return;
	}
	bp->vxlan_dst_port_count--;
	if (bp->vxlan_dst_port_count)
		return;
	struct bnx2x *bp = netdev_priv(netdev);
	u16 t_port = ntohs(port);

	if (netif_running(bp->dev)) {
		bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_DEL_VXLAN_PORT, 0);
	} else {
		bp->vxlan_dst_port = 0;
		netdev_info(bp->dev, "Deleted vxlan dest port %d", port);
	__bnx2x_del_udp_port(bp, t_port, BNX2X_UDP_PORT_VXLAN);
}
#endif

#if IS_ENABLED(CONFIG_GENEVE)
static void bnx2x_add_geneve_port(struct net_device *netdev,
				  sa_family_t sa_family, __be16 port)
{
	struct bnx2x *bp = netdev_priv(netdev);
	u16 t_port = ntohs(port);

	__bnx2x_add_udp_port(bp, t_port, BNX2X_UDP_PORT_GENEVE);
}

static void bnx2x_del_vxlan_port(struct net_device *netdev,
static void bnx2x_del_geneve_port(struct net_device *netdev,
				  sa_family_t sa_family, __be16 port)
{
	struct bnx2x *bp = netdev_priv(netdev);
	u16 t_port = ntohs(port);

	__bnx2x_del_vxlan_port(bp, t_port);
	__bnx2x_del_udp_port(bp, t_port, BNX2X_UDP_PORT_GENEVE);
}
#endif

@@ -10169,9 +10229,6 @@ static int bnx2x_close(struct net_device *dev);
static void bnx2x_sp_rtnl_task(struct work_struct *work)
{
	struct bnx2x *bp = container_of(work, struct bnx2x, sp_rtnl_task.work);
#ifdef CONFIG_BNX2X_VXLAN
	u16 port;
#endif

	rtnl_lock();

@@ -10270,23 +10327,27 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
			       &bp->sp_rtnl_state))
		bnx2x_update_mng_version(bp);

#ifdef CONFIG_BNX2X_VXLAN
	port = bp->vxlan_dst_port;
	if (test_and_clear_bit(BNX2X_SP_RTNL_ADD_VXLAN_PORT,
			       &bp->sp_rtnl_state)) {
		if (!bnx2x_vxlan_port_update(bp, port))
			netdev_info(bp->dev, "Added vxlan dest port %d", port);
		else
			bp->vxlan_dst_port = 0;
	}

	if (test_and_clear_bit(BNX2X_SP_RTNL_DEL_VXLAN_PORT,
#if defined(CONFIG_BNX2X_VXLAN) || IS_ENABLED(CONFIG_GENEVE)
	if (test_and_clear_bit(BNX2X_SP_RTNL_CHANGE_UDP_PORT,
			       &bp->sp_rtnl_state)) {
		if (!bnx2x_vxlan_port_update(bp, 0)) {
			netdev_info(bp->dev,
				    "Deleted vxlan dest port %d", port);
			bp->vxlan_dst_port = 0;
		if (bnx2x_udp_port_update(bp)) {
			/* On error, forget configuration */
			memset(bp->udp_tunnel_ports, 0,
			       sizeof(struct bnx2x_udp_tunnel) *
			       BNX2X_UDP_PORT_MAX);
		} else {
			/* Since we don't store additional port information,
			 * if no port is configured for any feature ask for
			 * information about currently configured ports.
			 */
#ifdef CONFIG_BNX2X_VXLAN
			if (!bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].count)
				vxlan_get_rx_port(bp->dev);
#endif
#if IS_ENABLED(CONFIG_GENEVE)
			if (!bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].count)
				geneve_get_rx_port(bp->dev);
#endif
		}
	}
#endif
@@ -12494,6 +12555,10 @@ static int bnx2x_open(struct net_device *dev)
	if (IS_PF(bp))
		vxlan_get_rx_port(dev);
#endif
#if IS_ENABLED(CONFIG_GENEVE)
	if (IS_PF(bp))
		geneve_get_rx_port(dev);
#endif

	return 0;
}
@@ -13011,6 +13076,10 @@ static const struct net_device_ops bnx2x_netdev_ops = {
	.ndo_add_vxlan_port	= bnx2x_add_vxlan_port,
	.ndo_del_vxlan_port	= bnx2x_del_vxlan_port,
#endif
#if IS_ENABLED(CONFIG_GENEVE)
	.ndo_add_geneve_port	= bnx2x_add_geneve_port,
	.ndo_del_geneve_port	= bnx2x_del_geneve_port,
#endif
};

static int bnx2x_set_coherency_mask(struct bnx2x *bp)