Commit b4fb2d33 authored by Joe Damato's avatar Joe Damato Committed by Tony Nguyen

i40e: Add support for MPLS + TSO

This change adds support for TSO of MPLS packets.

In my tests with tcpdump it seems to work. Note this test setup has
a 9000 byte MTU:

MPLS (label 100, exp 0, [S], ttl 64) IP srcip.50086 > dstip.1234:
  Flags [P.], seq 593345:644401, ack 0, win 420,
  options [nop,nop,TS val 45022534 ecr 1722291395], length 51056

IP dstip.1234 > srcip.50086: Flags [.], ack 593345, win 122,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0

IP dstip.1234 > srcip.50086: Flags [.], ack 602289, win 105,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0

IP dstip.1234 > srcip.50086: Flags [.], ack 620177, win 71,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0

MPLS (label 100, exp 0, [S], ttl 64) IP srcip.50086 > dstip.1234:
  Flags [P.], seq 644401:655953, ack 0, win 420,
  options [nop,nop,TS val 45022534 ecr 1722291395], length 11552

IP dstip.1234 > srcip.50086: Flags [.], ack 638065, win 37,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0

IP dstip.1234 > srcip.50086: Flags [.], ack 644401, win 25,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0

IP dstip.1234 > srcip.50086: Flags [.], ack 653345, win 8,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0

IP dstip.1234 > srcip.50086: Flags [.], ack 655953, win 3,
  options [nop,nop,TS val 1722291395 ecr 45022534], length 0
