Skip to content

Commit

Permalink
bnx2x: Add Geneve inner-RSS support
Browse files Browse the repository at this point in the history
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: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Yuval Mintz authored and David S. Miller committed Feb 17, 2016
1 parent 4452046 commit 883ce97
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 59 deletions.
19 changes: 15 additions & 4 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down
11 changes: 9 additions & 2 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down
175 changes: 122 additions & 53 deletions drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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 (udp_port->count && udp_port->dst_port == port) {
udp_port->count++;
return;
}

if (bp->vxlan_dst_port_count && bp->vxlan_dst_port == port) {
bp->vxlan_dst_port_count++;
if (udp_port->count) {
DP(BNX2X_MSG_SP,
"UDP tunnel [%d] - destination port limit reached\n",
type);
return;
}

if (bp->vxlan_dst_port_count || !IS_PF(bp)) {
DP(BNX2X_MSG_SP, "Vxlan destination port limit reached\n");
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;
}

bp->vxlan_dst_port = port;
bp->vxlan_dst_port_count = 1;
bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_ADD_VXLAN_PORT, 0);
/* 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,
sa_family_t sa_family, __be16 port)
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

Expand All @@ -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();

Expand Down Expand Up @@ -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;
vxlan_get_rx_port(bp->dev);
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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 883ce97

Please sign in to comment.