Skip to content

Commit

Permalink
i40e: Add support for MPLS + TSO
Browse files Browse the repository at this point in the history
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: Joe Damato <jdamato@fastly.com>
Co-developed-by: Mike Gallo <mgallo@fastly.com>
Signed-off-by: Mike Gallo <mgallo@fastly.com>
Tested-by: Gurucharan <gurucharanx.g@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
  • Loading branch information
jdamato-fsly authored and anguy11 committed Apr 12, 2022
1 parent 590032a commit b4fb2d3
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 19 deletions.
20 changes: 18 additions & 2 deletions drivers/net/ethernet/intel/i40e/i40e_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -13436,8 +13436,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
np->vsi = vsi;

hw_enc_features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM |
NETIF_F_HIGHDMA |
NETIF_F_SOFT_FEATURES |
NETIF_F_TSO |
Expand Down Expand Up @@ -13468,6 +13467,23 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
/* record features VLANs can make use of */
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 */
netdev->hw_features |= NETIF_F_HW_L2FW_DOFFLOAD;

Expand Down
47 changes: 30 additions & 17 deletions drivers/net/ethernet/intel/i40e/i40e_txrx.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/prefetch.h>
#include <linux/bpf_trace.h>
#include <net/mpls.h>
#include <net/xdp.h>
#include "i40e.h"
#include "i40e_trace.h"
Expand Down Expand Up @@ -3015,6 +3016,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
{
struct sk_buff *skb = first->skb;
u64 cd_cmd, cd_tso_len, cd_mss;
__be16 protocol;
union {
struct iphdr *v4;
struct ipv6hdr *v6;
Expand All @@ -3026,7 +3028,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
unsigned char *hdr;
} l4;
u32 paylen, l4_offset;
u16 gso_segs, gso_size;
u16 gso_size;
int err;

if (skb->ip_summed != CHECKSUM_PARTIAL)
Expand All @@ -3039,15 +3041,23 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
if (err < 0)
return err;

ip.hdr = skb_network_header(skb);
l4.hdr = skb_transport_header(skb);
protocol = vlan_get_protocol(skb);

if (eth_p_mpls(protocol))
ip.hdr = skb_inner_network_header(skb);
else
ip.hdr = skb_network_header(skb);
l4.hdr = skb_checksum_start(skb);

/* initialize outer IP header fields */
if (ip.v4->version == 4) {
ip.v4->tot_len = 0;
ip.v4->check = 0;

first->tx_flags |= I40E_TX_FLAGS_TSO;
} else {
ip.v6->payload_len = 0;
first->tx_flags |= I40E_TX_FLAGS_TSO;
}

if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE |
Expand Down Expand Up @@ -3100,10 +3110,9 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,

/* pull values out of skb_shinfo */
gso_size = skb_shinfo(skb)->gso_size;
gso_segs = skb_shinfo(skb)->gso_segs;

/* 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;

/* find the field values */
Expand Down Expand Up @@ -3187,13 +3196,27 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
unsigned char *exthdr;
u32 offset, cmd = 0;
__be16 frag_off;
__be16 protocol;
u8 l4_proto = 0;

if (skb->ip_summed != CHECKSUM_PARTIAL)
return 0;

ip.hdr = skb_network_header(skb);
l4.hdr = skb_transport_header(skb);
protocol = vlan_get_protocol(skb);

if (eth_p_mpls(protocol))
ip.hdr = skb_inner_network_header(skb);
else
ip.hdr = skb_network_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 */
offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
Expand Down Expand Up @@ -3749,7 +3772,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
struct i40e_tx_buffer *first;
u32 td_offset = 0;
u32 tx_flags = 0;
__be16 protocol;
u32 td_cmd = 0;
u8 hdr_len = 0;
int tso, count;
Expand Down Expand Up @@ -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))
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);

if (tso < 0)
Expand Down

0 comments on commit b4fb2d3

Please sign in to comment.