Signed-off-by: default avatarJoe Damato <jdamato@fastly.com>
Co-developed-by: default avatarMike Gallo <mgallo@fastly.com>
Signed-off-by: default avatarMike Gallo <mgallo@fastly.com>
Tested-by: Gurucharan <gurucharanx.g@intel.com> (A Contingent worker at Intel)
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 590032a4
...@@ -13436,8 +13436,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) ...@@ -13436,8 +13436,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
np->vsi = vsi; np->vsi = vsi;
hw_enc_features = NETIF_F_SG | hw_enc_features = NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_HW_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_HIGHDMA | NETIF_F_HIGHDMA |
NETIF_F_SOFT_FEATURES | NETIF_F_SOFT_FEATURES |
NETIF_F_TSO | NETIF_F_TSO |
...@@ -13468,6 +13467,23 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) ...@@ -13468,6 +13467,23 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
/* record features VLANs can make use of */ /* record features VLANs can make use of */
netdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID; netdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID;
#define I40E_GSO_PARTIAL_FEATURES (NETIF_F_GSO_GRE | \
NETIF_F_GSO_GRE_CSUM | \
NETIF_F_GSO_IPXIP4 | \
NETIF_F_GSO_IPXIP6 | \
NETIF_F_GSO_UDP_TUNNEL | \
NETIF_F_GSO_UDP_TUNNEL_CSUM)
netdev->gso_partial_features = I40E_GSO_PARTIAL_FEATURES;
netdev->features |= NETIF_F_GSO_PARTIAL |
I40E_GSO_PARTIAL_FEATURES;
netdev->mpls_features |= NETIF_F_SG;
netdev->mpls_features |= NETIF_F_HW_CSUM;
netdev->mpls_features |= NETIF_F_TSO;
netdev->mpls_features |= NETIF_F_TSO6;
netdev->mpls_features |= I40E_GSO_PARTIAL_FEATURES;
/* enable macvlan offloads */ /* enable macvlan offloads */
netdev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD; netdev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/bpf_trace.h> #include <linux/bpf_trace.h>
#include <net/mpls.h>
#include <net/xdp.h> #include <net/xdp.h>
#include "i40e.h" #include "i40e.h"
#include "i40e_trace.h" #include "i40e_trace.h"
...@@ -3015,6 +3016,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, ...@@ -3015,6 +3016,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
{ {
struct sk_buff *skb = first->skb; struct sk_buff *skb = first->skb;
u64 cd_cmd, cd_tso_len, cd_mss; u64 cd_cmd, cd_tso_len, cd_mss;
__be16 protocol;
union { union {
struct iphdr *v4; struct iphdr *v4;
struct ipv6hdr *v6; struct ipv6hdr *v6;
...@@ -3026,7 +3028,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, ...@@ -3026,7 +3028,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
unsigned char *hdr; unsigned char *hdr;
} l4; } l4;
u32 paylen, l4_offset; u32 paylen, l4_offset;
u16 gso_segs, gso_size; u16 gso_size;
int err; int err;
if (skb->ip_summed != CHECKSUM_PARTIAL) if (skb->ip_summed != CHECKSUM_PARTIAL)
...@@ -3039,15 +3041,23 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, ...@@ -3039,15 +3041,23 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
if (err < 0) if (err < 0)
return err; return err;
protocol = vlan_get_protocol(skb);
if (eth_p_mpls(protocol))
ip.hdr = skb_inner_network_header(skb);
else
ip.hdr = skb_network_header(skb); ip.hdr = skb_network_header(skb);
l4.hdr = skb_transport_header(skb); l4.hdr = skb_checksum_start(skb);
/* initialize outer IP header fields */ /* initialize outer IP header fields */
if (ip.v4->version == 4) { if (ip.v4->version == 4) {
ip.v4->tot_len = 0; ip.v4->tot_len = 0;
ip.v4->check = 0; ip.v4->check = 0;
first->tx_flags |= I40E_TX_FLAGS_TSO;
} else { } else {
ip.v6->payload_len = 0; ip.v6->payload_len = 0;
first->tx_flags |= I40E_TX_FLAGS_TSO;
} }
if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE | if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE |
...@@ -3100,10 +3110,9 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, ...@@ -3100,10 +3110,9 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
/* pull values out of skb_shinfo */ /* pull values out of skb_shinfo */
gso_size = skb_shinfo(skb)->gso_size; gso_size = skb_shinfo(skb)->gso_size;
gso_segs = skb_shinfo(skb)->gso_segs;
/* update GSO size and bytecount with header size */ /* update GSO size and bytecount with header size */
first->gso_segs = gso_segs; first->gso_segs = skb_shinfo(skb)->gso_segs;
first->bytecount += (first->gso_segs - 1) * *hdr_len; first->bytecount += (first->gso_segs - 1) * *hdr_len;
/* find the field values */ /* find the field values */
...@@ -3187,13 +3196,27 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, ...@@ -3187,13 +3196,27 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
unsigned char *exthdr; unsigned char *exthdr;
u32 offset, cmd = 0; u32 offset, cmd = 0;
__be16 frag_off; __be16 frag_off;
__be16 protocol;
u8 l4_proto = 0; u8 l4_proto = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) if (skb->ip_summed != CHECKSUM_PARTIAL)
return 0; return 0;
protocol = vlan_get_protocol(skb);
if (eth_p_mpls(protocol))
ip.hdr = skb_inner_network_header(skb);
else
ip.hdr = skb_network_header(skb); ip.hdr = skb_network_header(skb);
l4.hdr = skb_transport_header(skb); l4.hdr = skb_checksum_start(skb);
/* set the tx_flags to indicate the IP protocol type. this is
* required so that checksum header computation below is accurate.
*/
if (ip.v4->version == 4)
*tx_flags |= I40E_TX_FLAGS_IPV4;
else
*tx_flags |= I40E_TX_FLAGS_IPV6;
/* compute outer L2 header size */ /* compute outer L2 header size */
offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
...@@ -3749,7 +3772,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, ...@@ -3749,7 +3772,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
struct i40e_tx_buffer *first; struct i40e_tx_buffer *first;
u32 td_offset = 0; u32 td_offset = 0;
u32 tx_flags = 0; u32 tx_flags = 0;
__be16 protocol;
u32 td_cmd = 0; u32 td_cmd = 0;
u8 hdr_len = 0; u8 hdr_len = 0;
int tso, count; int tso, count;
...@@ -3791,15 +3813,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, ...@@ -3791,15 +3813,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags)) if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
goto out_drop; goto out_drop;
/* obtain protocol of skb */
protocol = vlan_get_protocol(skb);
/* setup IPv4/IPv6 offloads */
if (protocol == htons(ETH_P_IP))
tx_flags |= I40E_TX_FLAGS_IPV4;
else if (protocol == htons(ETH_P_IPV6))
tx_flags |= I40E_TX_FLAGS_IPV6;
tso = i40e_tso(first, &hdr_len, &cd_type_cmd_tso_mss); tso = i40e_tso(first, &hdr_len, &cd_type_cmd_tso_mss);
if (tso < 0) if (tso < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment