mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-28 13:34:38 +08:00
i40e: Implementation of VXLAN ndo's
This adds the implementation for the VXLAN ndo's. This allows the hardware to do RX checksum offload for inner packets on the UDP ports that VXLAN notifies us about. Signed-off-by: Joseph Gasparakis <joseph.gasparakis@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
be1d5eea00
commit
a1c9a9d998
@ -259,6 +259,19 @@ config I40E
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called i40e.
|
||||
|
||||
config I40E_VXLAN
|
||||
bool "Virtual eXtensible Local Area Network Support"
|
||||
default n
|
||||
depends on I40E && VXLAN && !(I40E=y && VXLAN=m)
|
||||
---help---
|
||||
This allows one to create VXLAN virtual interfaces that provide
|
||||
Layer 2 Networks over Layer 3 Networks. VXLAN is often used
|
||||
to tunnel virtual network infrastructure in virtualized environments.
|
||||
Say Y here if you want to use Virtual eXtensible Local Area Network
|
||||
(VXLAN) in the driver.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config I40EVF
|
||||
tristate "Intel(R) XL710 X710 Virtual Function Ethernet support"
|
||||
depends on PCI_MSI
|
||||
|
@ -207,6 +207,11 @@ struct i40e_pf {
|
||||
u8 atr_sample_rate;
|
||||
bool wol_en;
|
||||
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
__be16 vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
|
||||
u16 pending_vxlan_bitmap;
|
||||
|
||||
#endif
|
||||
enum i40e_interrupt_policy int_policy;
|
||||
u16 rx_itr_default;
|
||||
u16 tx_itr_default;
|
||||
@ -238,7 +243,10 @@ struct i40e_pf {
|
||||
#define I40E_FLAG_DCB_ENABLED (u64)(1 << 21)
|
||||
#define I40E_FLAG_FDIR_ENABLED (u64)(1 << 22)
|
||||
#define I40E_FLAG_FDIR_ATR_ENABLED (u64)(1 << 23)
|
||||
#define I40E_FLAG_MFP_ENABLED (u64)(1 << 27)
|
||||
#define I40E_FLAG_MFP_ENABLED (u64)(1 << 26)
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
#define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27)
|
||||
#endif
|
||||
|
||||
u16 num_tx_queues;
|
||||
u16 num_rx_queues;
|
||||
|
@ -1918,6 +1918,7 @@ struct i40e_aqc_add_udp_tunnel {
|
||||
u8 protocol_index;
|
||||
#define I40E_AQC_TUNNEL_TYPE_MAC 0x0
|
||||
#define I40E_AQC_TUNNEL_TYPE_UDP 0x1
|
||||
#define I40E_AQC_TUNNEL_TYPE_VXLAN 0x2
|
||||
u8 reserved[12];
|
||||
};
|
||||
|
||||
|
@ -1670,6 +1670,63 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_aq_add_udp_tunnel
|
||||
* @hw: pointer to the hw struct
|
||||
* @udp_port: the UDP port to add
|
||||
* @header_len: length of the tunneling header length in DWords
|
||||
* @protocol_index: protocol index type
|
||||
* @cmd_details: pointer to command details structure or NULL
|
||||
**/
|
||||
i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
|
||||
u16 udp_port, u8 header_len,
|
||||
u8 protocol_index, u8 *filter_index,
|
||||
struct i40e_asq_cmd_details *cmd_details)
|
||||
{
|
||||
struct i40e_aq_desc desc;
|
||||
struct i40e_aqc_add_udp_tunnel *cmd =
|
||||
(struct i40e_aqc_add_udp_tunnel *)&desc.params.raw;
|
||||
struct i40e_aqc_del_udp_tunnel_completion *resp =
|
||||
(struct i40e_aqc_del_udp_tunnel_completion *)&desc.params.raw;
|
||||
i40e_status status;
|
||||
|
||||
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_add_udp_tunnel);
|
||||
|
||||
cmd->udp_port = cpu_to_le16(udp_port);
|
||||
cmd->header_len = header_len;
|
||||
cmd->protocol_index = protocol_index;
|
||||
|
||||
status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
|
||||
|
||||
if (!status)
|
||||
*filter_index = resp->index;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_aq_del_udp_tunnel
|
||||
* @hw: pointer to the hw struct
|
||||
* @index: filter index
|
||||
* @cmd_details: pointer to command details structure or NULL
|
||||
**/
|
||||
i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index,
|
||||
struct i40e_asq_cmd_details *cmd_details)
|
||||
{
|
||||
struct i40e_aq_desc desc;
|
||||
struct i40e_aqc_remove_udp_tunnel *cmd =
|
||||
(struct i40e_aqc_remove_udp_tunnel *)&desc.params.raw;
|
||||
i40e_status status;
|
||||
|
||||
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_del_udp_tunnel);
|
||||
|
||||
cmd->index = index;
|
||||
|
||||
status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_aq_delete_element - Delete switch element
|
||||
* @hw: pointer to the hw struct
|
||||
|
@ -27,6 +27,9 @@
|
||||
|
||||
/* Local includes */
|
||||
#include "i40e.h"
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
#include <net/vxlan.h>
|
||||
#endif
|
||||
|
||||
const char i40e_driver_name[] = "i40e";
|
||||
static const char i40e_driver_string[] =
|
||||
@ -3993,6 +3996,9 @@ static int i40e_open(struct net_device *netdev)
|
||||
"couldn't set broadcast err %d aq_err %d\n",
|
||||
err, pf->hw.aq.asq_last_status);
|
||||
}
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
vxlan_get_rx_port(netdev);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@ -5016,6 +5022,52 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
|
||||
i40e_flush(hw);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
/**
|
||||
* i40e_sync_vxlan_filters_subtask - Sync the VSI filter list with HW
|
||||
* @pf: board private structure
|
||||
**/
|
||||
static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf)
|
||||
{
|
||||
const int vxlan_hdr_qwords = 4;
|
||||
struct i40e_hw *hw = &pf->hw;
|
||||
i40e_status ret;
|
||||
u8 filter_index;
|
||||
__be16 port;
|
||||
int i;
|
||||
|
||||
if (!(pf->flags & I40E_FLAG_VXLAN_FILTER_SYNC))
|
||||
return;
|
||||
|
||||
pf->flags &= ~I40E_FLAG_VXLAN_FILTER_SYNC;
|
||||
|
||||
for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) {
|
||||
if (pf->pending_vxlan_bitmap & (1 << i)) {
|
||||
pf->pending_vxlan_bitmap &= ~(1 << i);
|
||||
port = pf->vxlan_ports[i];
|
||||
ret = port ?
|
||||
i40e_aq_add_udp_tunnel(hw, ntohs(port),
|
||||
vxlan_hdr_qwords,
|
||||
I40E_AQC_TUNNEL_TYPE_VXLAN,
|
||||
&filter_index, NULL)
|
||||
: i40e_aq_del_udp_tunnel(hw, i, NULL);
|
||||
|
||||
if (ret) {
|
||||
dev_info(&pf->pdev->dev, "Failed to execute AQ command for %s port %d with index %d\n",
|
||||
port ? "adding" : "deleting",
|
||||
ntohs(port), port ? i : i);
|
||||
|
||||
pf->vxlan_ports[i] = 0;
|
||||
} else {
|
||||
dev_info(&pf->pdev->dev, "%s port %d with AQ command with index %d\n",
|
||||
port ? "Added" : "Deleted",
|
||||
ntohs(port), port ? i : filter_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* i40e_service_task - Run the driver's async subtasks
|
||||
* @work: pointer to work_struct containing our data
|
||||
@ -5034,6 +5086,9 @@ static void i40e_service_task(struct work_struct *work)
|
||||
i40e_fdir_reinit_subtask(pf);
|
||||
i40e_check_hang_subtask(pf);
|
||||
i40e_sync_filters_subtask(pf);
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
i40e_sync_vxlan_filters_subtask(pf);
|
||||
#endif
|
||||
i40e_clean_adminq_subtask(pf);
|
||||
|
||||
i40e_service_event_complete(pf);
|
||||
@ -5900,6 +5955,104 @@ static int i40e_set_features(struct net_device *netdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
/**
|
||||
* i40e_get_vxlan_port_idx - Lookup a possibly offloaded for Rx UDP port
|
||||
* @pf: board private structure
|
||||
* @port: The UDP port to look up
|
||||
*
|
||||
* Returns the index number or I40E_MAX_PF_UDP_OFFLOAD_PORTS if port not found
|
||||
**/
|
||||
static u8 i40e_get_vxlan_port_idx(struct i40e_pf *pf, __be16 port)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) {
|
||||
if (pf->vxlan_ports[i] == port)
|
||||
return i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_add_vxlan_port - Get notifications about VXLAN ports that come up
|
||||
* @netdev: This physical port's netdev
|
||||
* @sa_family: Socket Family that VXLAN is notifying us about
|
||||
* @port: New UDP port number that VXLAN started listening to
|
||||
**/
|
||||
static void i40e_add_vxlan_port(struct net_device *netdev,
|
||||
sa_family_t sa_family, __be16 port)
|
||||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
u8 next_idx;
|
||||
u8 idx;
|
||||
|
||||
if (sa_family == AF_INET6)
|
||||
return;
|
||||
|
||||
idx = i40e_get_vxlan_port_idx(pf, port);
|
||||
|
||||
/* Check if port already exists */
|
||||
if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
|
||||
netdev_info(netdev, "Port %d already offloaded\n", ntohs(port));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now check if there is space to add the new port */
|
||||
next_idx = i40e_get_vxlan_port_idx(pf, 0);
|
||||
|
||||
if (next_idx == I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
|
||||
netdev_info(netdev, "Maximum number of UDP ports reached, not adding port %d\n",
|
||||
ntohs(port));
|
||||
return;
|
||||
}
|
||||
|
||||
/* New port: add it and mark its index in the bitmap */
|
||||
pf->vxlan_ports[next_idx] = port;
|
||||
pf->pending_vxlan_bitmap |= (1 << next_idx);
|
||||
|
||||
pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC;
|
||||
}
|
||||
|
||||
/**
|
||||
* i40e_del_vxlan_port - Get notifications about VXLAN ports that go away
|
||||
* @netdev: This physical port's netdev
|
||||
* @sa_family: Socket Family that VXLAN is notifying us about
|
||||
* @port: UDP port number that VXLAN stopped listening to
|
||||
**/
|
||||
static void i40e_del_vxlan_port(struct net_device *netdev,
|
||||
sa_family_t sa_family, __be16 port)
|
||||
{
|
||||
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
||||
struct i40e_vsi *vsi = np->vsi;
|
||||
struct i40e_pf *pf = vsi->back;
|
||||
u8 idx;
|
||||
|
||||
if (sa_family == AF_INET6)
|
||||
return;
|
||||
|
||||
idx = i40e_get_vxlan_port_idx(pf, port);
|
||||
|
||||
/* Check if port already exists */
|
||||
if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) {
|
||||
/* if port exists, set it to 0 (mark for deletion)
|
||||
* and make it pending
|
||||
*/
|
||||
pf->vxlan_ports[idx] = 0;
|
||||
|
||||
pf->pending_vxlan_bitmap |= (1 << idx);
|
||||
|
||||
pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC;
|
||||
} else {
|
||||
netdev_warn(netdev, "Port %d was not found, not deleting\n",
|
||||
ntohs(port));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
static const struct net_device_ops i40e_netdev_ops = {
|
||||
.ndo_open = i40e_open,
|
||||
.ndo_stop = i40e_close,
|
||||
@ -5921,6 +6074,10 @@ static const struct net_device_ops i40e_netdev_ops = {
|
||||
.ndo_set_vf_vlan = i40e_ndo_set_vf_port_vlan,
|
||||
.ndo_set_vf_tx_rate = i40e_ndo_set_vf_bw,
|
||||
.ndo_get_vf_config = i40e_ndo_get_vf_config,
|
||||
#ifdef CONFIG_I40E_VXLAN
|
||||
.ndo_add_vxlan_port = i40e_add_vxlan_port,
|
||||
.ndo_del_vxlan_port = i40e_del_vxlan_port,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -157,6 +157,12 @@ i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
|
||||
struct i40e_asq_cmd_details *cmd_details);
|
||||
i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
|
||||
struct i40e_asq_cmd_details *cmd_details);
|
||||
i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
|
||||
u16 udp_port, u8 header_len,
|
||||
u8 protocol_index, u8 *filter_index,
|
||||
struct i40e_asq_cmd_details *cmd_details);
|
||||
i40e_status i40e_aq_del_udp_tunnel(struct i40e_hw *hw, u8 index,
|
||||
struct i40e_asq_cmd_details *cmd_details);
|
||||
i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid,
|
||||
struct i40e_asq_cmd_details *cmd_details);
|
||||
i40e_status i40e_aq_mac_address_write(struct i40e_hw *hw,
|
||||
|
@ -59,6 +59,7 @@
|
||||
#define I40E_MAX_VSI_QP 16
|
||||
#define I40E_MAX_VF_VSI 3
|
||||
#define I40E_MAX_CHAINED_RX_BUFFERS 5
|
||||
#define I40E_MAX_PF_UDP_OFFLOAD_PORTS 16
|
||||
|
||||
/* Max default timeout in ms, */
|
||||
#define I40E_MAX_NVM_TIMEOUT 18000
|
||||
|
Loading…
Reference in New Issue
Block a user