Skip to content

Commit 447bc4b

Browse files
Mike Yuklassert
authored andcommitted
xfrm: Support crypto offload for outbound IPv4 UDP-encapsulated ESP packet
esp_xmit() is already able to handle UDP encapsulation through the call to esp_output_head(). However, the ESP header and the outer IP header are not correct and need to be corrected. Test: Enabled both dir=in/out IPsec crypto offload, and verified IPv4 UDP-encapsulated ESP packets on both wifi/cellular network Signed-off-by: Mike Yu <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 4ecbac8 commit 447bc4b

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

net/ipv4/esp4.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
349349
{
350350
struct udphdr *uh;
351351
unsigned int len;
352+
struct xfrm_offload *xo = xfrm_offload(skb);
352353

353354
len = skb->len + esp->tailen - skb_transport_offset(skb);
354355
if (len + sizeof(struct iphdr) > IP_MAX_MTU)
@@ -360,7 +361,12 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
360361
uh->len = htons(len);
361362
uh->check = 0;
362363

363-
*skb_mac_header(skb) = IPPROTO_UDP;
364+
/* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload
365+
* data path, which means that esp_output_udp_encap is called outside of the XFRM stack.
366+
* In this case, the mac header doesn't point to the IPv4 protocol field, so don't set it.
367+
*/
368+
if (!xo || encap_type != UDP_ENCAP_ESPINUDP)
369+
*skb_mac_header(skb) = IPPROTO_UDP;
364370

365371
return (struct ip_esp_hdr *)(uh + 1);
366372
}

net/ipv4/esp4_offload.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
264264
struct esp_info esp;
265265
bool hw_offload = true;
266266
__u32 seq;
267+
int encap_type = 0;
267268

268269
esp.inplace = true;
269270

@@ -296,8 +297,10 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
296297

297298
esp.esph = ip_esp_hdr(skb);
298299

300+
if (x->encap)
301+
encap_type = x->encap->encap_type;
299302

300-
if (!hw_offload || !skb_is_gso(skb)) {
303+
if (!hw_offload || !skb_is_gso(skb) || (hw_offload && encap_type == UDP_ENCAP_ESPINUDP)) {
301304
esp.nfrags = esp_output_head(x, skb, &esp);
302305
if (esp.nfrags < 0)
303306
return esp.nfrags;
@@ -324,6 +327,18 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
324327

325328
esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
326329

330+
if (hw_offload && encap_type == UDP_ENCAP_ESPINUDP) {
331+
/* In the XFRM stack, the encapsulation protocol is set to iphdr->protocol by
332+
* setting *skb_mac_header(skb) (see esp_output_udp_encap()) where skb->mac_header
333+
* points to iphdr->protocol (see xfrm4_tunnel_encap_add()).
334+
* However, in esp_xmit(), skb->mac_header doesn't point to iphdr->protocol.
335+
* Therefore, the protocol field needs to be corrected.
336+
*/
337+
ip_hdr(skb)->protocol = IPPROTO_UDP;
338+
339+
esph->seq_no = htonl(seq);
340+
}
341+
327342
ip_hdr(skb)->tot_len = htons(skb->len);
328343
ip_send_check(ip_hdr(skb));
329344

0 commit comments

Comments
 (0)