Merge branch '10GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue
Jeff Kirsher says: ==================== 10GbE Intel Wired LAN Driver Updates 2018-01-23 This series contains updates to ixgbe only. Shannon Nelson provides an implementation of the ipsec hardware offload feature for the ixgbe driver for these devices: x540, x550, 82599. The ixgbe NICs support ipsec offload for 1024 Rx and 1024 Tx Security Associations (SAs), using up to 128 inbound IP addresses, and using the rfc4106(gcm(aes)) encryption. This code does not yet support checksum offload, or TSO in conjunction with the ipsec offload - those will be added in the future. This code shows improvements in both packet throughput and CPU utilization. For example, here are some quicky numbers that show the magnitude of the performance gain on a single run of "iperf -c <dest>" with the ipsec offload on both ends of a point-to-point connection: 9.4 Gbps - normal case 7.6 Gbps - ipsec with offload 343 Mbps - ipsec no offload ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0542e13b5f
|
@ -42,3 +42,4 @@ ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \
|
|||
ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o
|
||||
ixgbe-$(CONFIG_DEBUG_FS) += ixgbe_debugfs.o
|
||||
ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
|
||||
ixgbe-$(CONFIG_XFRM_OFFLOAD) += ixgbe_ipsec.o
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#ifdef CONFIG_IXGBE_DCA
|
||||
#include <linux/dca.h>
|
||||
#endif
|
||||
#include "ixgbe_ipsec.h"
|
||||
|
||||
#include <net/xdp.h>
|
||||
#include <net/busy_poll.h>
|
||||
|
@ -171,10 +172,11 @@ enum ixgbe_tx_flags {
|
|||
IXGBE_TX_FLAGS_CC = 0x08,
|
||||
IXGBE_TX_FLAGS_IPV4 = 0x10,
|
||||
IXGBE_TX_FLAGS_CSUM = 0x20,
|
||||
IXGBE_TX_FLAGS_IPSEC = 0x40,
|
||||
|
||||
/* software defined flags */
|
||||
IXGBE_TX_FLAGS_SW_VLAN = 0x40,
|
||||
IXGBE_TX_FLAGS_FCOE = 0x80,
|
||||
IXGBE_TX_FLAGS_SW_VLAN = 0x80,
|
||||
IXGBE_TX_FLAGS_FCOE = 0x100,
|
||||
};
|
||||
|
||||
/* VLAN info */
|
||||
|
@ -629,15 +631,18 @@ struct ixgbe_adapter {
|
|||
#define IXGBE_FLAG2_EEE_CAPABLE BIT(14)
|
||||
#define IXGBE_FLAG2_EEE_ENABLED BIT(15)
|
||||
#define IXGBE_FLAG2_RX_LEGACY BIT(16)
|
||||
#define IXGBE_FLAG2_IPSEC_ENABLED BIT(17)
|
||||
|
||||
/* Tx fast path data */
|
||||
int num_tx_queues;
|
||||
u16 tx_itr_setting;
|
||||
u16 tx_work_limit;
|
||||
u64 tx_ipsec;
|
||||
|
||||
/* Rx fast path data */
|
||||
int num_rx_queues;
|
||||
u16 rx_itr_setting;
|
||||
u64 rx_ipsec;
|
||||
|
||||
/* Port number used to identify VXLAN traffic */
|
||||
__be16 vxlan_port;
|
||||
|
@ -781,6 +786,10 @@ struct ixgbe_adapter {
|
|||
|
||||
#define IXGBE_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
|
||||
u32 *rss_key;
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
struct ixgbe_ipsec *ipsec;
|
||||
#endif /* CONFIG_XFRM */
|
||||
};
|
||||
|
||||
static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter)
|
||||
|
@ -1011,4 +1020,24 @@ void ixgbe_store_key(struct ixgbe_adapter *adapter);
|
|||
void ixgbe_store_reta(struct ixgbe_adapter *adapter);
|
||||
s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
|
||||
u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm);
|
||||
#ifdef CONFIG_XFRM_OFFLOAD
|
||||
void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter);
|
||||
void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter);
|
||||
void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter);
|
||||
void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
|
||||
union ixgbe_adv_rx_desc *rx_desc,
|
||||
struct sk_buff *skb);
|
||||
int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring, struct ixgbe_tx_buffer *first,
|
||||
struct ixgbe_ipsec_tx_data *itd);
|
||||
#else
|
||||
static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { };
|
||||
static inline void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter) { };
|
||||
static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { };
|
||||
static inline void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
|
||||
union ixgbe_adv_rx_desc *rx_desc,
|
||||
struct sk_buff *skb) { };
|
||||
static inline int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring,
|
||||
struct ixgbe_tx_buffer *first,
|
||||
struct ixgbe_ipsec_tx_data *itd) { return 0; };
|
||||
#endif /* CONFIG_XFRM_OFFLOAD */
|
||||
#endif /* _IXGBE_H_ */
|
||||
|
|
|
@ -115,6 +115,8 @@ static const struct ixgbe_stats ixgbe_gstrings_stats[] = {
|
|||
{"tx_hwtstamp_timeouts", IXGBE_STAT(tx_hwtstamp_timeouts)},
|
||||
{"tx_hwtstamp_skipped", IXGBE_STAT(tx_hwtstamp_skipped)},
|
||||
{"rx_hwtstamp_cleared", IXGBE_STAT(rx_hwtstamp_cleared)},
|
||||
{"tx_ipsec", IXGBE_STAT(tx_ipsec)},
|
||||
{"rx_ipsec", IXGBE_STAT(rx_ipsec)},
|
||||
#ifdef IXGBE_FCOE
|
||||
{"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)},
|
||||
{"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)},
|
||||
|
|
|
@ -0,0 +1,941 @@
|
|||
/*******************************************************************************
|
||||
*
|
||||
* Intel 10 Gigabit PCI Express Linux driver
|
||||
* Copyright(c) 2017 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Contact Information:
|
||||
* Linux NICS <linux.nics@intel.com>
|
||||
* e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "ixgbe.h"
|
||||
#include <net/xfrm.h>
|
||||
#include <crypto/aead.h>
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_set_tx_sa - set the Tx SA registers
|
||||
* @hw: hw specific details
|
||||
* @idx: register index to write
|
||||
* @key: key byte array
|
||||
* @salt: salt bytes
|
||||
**/
|
||||
static void ixgbe_ipsec_set_tx_sa(struct ixgbe_hw *hw, u16 idx,
|
||||
u32 key[], u32 salt)
|
||||
{
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(i), cpu_to_be32(key[3 - i]));
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT, cpu_to_be32(salt));
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_IPSTXIDX);
|
||||
reg &= IXGBE_RXTXIDX_IPS_EN;
|
||||
reg |= idx << IXGBE_RXTXIDX_IDX_SHIFT | IXGBE_RXTXIDX_WRITE;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, reg);
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_set_rx_item - set an Rx table item
|
||||
* @hw: hw specific details
|
||||
* @idx: register index to write
|
||||
* @tbl: table selector
|
||||
*
|
||||
* Trigger the device to store into a particular Rx table the
|
||||
* data that has already been loaded into the input register
|
||||
**/
|
||||
static void ixgbe_ipsec_set_rx_item(struct ixgbe_hw *hw, u16 idx,
|
||||
enum ixgbe_ipsec_tbl_sel tbl)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_IPSRXIDX);
|
||||
reg &= IXGBE_RXTXIDX_IPS_EN;
|
||||
reg |= tbl << IXGBE_RXIDX_TBL_SHIFT |
|
||||
idx << IXGBE_RXTXIDX_IDX_SHIFT |
|
||||
IXGBE_RXTXIDX_WRITE;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, reg);
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_set_rx_sa - set up the register bits to save SA info
|
||||
* @hw: hw specific details
|
||||
* @idx: register index to write
|
||||
* @spi: security parameter index
|
||||
* @key: key byte array
|
||||
* @salt: salt bytes
|
||||
* @mode: rx decrypt control bits
|
||||
* @ip_idx: index into IP table for related IP address
|
||||
**/
|
||||
static void ixgbe_ipsec_set_rx_sa(struct ixgbe_hw *hw, u16 idx, __be32 spi,
|
||||
u32 key[], u32 salt, u32 mode, u32 ip_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* store the SPI (in bigendian) and IPidx */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXSPI, cpu_to_le32(spi));
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPIDX, ip_idx);
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
|
||||
ixgbe_ipsec_set_rx_item(hw, idx, ips_rx_spi_tbl);
|
||||
|
||||
/* store the key, salt, and mode */
|
||||
for (i = 0; i < 4; i++)
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(i), cpu_to_be32(key[3 - i]));
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXSALT, cpu_to_be32(salt));
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXMOD, mode);
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
|
||||
ixgbe_ipsec_set_rx_item(hw, idx, ips_rx_key_tbl);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_set_rx_ip - set up the register bits to save SA IP addr info
|
||||
* @hw: hw specific details
|
||||
* @idx: register index to write
|
||||
* @addr: IP address byte array
|
||||
**/
|
||||
static void ixgbe_ipsec_set_rx_ip(struct ixgbe_hw *hw, u16 idx, __be32 addr[])
|
||||
{
|
||||
int i;
|
||||
|
||||
/* store the ip address */
|
||||
for (i = 0; i < 4; i++)
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(i), cpu_to_le32(addr[i]));
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
|
||||
ixgbe_ipsec_set_rx_item(hw, idx, ips_rx_ip_tbl);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_clear_hw_tables - because some tables don't get cleared on reset
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
static void ixgbe_ipsec_clear_hw_tables(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 buf[4] = {0, 0, 0, 0};
|
||||
u16 idx;
|
||||
|
||||
/* disable Rx and Tx SA lookup */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, 0);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, 0);
|
||||
|
||||
/* scrub the tables - split the loops for the max of the IP table */
|
||||
for (idx = 0; idx < IXGBE_IPSEC_MAX_RX_IP_COUNT; idx++) {
|
||||
ixgbe_ipsec_set_tx_sa(hw, idx, buf, 0);
|
||||
ixgbe_ipsec_set_rx_sa(hw, idx, 0, buf, 0, 0, 0);
|
||||
ixgbe_ipsec_set_rx_ip(hw, idx, (__be32 *)buf);
|
||||
}
|
||||
for (; idx < IXGBE_IPSEC_MAX_SA_COUNT; idx++) {
|
||||
ixgbe_ipsec_set_tx_sa(hw, idx, buf, 0);
|
||||
ixgbe_ipsec_set_rx_sa(hw, idx, 0, buf, 0, 0, 0);
|
||||
}
|
||||
|
||||
ipsec->num_rx_sa = 0;
|
||||
ipsec->num_tx_sa = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_stop_data
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
static void ixgbe_ipsec_stop_data(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
bool link = adapter->link_up;
|
||||
u32 t_rdy, r_rdy;
|
||||
u32 limit;
|
||||
u32 reg;
|
||||
|
||||
/* halt data paths */
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
|
||||
reg |= IXGBE_SECTXCTRL_TX_DIS;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, reg);
|
||||
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
|
||||
reg |= IXGBE_SECRXCTRL_RX_DIS;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg);
|
||||
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
|
||||
/* If the tx fifo doesn't have link, but still has data,
|
||||
* we can't clear the tx sec block. Set the MAC loopback
|
||||
* before block clear
|
||||
*/
|
||||
if (!link) {
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_MACC);
|
||||
reg |= IXGBE_MACC_FLU;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_MACC, reg);
|
||||
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
|
||||
reg |= IXGBE_HLREG0_LPBK;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg);
|
||||
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
mdelay(3);
|
||||
}
|
||||
|
||||
/* wait for the paths to empty */
|
||||
limit = 20;
|
||||
do {
|
||||
mdelay(10);
|
||||
t_rdy = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT) &
|
||||
IXGBE_SECTXSTAT_SECTX_RDY;
|
||||
r_rdy = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) &
|
||||
IXGBE_SECRXSTAT_SECRX_RDY;
|
||||
} while (!t_rdy && !r_rdy && limit--);
|
||||
|
||||
/* undo loopback if we played with it earlier */
|
||||
if (!link) {
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_MACC);
|
||||
reg &= ~IXGBE_MACC_FLU;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_MACC, reg);
|
||||
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_HLREG0);
|
||||
reg &= ~IXGBE_HLREG0_LPBK;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg);
|
||||
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_stop_engine
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
static void ixgbe_ipsec_stop_engine(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 reg;
|
||||
|
||||
ixgbe_ipsec_stop_data(adapter);
|
||||
|
||||
/* disable Rx and Tx SA lookup */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, 0);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, 0);
|
||||
|
||||
/* disable the Rx and Tx engines and full packet store-n-forward */
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
|
||||
reg |= IXGBE_SECTXCTRL_SECTX_DIS;
|
||||
reg &= ~IXGBE_SECTXCTRL_STORE_FORWARD;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, reg);
|
||||
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
|
||||
reg |= IXGBE_SECRXCTRL_SECRX_DIS;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg);
|
||||
|
||||
/* restore the "tx security buffer almost full threshold" to 0x250 */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXBUFFAF, 0x250);
|
||||
|
||||
/* Set minimum IFG between packets back to the default 0x1 */
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG);
|
||||
reg = (reg & 0xfffffff0) | 0x1;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg);
|
||||
|
||||
/* final set for normal (no ipsec offload) processing */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, IXGBE_SECTXCTRL_SECTX_DIS);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, IXGBE_SECRXCTRL_SECRX_DIS);
|
||||
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_start_engine
|
||||
* @adapter: board private structure
|
||||
*
|
||||
* NOTE: this increases power consumption whether being used or not
|
||||
**/
|
||||
static void ixgbe_ipsec_start_engine(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 reg;
|
||||
|
||||
ixgbe_ipsec_stop_data(adapter);
|
||||
|
||||
/* Set minimum IFG between packets to 3 */
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG);
|
||||
reg = (reg & 0xfffffff0) | 0x3;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg);
|
||||
|
||||
/* Set "tx security buffer almost full threshold" to 0x15 so that the
|
||||
* almost full indication is generated only after buffer contains at
|
||||
* least an entire jumbo packet.
|
||||
*/
|
||||
reg = IXGBE_READ_REG(hw, IXGBE_SECTXBUFFAF);
|
||||
reg = (reg & 0xfffffc00) | 0x15;
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXBUFFAF, reg);
|
||||
|
||||
/* restart the data paths by clearing the DISABLE bits */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, 0);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL, IXGBE_SECTXCTRL_STORE_FORWARD);
|
||||
|
||||
/* enable Rx and Tx SA lookup */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSTXIDX, IXGBE_RXTXIDX_IPS_EN);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_IPSRXIDX, IXGBE_RXTXIDX_IPS_EN);
|
||||
|
||||
IXGBE_WRITE_FLUSH(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_restore - restore the ipsec HW settings after a reset
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
int i;
|
||||
|
||||
if (!(adapter->flags2 & IXGBE_FLAG2_IPSEC_ENABLED))
|
||||
return;
|
||||
|
||||
/* clean up and restart the engine */
|
||||
ixgbe_ipsec_stop_engine(adapter);
|
||||
ixgbe_ipsec_clear_hw_tables(adapter);
|
||||
ixgbe_ipsec_start_engine(adapter);
|
||||
|
||||
/* reload the IP addrs */
|
||||
for (i = 0; i < IXGBE_IPSEC_MAX_RX_IP_COUNT; i++) {
|
||||
struct rx_ip_sa *ipsa = &ipsec->ip_tbl[i];
|
||||
|
||||
if (ipsa->used)
|
||||
ixgbe_ipsec_set_rx_ip(hw, i, ipsa->ipaddr);
|
||||
}
|
||||
|
||||
/* reload the Rx and Tx keys */
|
||||
for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
|
||||
struct rx_sa *rsa = &ipsec->rx_tbl[i];
|
||||
struct tx_sa *tsa = &ipsec->tx_tbl[i];
|
||||
|
||||
if (rsa->used)
|
||||
ixgbe_ipsec_set_rx_sa(hw, i, rsa->xs->id.spi,
|
||||
rsa->key, rsa->salt,
|
||||
rsa->mode, rsa->iptbl_ind);
|
||||
|
||||
if (tsa->used)
|
||||
ixgbe_ipsec_set_tx_sa(hw, i, tsa->key, tsa->salt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_find_empty_idx - find the first unused security parameter index
|
||||
* @ipsec: pointer to ipsec struct
|
||||
* @rxtable: true if we need to look in the Rx table
|
||||
*
|
||||
* Returns the first unused index in either the Rx or Tx SA table
|
||||
**/
|
||||
static int ixgbe_ipsec_find_empty_idx(struct ixgbe_ipsec *ipsec, bool rxtable)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
if (rxtable) {
|
||||
if (ipsec->num_rx_sa == IXGBE_IPSEC_MAX_SA_COUNT)
|
||||
return -ENOSPC;
|
||||
|
||||
/* search rx sa table */
|
||||
for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
|
||||
if (!ipsec->rx_tbl[i].used)
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
if (ipsec->num_tx_sa == IXGBE_IPSEC_MAX_SA_COUNT)
|
||||
return -ENOSPC;
|
||||
|
||||
/* search tx sa table */
|
||||
for (i = 0; i < IXGBE_IPSEC_MAX_SA_COUNT; i++) {
|
||||
if (!ipsec->tx_tbl[i].used)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_find_rx_state - find the state that matches
|
||||
* @ipsec: pointer to ipsec struct
|
||||
* @daddr: inbound address to match
|
||||
* @proto: protocol to match
|
||||
* @spi: SPI to match
|
||||
* @ip4: true if using an ipv4 address
|
||||
*
|
||||
* Returns a pointer to the matching SA state information
|
||||
**/
|
||||
static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec *ipsec,
|
||||
__be32 *daddr, u8 proto,
|
||||
__be32 spi, bool ip4)
|
||||
{
|
||||
struct rx_sa *rsa;
|
||||
struct xfrm_state *ret = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist, spi)
|
||||
if (spi == rsa->xs->id.spi &&
|
||||
((ip4 && *daddr == rsa->xs->id.daddr.a4) ||
|
||||
(!ip4 && !memcmp(daddr, &rsa->xs->id.daddr.a6,
|
||||
sizeof(rsa->xs->id.daddr.a6)))) &&
|
||||
proto == rsa->xs->id.proto) {
|
||||
ret = rsa->xs;
|
||||
xfrm_state_hold(ret);
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_parse_proto_keys - find the key and salt based on the protocol
|
||||
* @xs: pointer to xfrm_state struct
|
||||
* @mykey: pointer to key array to populate
|
||||
* @mysalt: pointer to salt value to populate
|
||||
*
|
||||
* This copies the protocol keys and salt to our own data tables. The
|
||||
* 82599 family only supports the one algorithm.
|
||||
**/
|
||||
static int ixgbe_ipsec_parse_proto_keys(struct xfrm_state *xs,
|
||||
u32 *mykey, u32 *mysalt)
|
||||
{
|
||||
struct net_device *dev = xs->xso.dev;
|
||||
unsigned char *key_data;
|
||||
char *alg_name = NULL;
|
||||
const char aes_gcm_name[] = "rfc4106(gcm(aes))";
|
||||
int key_len;
|
||||
|
||||
if (xs->aead) {
|
||||
key_data = &xs->aead->alg_key[0];
|
||||
key_len = xs->aead->alg_key_len;
|
||||
alg_name = xs->aead->alg_name;
|
||||
} else {
|
||||
netdev_err(dev, "Unsupported IPsec algorithm\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (strcmp(alg_name, aes_gcm_name)) {
|
||||
netdev_err(dev, "Unsupported IPsec algorithm - please use %s\n",
|
||||
aes_gcm_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The key bytes come down in a bigendian array of bytes, so
|
||||
* we don't need to do any byteswapping.
|
||||
* 160 accounts for 16 byte key and 4 byte salt
|
||||
*/
|
||||
if (key_len == 160) {
|
||||
*mysalt = ((u32 *)key_data)[4];
|
||||
} else if (key_len != 128) {
|
||||
netdev_err(dev, "IPsec hw offload only supports keys up to 128 bits with a 32 bit salt\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
netdev_info(dev, "IPsec hw offload parameters missing 32 bit salt value\n");
|
||||
*mysalt = 0;
|
||||
}
|
||||
memcpy(mykey, key_data, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_add_sa - program device with a security association
|
||||
* @xs: pointer to transformer state struct
|
||||
**/
|
||||
static int ixgbe_ipsec_add_sa(struct xfrm_state *xs)
|
||||
{
|
||||
struct net_device *dev = xs->xso.dev;
|
||||
struct ixgbe_adapter *adapter = netdev_priv(dev);
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
int checked, match, first;
|
||||
u16 sa_idx;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (xs->id.proto != IPPROTO_ESP && xs->id.proto != IPPROTO_AH) {
|
||||
netdev_err(dev, "Unsupported protocol 0x%04x for ipsec offload\n",
|
||||
xs->id.proto);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
|
||||
struct rx_sa rsa;
|
||||
|
||||
if (xs->calg) {
|
||||
netdev_err(dev, "Compression offload not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* find the first unused index */
|
||||
ret = ixgbe_ipsec_find_empty_idx(ipsec, true);
|
||||
if (ret < 0) {
|
||||
netdev_err(dev, "No space for SA in Rx table!\n");
|
||||
return ret;
|
||||
}
|
||||
sa_idx = (u16)ret;
|
||||
|
||||
memset(&rsa, 0, sizeof(rsa));
|
||||
rsa.used = true;
|
||||
rsa.xs = xs;
|
||||
|
||||
if (rsa.xs->id.proto & IPPROTO_ESP)
|
||||
rsa.decrypt = xs->ealg || xs->aead;
|
||||
|
||||
/* get the key and salt */
|
||||
ret = ixgbe_ipsec_parse_proto_keys(xs, rsa.key, &rsa.salt);
|
||||
if (ret) {
|
||||
netdev_err(dev, "Failed to get key data for Rx SA table\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get ip for rx sa table */
|
||||
if (xs->props.family == AF_INET6)
|
||||
memcpy(rsa.ipaddr, &xs->id.daddr.a6, 16);
|
||||
else
|
||||
memcpy(&rsa.ipaddr[3], &xs->id.daddr.a4, 4);
|
||||
|
||||
/* The HW does not have a 1:1 mapping from keys to IP addrs, so
|
||||
* check for a matching IP addr entry in the table. If the addr
|
||||
* already exists, use it; else find an unused slot and add the
|
||||
* addr. If one does not exist and there are no unused table
|
||||
* entries, fail the request.
|
||||
*/
|
||||
|
||||
/* Find an existing match or first not used, and stop looking
|
||||
* after we've checked all we know we have.
|
||||
*/
|
||||
checked = 0;
|
||||
match = -1;
|
||||
first = -1;
|
||||
for (i = 0;
|
||||
i < IXGBE_IPSEC_MAX_RX_IP_COUNT &&
|
||||
(checked < ipsec->num_rx_sa || first < 0);
|
||||
i++) {
|
||||
if (ipsec->ip_tbl[i].used) {
|
||||
if (!memcmp(ipsec->ip_tbl[i].ipaddr,
|
||||
rsa.ipaddr, sizeof(rsa.ipaddr))) {
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
checked++;
|
||||
} else if (first < 0) {
|
||||
first = i; /* track the first empty seen */
|
||||
}
|
||||
}
|
||||
|
||||
if (ipsec->num_rx_sa == 0)
|
||||
first = 0;
|
||||
|
||||
if (match >= 0) {
|
||||
/* addrs are the same, we should use this one */
|
||||
rsa.iptbl_ind = match;
|
||||
ipsec->ip_tbl[match].ref_cnt++;
|
||||
|
||||
} else if (first >= 0) {
|
||||
/* no matches, but here's an empty slot */
|
||||
rsa.iptbl_ind = first;
|
||||
|
||||
memcpy(ipsec->ip_tbl[first].ipaddr,
|
||||
rsa.ipaddr, sizeof(rsa.ipaddr));
|
||||
ipsec->ip_tbl[first].ref_cnt = 1;
|
||||
ipsec->ip_tbl[first].used = true;
|
||||
|
||||
ixgbe_ipsec_set_rx_ip(hw, rsa.iptbl_ind, rsa.ipaddr);
|
||||
|
||||
} else {
|
||||
/* no match and no empty slot */
|
||||
netdev_err(dev, "No space for SA in Rx IP SA table\n");
|
||||
memset(&rsa, 0, sizeof(rsa));
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
rsa.mode = IXGBE_RXMOD_VALID;
|
||||
if (rsa.xs->id.proto & IPPROTO_ESP)
|
||||
rsa.mode |= IXGBE_RXMOD_PROTO_ESP;
|
||||
if (rsa.decrypt)
|
||||
rsa.mode |= IXGBE_RXMOD_DECRYPT;
|
||||
if (rsa.xs->props.family == AF_INET6)
|
||||
rsa.mode |= IXGBE_RXMOD_IPV6;
|
||||
|
||||
/* the preparations worked, so save the info */
|
||||
memcpy(&ipsec->rx_tbl[sa_idx], &rsa, sizeof(rsa));
|
||||
|
||||
ixgbe_ipsec_set_rx_sa(hw, sa_idx, rsa.xs->id.spi, rsa.key,
|
||||
rsa.salt, rsa.mode, rsa.iptbl_ind);
|
||||
xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_RX_INDEX;
|
||||
|
||||
ipsec->num_rx_sa++;
|
||||
|
||||
/* hash the new entry for faster search in Rx path */
|
||||
hash_add_rcu(ipsec->rx_sa_list, &ipsec->rx_tbl[sa_idx].hlist,
|
||||
rsa.xs->id.spi);
|
||||
} else {
|
||||
struct tx_sa tsa;
|
||||
|
||||
/* find the first unused index */
|
||||
ret = ixgbe_ipsec_find_empty_idx(ipsec, false);
|
||||
if (ret < 0) {
|
||||
netdev_err(dev, "No space for SA in Tx table\n");
|
||||
return ret;
|
||||
}
|
||||
sa_idx = (u16)ret;
|
||||
|
||||
memset(&tsa, 0, sizeof(tsa));
|
||||
tsa.used = true;
|
||||
tsa.xs = xs;
|
||||
|
||||
if (xs->id.proto & IPPROTO_ESP)
|
||||
tsa.encrypt = xs->ealg || xs->aead;
|
||||
|
||||
ret = ixgbe_ipsec_parse_proto_keys(xs, tsa.key, &tsa.salt);
|
||||
if (ret) {
|
||||
netdev_err(dev, "Failed to get key data for Tx SA table\n");
|
||||
memset(&tsa, 0, sizeof(tsa));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* the preparations worked, so save the info */
|
||||
memcpy(&ipsec->tx_tbl[sa_idx], &tsa, sizeof(tsa));
|
||||
|
||||
ixgbe_ipsec_set_tx_sa(hw, sa_idx, tsa.key, tsa.salt);
|
||||
|
||||
xs->xso.offload_handle = sa_idx + IXGBE_IPSEC_BASE_TX_INDEX;
|
||||
|
||||
ipsec->num_tx_sa++;
|
||||
}
|
||||
|
||||
/* enable the engine if not already warmed up */
|
||||
if (!(adapter->flags2 & IXGBE_FLAG2_IPSEC_ENABLED)) {
|
||||
ixgbe_ipsec_start_engine(adapter);
|
||||
adapter->flags2 |= IXGBE_FLAG2_IPSEC_ENABLED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_del_sa - clear out this specific SA
|
||||
* @xs: pointer to transformer state struct
|
||||
**/
|
||||
static void ixgbe_ipsec_del_sa(struct xfrm_state *xs)
|
||||
{
|
||||
struct net_device *dev = xs->xso.dev;
|
||||
struct ixgbe_adapter *adapter = netdev_priv(dev);
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 zerobuf[4] = {0, 0, 0, 0};
|
||||
u16 sa_idx;
|
||||
|
||||
if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
|
||||
struct rx_sa *rsa;
|
||||
u8 ipi;
|
||||
|
||||
sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_RX_INDEX;
|
||||
rsa = &ipsec->rx_tbl[sa_idx];
|
||||
|
||||
if (!rsa->used) {
|
||||
netdev_err(dev, "Invalid Rx SA selected sa_idx=%d offload_handle=%lu\n",
|
||||
sa_idx, xs->xso.offload_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
ixgbe_ipsec_set_rx_sa(hw, sa_idx, 0, zerobuf, 0, 0, 0);
|
||||
hash_del_rcu(&rsa->hlist);
|
||||
|
||||
/* if the IP table entry is referenced by only this SA,
|
||||
* i.e. ref_cnt is only 1, clear the IP table entry as well
|
||||
*/
|
||||
ipi = rsa->iptbl_ind;
|
||||
if (ipsec->ip_tbl[ipi].ref_cnt > 0) {
|
||||
ipsec->ip_tbl[ipi].ref_cnt--;
|
||||
|
||||
if (!ipsec->ip_tbl[ipi].ref_cnt) {
|
||||
memset(&ipsec->ip_tbl[ipi], 0,
|
||||
sizeof(struct rx_ip_sa));
|
||||
ixgbe_ipsec_set_rx_ip(hw, ipi, zerobuf);
|
||||
}
|
||||
}
|
||||
|
||||
memset(rsa, 0, sizeof(struct rx_sa));
|
||||
ipsec->num_rx_sa--;
|
||||
} else {
|
||||
sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
|
||||
|
||||
if (!ipsec->tx_tbl[sa_idx].used) {
|
||||
netdev_err(dev, "Invalid Tx SA selected sa_idx=%d offload_handle=%lu\n",
|
||||
sa_idx, xs->xso.offload_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
ixgbe_ipsec_set_tx_sa(hw, sa_idx, zerobuf, 0);
|
||||
memset(&ipsec->tx_tbl[sa_idx], 0, sizeof(struct tx_sa));
|
||||
ipsec->num_tx_sa--;
|
||||
}
|
||||
|
||||
/* if there are no SAs left, stop the engine to save energy */
|
||||
if (ipsec->num_rx_sa == 0 && ipsec->num_tx_sa == 0) {
|
||||
adapter->flags2 &= ~IXGBE_FLAG2_IPSEC_ENABLED;
|
||||
ixgbe_ipsec_stop_engine(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_offload_ok - can this packet use the xfrm hw offload
|
||||
* @skb: current data packet
|
||||
* @xs: pointer to transformer state struct
|
||||
**/
|
||||
static bool ixgbe_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
|
||||
{
|
||||
if (xs->props.family == AF_INET) {
|
||||
/* Offload with IPv4 options is not supported yet */
|
||||
if (ip_hdr(skb)->ihl != 5)
|
||||
return false;
|
||||
} else {
|
||||
/* Offload with IPv6 extension headers is not support yet */
|
||||
if (ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_free - called by xfrm garbage collections
|
||||
* @xs: pointer to transformer state struct
|
||||
*
|
||||
* We don't have any garbage to collect, so we shouldn't bother
|
||||
* implementing this function, but the XFRM code doesn't check for
|
||||
* existence before calling the API callback.
|
||||
**/
|
||||
static void ixgbe_ipsec_free(struct xfrm_state *xs)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct xfrmdev_ops ixgbe_xfrmdev_ops = {
|
||||
.xdo_dev_state_add = ixgbe_ipsec_add_sa,
|
||||
.xdo_dev_state_delete = ixgbe_ipsec_del_sa,
|
||||
.xdo_dev_offload_ok = ixgbe_ipsec_offload_ok,
|
||||
.xdo_dev_state_free = ixgbe_ipsec_free,
|
||||
};
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_tx - setup Tx flags for ipsec offload
|
||||
* @tx_ring: outgoing context
|
||||
* @first: current data packet
|
||||
* @itd: ipsec Tx data for later use in building context descriptor
|
||||
**/
|
||||
int ixgbe_ipsec_tx(struct ixgbe_ring *tx_ring,
|
||||
struct ixgbe_tx_buffer *first,
|
||||
struct ixgbe_ipsec_tx_data *itd)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = netdev_priv(tx_ring->netdev);
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
struct xfrm_state *xs;
|
||||
struct tx_sa *tsa;
|
||||
|
||||
if (unlikely(!first->skb->sp->len)) {
|
||||
netdev_err(tx_ring->netdev, "%s: no xfrm state len = %d\n",
|
||||
__func__, first->skb->sp->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xs = xfrm_input_state(first->skb);
|
||||
if (unlikely(!xs)) {
|
||||
netdev_err(tx_ring->netdev, "%s: no xfrm_input_state() xs = %p\n",
|
||||
__func__, xs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
itd->sa_idx = xs->xso.offload_handle - IXGBE_IPSEC_BASE_TX_INDEX;
|
||||
if (unlikely(itd->sa_idx > IXGBE_IPSEC_MAX_SA_COUNT)) {
|
||||
netdev_err(tx_ring->netdev, "%s: bad sa_idx=%d handle=%lu\n",
|
||||
__func__, itd->sa_idx, xs->xso.offload_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tsa = &ipsec->tx_tbl[itd->sa_idx];
|
||||
if (unlikely(!tsa->used)) {
|
||||
netdev_err(tx_ring->netdev, "%s: unused sa_idx=%d\n",
|
||||
__func__, itd->sa_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
first->tx_flags |= IXGBE_TX_FLAGS_IPSEC | IXGBE_TX_FLAGS_CC;
|
||||
|
||||
itd->flags = 0;
|
||||
if (xs->id.proto == IPPROTO_ESP) {
|
||||
itd->flags |= IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP |
|
||||
IXGBE_ADVTXD_TUCMD_L4T_TCP;
|
||||
if (first->protocol == htons(ETH_P_IP))
|
||||
itd->flags |= IXGBE_ADVTXD_TUCMD_IPV4;
|
||||
itd->trailer_len = xs->props.trailer_len;
|
||||
}
|
||||
if (tsa->encrypt)
|
||||
itd->flags |= IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_ipsec_rx - decode ipsec bits from Rx descriptor
|
||||
* @rx_ring: receiving ring
|
||||
* @rx_desc: receive data descriptor
|
||||
* @skb: current data packet
|
||||
*
|
||||
* Determine if there was an ipsec encapsulation noticed, and if so set up
|
||||
* the resulting status for later in the receive stack.
|
||||
**/
|
||||
void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
|
||||
union ixgbe_adv_rx_desc *rx_desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = netdev_priv(rx_ring->netdev);
|
||||
__le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
|
||||
__le16 ipsec_pkt_types = cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH |
|
||||
IXGBE_RXDADV_PKTTYPE_IPSEC_ESP);
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
struct xfrm_offload *xo = NULL;
|
||||
struct xfrm_state *xs = NULL;
|
||||
struct ipv6hdr *ip6 = NULL;
|
||||
struct iphdr *ip4 = NULL;
|
||||
void *daddr;
|
||||
__be32 spi;
|
||||
u8 *c_hdr;
|
||||
u8 proto;
|
||||
|
||||
/* Find the ip and crypto headers in the data.
|
||||
* We can assume no vlan header in the way, b/c the
|
||||
* hw won't recognize the IPsec packet and anyway the
|
||||
* currently vlan device doesn't support xfrm offload.
|
||||
*/
|
||||
if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV4)) {
|
||||
ip4 = (struct iphdr *)(skb->data + ETH_HLEN);
|
||||
daddr = &ip4->daddr;
|
||||
c_hdr = (u8 *)ip4 + ip4->ihl * 4;
|
||||
} else if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV6)) {
|
||||
ip6 = (struct ipv6hdr *)(skb->data + ETH_HLEN);
|
||||
daddr = &ip6->daddr;
|
||||
c_hdr = (u8 *)ip6 + sizeof(struct ipv6hdr);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pkt_info & ipsec_pkt_types) {
|
||||
case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH):
|
||||
spi = ((struct ip_auth_hdr *)c_hdr)->spi;
|
||||
proto = IPPROTO_AH;
|
||||
break;
|
||||
case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_ESP):
|
||||
spi = ((struct ip_esp_hdr *)c_hdr)->spi;
|
||||
proto = IPPROTO_ESP;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
xs = ixgbe_ipsec_find_rx_state(ipsec, daddr, proto, spi, !!ip4);
|
||||
if (unlikely(!xs))
|
||||
return;
|
||||
|
||||
skb->sp = secpath_dup(skb->sp);
|
||||
if (unlikely(!skb->sp))
|
||||
return;
|
||||
|
||||
skb->sp->xvec[skb->sp->len++] = xs;
|
||||
skb->sp->olen++;
|
||||
xo = xfrm_offload(skb);
|
||||
xo->flags = CRYPTO_DONE;
|
||||
xo->status = CRYPTO_SUCCESS;
|
||||
|
||||
adapter->rx_ipsec++;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_init_ipsec_offload - initialize security registers for IPSec operation
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_ipsec *ipsec;
|
||||
size_t size;
|
||||
|
||||
if (adapter->hw.mac.type == ixgbe_mac_82598EB)
|
||||
return;
|
||||
|
||||
ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL);
|
||||
if (!ipsec)
|
||||
goto err1;
|
||||
hash_init(ipsec->rx_sa_list);
|
||||
|
||||
size = sizeof(struct rx_sa) * IXGBE_IPSEC_MAX_SA_COUNT;
|
||||
ipsec->rx_tbl = kzalloc(size, GFP_KERNEL);
|
||||
if (!ipsec->rx_tbl)
|
||||
goto err2;
|
||||
|
||||
size = sizeof(struct tx_sa) * IXGBE_IPSEC_MAX_SA_COUNT;
|
||||
ipsec->tx_tbl = kzalloc(size, GFP_KERNEL);
|
||||
if (!ipsec->tx_tbl)
|
||||
goto err2;
|
||||
|
||||
size = sizeof(struct rx_ip_sa) * IXGBE_IPSEC_MAX_RX_IP_COUNT;
|
||||
ipsec->ip_tbl = kzalloc(size, GFP_KERNEL);
|
||||
if (!ipsec->ip_tbl)
|
||||
goto err2;
|
||||
|
||||
ipsec->num_rx_sa = 0;
|
||||
ipsec->num_tx_sa = 0;
|
||||
|
||||
adapter->ipsec = ipsec;
|
||||
ixgbe_ipsec_stop_engine(adapter);
|
||||
ixgbe_ipsec_clear_hw_tables(adapter);
|
||||
|
||||
adapter->netdev->xfrmdev_ops = &ixgbe_xfrmdev_ops;
|
||||
adapter->netdev->features |= NETIF_F_HW_ESP;
|
||||
adapter->netdev->hw_enc_features |= NETIF_F_HW_ESP;
|
||||
|
||||
return;
|
||||
|
||||
err2:
|
||||
kfree(ipsec->ip_tbl);
|
||||
kfree(ipsec->rx_tbl);
|
||||
kfree(ipsec->tx_tbl);
|
||||
err1:
|
||||
kfree(adapter->ipsec);
|
||||
netdev_err(adapter->netdev, "Unable to allocate memory for SA tables");
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_stop_ipsec_offload - tear down the ipsec offload
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct ixgbe_ipsec *ipsec = adapter->ipsec;
|
||||
|
||||
adapter->ipsec = NULL;
|
||||
if (ipsec) {
|
||||
kfree(ipsec->ip_tbl);
|
||||
kfree(ipsec->rx_tbl);
|
||||
kfree(ipsec->tx_tbl);
|
||||
kfree(ipsec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Intel 10 Gigabit PCI Express Linux driver
|
||||
Copyright(c) 2017 Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Contact Information:
|
||||
Linux NICS <linux.nics@intel.com>
|
||||
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
|
||||
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _IXGBE_IPSEC_H_
|
||||
#define _IXGBE_IPSEC_H_
|
||||
|
||||
#define IXGBE_IPSEC_MAX_SA_COUNT 1024
|
||||
#define IXGBE_IPSEC_MAX_RX_IP_COUNT 128
|
||||
#define IXGBE_IPSEC_BASE_RX_INDEX 0
|
||||
#define IXGBE_IPSEC_BASE_TX_INDEX IXGBE_IPSEC_MAX_SA_COUNT
|
||||
|
||||
#define IXGBE_RXTXIDX_IPS_EN 0x00000001
|
||||
#define IXGBE_RXIDX_TBL_SHIFT 1
|
||||
enum ixgbe_ipsec_tbl_sel {
|
||||
ips_rx_ip_tbl = 0x01,
|
||||
ips_rx_spi_tbl = 0x02,
|
||||
ips_rx_key_tbl = 0x03,
|
||||
};
|
||||
|
||||
#define IXGBE_RXTXIDX_IDX_SHIFT 3
|
||||
#define IXGBE_RXTXIDX_READ 0x40000000
|
||||
#define IXGBE_RXTXIDX_WRITE 0x80000000
|
||||
|
||||
#define IXGBE_RXMOD_VALID 0x00000001
|
||||
#define IXGBE_RXMOD_PROTO_ESP 0x00000004
|
||||
#define IXGBE_RXMOD_DECRYPT 0x00000008
|
||||
#define IXGBE_RXMOD_IPV6 0x00000010
|
||||
|
||||
struct rx_sa {
|
||||
struct hlist_node hlist;
|
||||
struct xfrm_state *xs;
|
||||
__be32 ipaddr[4];
|
||||
u32 key[4];
|
||||
u32 salt;
|
||||
u32 mode;
|
||||
u8 iptbl_ind;
|
||||
bool used;
|
||||
bool decrypt;
|
||||
};
|
||||
|
||||
struct rx_ip_sa {
|
||||
__be32 ipaddr[4];
|
||||
u32 ref_cnt;
|
||||
bool used;
|
||||
};
|
||||
|
||||
struct tx_sa {
|
||||
struct xfrm_state *xs;
|
||||
u32 key[4];
|
||||
u32 salt;
|
||||
bool encrypt;
|
||||
bool used;
|
||||
};
|
||||
|
||||
struct ixgbe_ipsec_tx_data {
|
||||
u32 flags;
|
||||
u16 trailer_len;
|
||||
u16 sa_idx;
|
||||
};
|
||||
|
||||
struct ixgbe_ipsec {
|
||||
u16 num_rx_sa;
|
||||
u16 num_tx_sa;
|
||||
struct rx_ip_sa *ip_tbl;
|
||||
struct rx_sa *rx_tbl;
|
||||
struct tx_sa *tx_tbl;
|
||||
DECLARE_HASHTABLE(rx_sa_list, 10);
|
||||
};
|
||||
#endif /* _IXGBE_IPSEC_H_ */
|
|
@ -1282,7 +1282,7 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
|
|||
}
|
||||
|
||||
void ixgbe_tx_ctxtdesc(struct ixgbe_ring *tx_ring, u32 vlan_macip_lens,
|
||||
u32 fcoe_sof_eof, u32 type_tucmd, u32 mss_l4len_idx)
|
||||
u32 fceof_saidx, u32 type_tucmd, u32 mss_l4len_idx)
|
||||
{
|
||||
struct ixgbe_adv_tx_context_desc *context_desc;
|
||||
u16 i = tx_ring->next_to_use;
|
||||
|
@ -1296,7 +1296,7 @@ void ixgbe_tx_ctxtdesc(struct ixgbe_ring *tx_ring, u32 vlan_macip_lens,
|
|||
type_tucmd |= IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT;
|
||||
|
||||
context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
|
||||
context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof);
|
||||
context_desc->fceof_saidx = cpu_to_le32(fceof_saidx);
|
||||
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
|
||||
context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
|
||||
}
|
||||
|
|
|
@ -1171,7 +1171,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
|
|||
struct ixgbe_adapter *adapter = q_vector->adapter;
|
||||
struct ixgbe_tx_buffer *tx_buffer;
|
||||
union ixgbe_adv_tx_desc *tx_desc;
|
||||
unsigned int total_bytes = 0, total_packets = 0;
|
||||
unsigned int total_bytes = 0, total_packets = 0, total_ipsec = 0;
|
||||
unsigned int budget = q_vector->tx.work_limit;
|
||||
unsigned int i = tx_ring->next_to_clean;
|
||||
|
||||
|
@ -1202,6 +1202,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
|
|||
/* update the statistics for this packet */
|
||||
total_bytes += tx_buffer->bytecount;
|
||||
total_packets += tx_buffer->gso_segs;
|
||||
if (tx_buffer->tx_flags & IXGBE_TX_FLAGS_IPSEC)
|
||||
total_ipsec++;
|
||||
|
||||
/* free the skb */
|
||||
if (ring_is_xdp(tx_ring))
|
||||
|
@ -1264,6 +1266,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
|
|||
u64_stats_update_end(&tx_ring->syncp);
|
||||
q_vector->tx.total_bytes += total_bytes;
|
||||
q_vector->tx.total_packets += total_packets;
|
||||
adapter->tx_ipsec += total_ipsec;
|
||||
|
||||
if (check_for_tx_hang(tx_ring) && ixgbe_check_tx_hang(tx_ring)) {
|
||||
/* schedule immediate reset if we believe we hung */
|
||||
|
@ -1752,6 +1755,9 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
|
|||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
|
||||
}
|
||||
|
||||
if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_SECP))
|
||||
ixgbe_ipsec_rx(rx_ring, rx_desc, skb);
|
||||
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
|
||||
/* record Rx queue, or update MACVLAN statistics */
|
||||
|
@ -5425,6 +5431,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
|
|||
|
||||
ixgbe_set_rx_mode(adapter->netdev);
|
||||
ixgbe_restore_vlan(adapter);
|
||||
ixgbe_ipsec_restore(adapter);
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case ixgbe_mac_82599EB:
|
||||
|
@ -7795,10 +7802,12 @@ static inline bool ixgbe_ipv6_csum_is_sctp(struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
|
||||
struct ixgbe_tx_buffer *first)
|
||||
struct ixgbe_tx_buffer *first,
|
||||
struct ixgbe_ipsec_tx_data *itd)
|
||||
{
|
||||
struct sk_buff *skb = first->skb;
|
||||
u32 vlan_macip_lens = 0;
|
||||
u32 fceof_saidx = 0;
|
||||
u32 type_tucmd = 0;
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
|
@ -7839,7 +7848,12 @@ no_csum:
|
|||
vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
|
||||
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
|
||||
|
||||
ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0, type_tucmd, 0);
|
||||
if (first->tx_flags & IXGBE_TX_FLAGS_IPSEC) {
|
||||
fceof_saidx |= itd->sa_idx;
|
||||
type_tucmd |= itd->flags | itd->trailer_len;
|
||||
}
|
||||
|
||||
ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, fceof_saidx, type_tucmd, 0);
|
||||
}
|
||||
|
||||
#define IXGBE_SET_FLAG(_input, _flag, _result) \
|
||||
|
@ -7882,11 +7896,16 @@ static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
|
|||
IXGBE_TX_FLAGS_CSUM,
|
||||
IXGBE_ADVTXD_POPTS_TXSM);
|
||||
|
||||
/* enble IPv4 checksum for TSO */
|
||||
/* enable IPv4 checksum for TSO */
|
||||
olinfo_status |= IXGBE_SET_FLAG(tx_flags,
|
||||
IXGBE_TX_FLAGS_IPV4,
|
||||
IXGBE_ADVTXD_POPTS_IXSM);
|
||||
|
||||
/* enable IPsec */
|
||||
olinfo_status |= IXGBE_SET_FLAG(tx_flags,
|
||||
IXGBE_TX_FLAGS_IPSEC,
|
||||
IXGBE_ADVTXD_POPTS_IPSEC);
|
||||
|
||||
/*
|
||||
* Check Context must be set if Tx switch is enabled, which it
|
||||
* always is for case where virtual functions are running
|
||||
|
@ -8350,6 +8369,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
|
|||
u32 tx_flags = 0;
|
||||
unsigned short f;
|
||||
u16 count = TXD_USE_COUNT(skb_headlen(skb));
|
||||
struct ixgbe_ipsec_tx_data ipsec_tx = { 0 };
|
||||
__be16 protocol = skb->protocol;
|
||||
u8 hdr_len = 0;
|
||||
|
||||
|
@ -8454,11 +8474,16 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
#endif /* IXGBE_FCOE */
|
||||
|
||||
#ifdef CONFIG_XFRM_OFFLOAD
|
||||
if (skb->sp && !ixgbe_ipsec_tx(tx_ring, first, &ipsec_tx))
|
||||
goto out_drop;
|
||||
#endif
|
||||
tso = ixgbe_tso(tx_ring, first, &hdr_len);
|
||||
if (tso < 0)
|
||||
goto out_drop;
|
||||
else if (!tso)
|
||||
ixgbe_tx_csum(tx_ring, first);
|
||||
ixgbe_tx_csum(tx_ring, first, &ipsec_tx);
|
||||
|
||||
/* add the ATR filter if ATR is on */
|
||||
if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
|
||||
|
@ -9870,6 +9895,12 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev,
|
|||
if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID))
|
||||
features &= ~NETIF_F_TSO;
|
||||
|
||||
#ifdef CONFIG_XFRM_OFFLOAD
|
||||
/* IPsec offload doesn't get along well with others *yet* */
|
||||
if (skb->sp)
|
||||
features &= ~(NETIF_F_TSO | NETIF_F_HW_CSUM);
|
||||
#endif
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
|
@ -10459,6 +10490,7 @@ skip_sriov:
|
|||
NETIF_F_FCOE_MTU;
|
||||
}
|
||||
#endif /* IXGBE_FCOE */
|
||||
ixgbe_init_ipsec_offload(adapter);
|
||||
|
||||
if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)
|
||||
netdev->hw_features |= NETIF_F_LRO;
|
||||
|
@ -10694,6 +10726,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
|
|||
if (netdev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdev(netdev);
|
||||
|
||||
ixgbe_stop_ipsec_offload(adapter);
|
||||
ixgbe_clear_interrupt_scheme(adapter);
|
||||
|
||||
ixgbe_release_hw_control(adapter);
|
||||
|
|
|
@ -2360,11 +2360,6 @@ enum {
|
|||
#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
|
||||
#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */
|
||||
|
||||
#define IXGBE_RXDADV_IPSEC_STATUS_SECP 0x00020000
|
||||
#define IXGBE_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL 0x08000000
|
||||
#define IXGBE_RXDADV_IPSEC_ERROR_INVALID_LENGTH 0x10000000
|
||||
#define IXGBE_RXDADV_IPSEC_ERROR_AUTH_FAILED 0x18000000
|
||||
#define IXGBE_RXDADV_IPSEC_ERROR_BIT_MASK 0x18000000
|
||||
/* Multiple Transmit Queue Command Register */
|
||||
#define IXGBE_MTQC_RT_ENA 0x1 /* DCB Enable */
|
||||
#define IXGBE_MTQC_VT_ENA 0x2 /* VMDQ2 Enable */
|
||||
|
@ -2416,6 +2411,9 @@ enum {
|
|||
#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */
|
||||
#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */
|
||||
#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */
|
||||
#define IXGBE_RXDADV_ERR_IPSEC_INV_PROTOCOL 0x08000000 /* overlap ERR_PE */
|
||||
#define IXGBE_RXDADV_ERR_IPSEC_INV_LENGTH 0x10000000 /* overlap ERR_OSE */
|
||||
#define IXGBE_RXDADV_ERR_IPSEC_AUTH_FAILED 0x18000000
|
||||
#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */
|
||||
#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */
|
||||
#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */
|
||||
|
@ -2437,6 +2435,7 @@ enum {
|
|||
#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */
|
||||
#define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */
|
||||
#define IXGBE_RXDADV_STAT_TS 0x00010000 /* IEEE 1588 Time Stamp */
|
||||
#define IXGBE_RXDADV_STAT_SECP 0x00020000 /* IPsec/MACsec pkt found */
|
||||
|
||||
/* PSRTYPE bit definitions */
|
||||
#define IXGBE_PSRTYPE_TCPHDR 0x00000010
|
||||
|
@ -2503,13 +2502,6 @@ enum {
|
|||
#define IXGBE_RXDADV_PKTTYPE_ETQF_MASK 0x00000070 /* ETQF has 8 indices */
|
||||
#define IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT 4 /* Right-shift 4 bits */
|
||||
|
||||
/* Security Processing bit Indication */
|
||||
#define IXGBE_RXDADV_LNKSEC_STATUS_SECP 0x00020000
|
||||
#define IXGBE_RXDADV_LNKSEC_ERROR_NO_SA_MATCH 0x08000000
|
||||
#define IXGBE_RXDADV_LNKSEC_ERROR_REPLAY_ERROR 0x10000000
|
||||
#define IXGBE_RXDADV_LNKSEC_ERROR_BIT_MASK 0x18000000
|
||||
#define IXGBE_RXDADV_LNKSEC_ERROR_BAD_SIG 0x18000000
|
||||
|
||||
/* Masks to determine if packets should be dropped due to frame errors */
|
||||
#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \
|
||||
IXGBE_RXD_ERR_CE | \
|
||||
|
@ -2523,6 +2515,8 @@ enum {
|
|||
IXGBE_RXDADV_ERR_LE | \
|
||||
IXGBE_RXDADV_ERR_PE | \
|
||||
IXGBE_RXDADV_ERR_OSE | \
|
||||
IXGBE_RXDADV_ERR_IPSEC_INV_PROTOCOL | \
|
||||
IXGBE_RXDADV_ERR_IPSEC_INV_LENGTH | \
|
||||
IXGBE_RXDADV_ERR_USE)
|
||||
|
||||
/* Multicast bit mask */
|
||||
|
@ -2901,7 +2895,7 @@ union ixgbe_adv_rx_desc {
|
|||
/* Context descriptors */
|
||||
struct ixgbe_adv_tx_context_desc {
|
||||
__le32 vlan_macip_lens;
|
||||
__le32 seqnum_seed;
|
||||
__le32 fceof_saidx;
|
||||
__le32 type_tucmd_mlhl;
|
||||
__le32 mss_l4len_idx;
|
||||
};
|
||||
|
@ -2932,6 +2926,7 @@ struct ixgbe_adv_tx_context_desc {
|
|||
IXGBE_ADVTXD_POPTS_SHIFT)
|
||||
#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
|
||||
IXGBE_ADVTXD_POPTS_SHIFT)
|
||||
#define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */
|
||||
#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */
|
||||
#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */
|
||||
#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
|
||||
|
@ -2947,7 +2942,6 @@ struct ixgbe_adv_tx_context_desc {
|
|||
#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */
|
||||
#define IXGBE_ADVTXD_TUCMD_L4T_RSV 0x00001800 /* RSV L4 Packet TYPE */
|
||||
#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /*Req requires Markers and CRC*/
|
||||
#define IXGBE_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */
|
||||
#define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
|
||||
#define IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000/* ESP Encrypt Enable */
|
||||
#define IXGBE_ADVTXT_TUCMD_FCOE 0x00008000 /* FCoE Frame Type */
|
||||
|
|
Loading…
Reference in New Issue