mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-22 04:15:42 -05:00
net: libwx: fix Tx descriptor content for some tunnel packets
The length of skb header was incorrectly calculated when transmit a tunnel
packet with outer IPv6 extension header, or a IP over IP packet which has
inner IPv6 header. Thus the correct Tx context descriptor cannot be
composed, resulting in Tx ring hang.
Fixes: 3403960cdf ("net: wangxun: libwx add tx offload functions")
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Link: https://patch.msgid.link/20250324103235.823096-1-jiawenwu@trustnetic.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
bf2986fcf8
commit
a44940d094
@@ -1082,26 +1082,6 @@ static void wx_tx_ctxtdesc(struct wx_ring *tx_ring, u32 vlan_macip_lens,
|
||||
context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
|
||||
}
|
||||
|
||||
static void wx_get_ipv6_proto(struct sk_buff *skb, int offset, u8 *nexthdr)
|
||||
{
|
||||
struct ipv6hdr *hdr = (struct ipv6hdr *)(skb->data + offset);
|
||||
|
||||
*nexthdr = hdr->nexthdr;
|
||||
offset += sizeof(struct ipv6hdr);
|
||||
while (ipv6_ext_hdr(*nexthdr)) {
|
||||
struct ipv6_opt_hdr _hdr, *hp;
|
||||
|
||||
if (*nexthdr == NEXTHDR_NONE)
|
||||
return;
|
||||
hp = skb_header_pointer(skb, offset, sizeof(_hdr), &_hdr);
|
||||
if (!hp)
|
||||
return;
|
||||
if (*nexthdr == NEXTHDR_FRAGMENT)
|
||||
break;
|
||||
*nexthdr = hp->nexthdr;
|
||||
}
|
||||
}
|
||||
|
||||
union network_header {
|
||||
struct iphdr *ipv4;
|
||||
struct ipv6hdr *ipv6;
|
||||
@@ -1112,6 +1092,8 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
|
||||
{
|
||||
u8 tun_prot = 0, l4_prot = 0, ptype = 0;
|
||||
struct sk_buff *skb = first->skb;
|
||||
unsigned char *exthdr, *l4_hdr;
|
||||
__be16 frag_off;
|
||||
|
||||
if (skb->encapsulation) {
|
||||
union network_header hdr;
|
||||
@@ -1122,14 +1104,18 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
|
||||
ptype = WX_PTYPE_TUN_IPV4;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
wx_get_ipv6_proto(skb, skb_network_offset(skb), &tun_prot);
|
||||
l4_hdr = skb_transport_header(skb);
|
||||
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
|
||||
tun_prot = ipv6_hdr(skb)->nexthdr;
|
||||
if (l4_hdr != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data, &tun_prot, &frag_off);
|
||||
ptype = WX_PTYPE_TUN_IPV6;
|
||||
break;
|
||||
default:
|
||||
return ptype;
|
||||
}
|
||||
|
||||
if (tun_prot == IPPROTO_IPIP) {
|
||||
if (tun_prot == IPPROTO_IPIP || tun_prot == IPPROTO_IPV6) {
|
||||
hdr.raw = (void *)inner_ip_hdr(skb);
|
||||
ptype |= WX_PTYPE_PKT_IPIP;
|
||||
} else if (tun_prot == IPPROTO_UDP) {
|
||||
@@ -1166,7 +1152,11 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
|
||||
l4_prot = hdr.ipv4->protocol;
|
||||
break;
|
||||
case 6:
|
||||
wx_get_ipv6_proto(skb, skb_inner_network_offset(skb), &l4_prot);
|
||||
l4_hdr = skb_inner_transport_header(skb);
|
||||
exthdr = skb_inner_network_header(skb) + sizeof(struct ipv6hdr);
|
||||
l4_prot = inner_ipv6_hdr(skb)->nexthdr;
|
||||
if (l4_hdr != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_prot, &frag_off);
|
||||
ptype |= WX_PTYPE_PKT_IPV6;
|
||||
break;
|
||||
default:
|
||||
@@ -1179,7 +1169,11 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
|
||||
ptype = WX_PTYPE_PKT_IP;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
wx_get_ipv6_proto(skb, skb_network_offset(skb), &l4_prot);
|
||||
l4_hdr = skb_transport_header(skb);
|
||||
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
|
||||
l4_prot = ipv6_hdr(skb)->nexthdr;
|
||||
if (l4_hdr != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_prot, &frag_off);
|
||||
ptype = WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6;
|
||||
break;
|
||||
default:
|
||||
@@ -1269,13 +1263,20 @@ static int wx_tso(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
|
||||
|
||||
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
|
||||
if (enc) {
|
||||
unsigned char *exthdr, *l4_hdr;
|
||||
__be16 frag_off;
|
||||
|
||||
switch (first->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
tun_prot = ip_hdr(skb)->protocol;
|
||||
first->tx_flags |= WX_TX_FLAGS_OUTER_IPV4;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
l4_hdr = skb_transport_header(skb);
|
||||
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
|
||||
tun_prot = ipv6_hdr(skb)->nexthdr;
|
||||
if (l4_hdr != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data, &tun_prot, &frag_off);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1298,6 +1299,7 @@ static int wx_tso(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
|
||||
WX_TXD_TUNNEL_LEN_SHIFT);
|
||||
break;
|
||||
case IPPROTO_IPIP:
|
||||
case IPPROTO_IPV6:
|
||||
tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb) -
|
||||
(char *)ip_hdr(skb)) >> 2) <<
|
||||
WX_TXD_OUTER_IPLEN_SHIFT;
|
||||
@@ -1341,6 +1343,8 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
|
||||
vlan_macip_lens = skb_network_offset(skb) <<
|
||||
WX_TXD_MACLEN_SHIFT;
|
||||
} else {
|
||||
unsigned char *exthdr, *l4_hdr;
|
||||
__be16 frag_off;
|
||||
u8 l4_prot = 0;
|
||||
union {
|
||||
struct iphdr *ipv4;
|
||||
@@ -1362,7 +1366,12 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
|
||||
tun_prot = ip_hdr(skb)->protocol;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
l4_hdr = skb_transport_header(skb);
|
||||
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
|
||||
tun_prot = ipv6_hdr(skb)->nexthdr;
|
||||
if (l4_hdr != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data,
|
||||
&tun_prot, &frag_off);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -1386,6 +1395,7 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
|
||||
WX_TXD_TUNNEL_LEN_SHIFT);
|
||||
break;
|
||||
case IPPROTO_IPIP:
|
||||
case IPPROTO_IPV6:
|
||||
tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb) -
|
||||
(char *)ip_hdr(skb)) >> 2) <<
|
||||
WX_TXD_OUTER_IPLEN_SHIFT;
|
||||
@@ -1408,7 +1418,10 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
|
||||
break;
|
||||
case 6:
|
||||
vlan_macip_lens |= (transport_hdr.raw - network_hdr.raw) >> 1;
|
||||
exthdr = network_hdr.raw + sizeof(struct ipv6hdr);
|
||||
l4_prot = network_hdr.ipv6->nexthdr;
|
||||
if (transport_hdr.raw != exthdr)
|
||||
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_prot, &frag_off);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user