hc
2024-05-11 04dd17822334871b23ea2862f7798fb0e0007777
kernel/net/ipv4/esp4_offload.c
....@@ -1,13 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * IPV4 GSO/GRO offload support
34 * Linux INET implementation
45 *
56 * Copyright (C) 2016 secunet Security Networks AG
67 * Author: Steffen Klassert <steffen.klassert@secunet.com>
7
- *
8
- * This program is free software; you can redistribute it and/or modify it
9
- * under the terms and conditions of the GNU General Public License,
10
- * version 2, as published by the Free Software Foundation.
118 *
129 * ESP GRO support
1310 */
....@@ -46,27 +43,28 @@
4643
4744 xo = xfrm_offload(skb);
4845 if (!xo || !(xo->flags & CRYPTO_DONE)) {
49
- err = secpath_set(skb);
50
- if (err)
46
+ struct sec_path *sp = secpath_set(skb);
47
+
48
+ if (!sp)
5149 goto out;
5250
53
- if (skb->sp->len == XFRM_MAX_DEPTH)
54
- goto out;
51
+ if (sp->len == XFRM_MAX_DEPTH)
52
+ goto out_reset;
5553
5654 x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
5755 (xfrm_address_t *)&ip_hdr(skb)->daddr,
5856 spi, IPPROTO_ESP, AF_INET);
5957 if (!x)
60
- goto out;
58
+ goto out_reset;
6159
62
- skb->sp->xvec[skb->sp->len++] = x;
63
- skb->sp->olen++;
60
+ skb->mark = xfrm_smark_get(skb->mark, x);
61
+
62
+ sp->xvec[sp->len++] = x;
63
+ sp->olen++;
6464
6565 xo = xfrm_offload(skb);
66
- if (!xo) {
67
- xfrm_state_put(x);
68
- goto out;
69
- }
66
+ if (!xo)
67
+ goto out_reset;
7068 }
7169
7270 xo->flags |= XFRM_GRO;
....@@ -81,6 +79,8 @@
8179 xfrm_input(skb, IPPROTO_ESP, spi, -2);
8280
8381 return ERR_PTR(-EINPROGRESS);
82
+out_reset:
83
+ secpath_reset(skb);
8484 out:
8585 skb_push(skb, offset);
8686 NAPI_GRO_CB(skb)->same_flow = 0;
....@@ -106,6 +106,87 @@
106106 xo->proto = proto;
107107 }
108108
109
+static struct sk_buff *xfrm4_tunnel_gso_segment(struct xfrm_state *x,
110
+ struct sk_buff *skb,
111
+ netdev_features_t features)
112
+{
113
+ __skb_push(skb, skb->mac_len);
114
+ return skb_mac_gso_segment(skb, features);
115
+}
116
+
117
+static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
118
+ struct sk_buff *skb,
119
+ netdev_features_t features)
120
+{
121
+ const struct net_offload *ops;
122
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
123
+ struct xfrm_offload *xo = xfrm_offload(skb);
124
+
125
+ skb->transport_header += x->props.header_len;
126
+ ops = rcu_dereference(inet_offloads[xo->proto]);
127
+ if (likely(ops && ops->callbacks.gso_segment))
128
+ segs = ops->callbacks.gso_segment(skb, features);
129
+
130
+ return segs;
131
+}
132
+
133
+static struct sk_buff *xfrm4_beet_gso_segment(struct xfrm_state *x,
134
+ struct sk_buff *skb,
135
+ netdev_features_t features)
136
+{
137
+ struct xfrm_offload *xo = xfrm_offload(skb);
138
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
139
+ const struct net_offload *ops;
140
+ u8 proto = xo->proto;
141
+
142
+ skb->transport_header += x->props.header_len;
143
+
144
+ if (x->sel.family != AF_INET6) {
145
+ if (proto == IPPROTO_BEETPH) {
146
+ struct ip_beet_phdr *ph =
147
+ (struct ip_beet_phdr *)skb->data;
148
+
149
+ skb->transport_header += ph->hdrlen * 8;
150
+ proto = ph->nexthdr;
151
+ } else {
152
+ skb->transport_header -= IPV4_BEET_PHMAXLEN;
153
+ }
154
+ } else {
155
+ __be16 frag;
156
+
157
+ skb->transport_header +=
158
+ ipv6_skip_exthdr(skb, 0, &proto, &frag);
159
+ if (proto == IPPROTO_TCP)
160
+ skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
161
+ }
162
+
163
+ if (proto == IPPROTO_IPV6)
164
+ skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP4;
165
+
166
+ __skb_pull(skb, skb_transport_offset(skb));
167
+ ops = rcu_dereference(inet_offloads[proto]);
168
+ if (likely(ops && ops->callbacks.gso_segment))
169
+ segs = ops->callbacks.gso_segment(skb, features);
170
+
171
+ return segs;
172
+}
173
+
174
+static struct sk_buff *xfrm4_outer_mode_gso_segment(struct xfrm_state *x,
175
+ struct sk_buff *skb,
176
+ netdev_features_t features)
177
+{
178
+ switch (x->outer_mode.encap) {
179
+ case XFRM_MODE_TUNNEL:
180
+ return xfrm4_tunnel_gso_segment(x, skb, features);
181
+ case XFRM_MODE_TRANSPORT:
182
+ return xfrm4_transport_gso_segment(x, skb, features);
183
+ case XFRM_MODE_BEET:
184
+ return xfrm4_beet_gso_segment(x, skb, features);
185
+ }
186
+
187
+ return ERR_PTR(-EOPNOTSUPP);
188
+}
189
+
109190 static struct sk_buff *esp4_gso_segment(struct sk_buff *skb,
110191 netdev_features_t features)
111192 {
....@@ -114,6 +195,7 @@
114195 struct crypto_aead *aead;
115196 netdev_features_t esp_features = features;
116197 struct xfrm_offload *xo = xfrm_offload(skb);
198
+ struct sec_path *sp;
117199
118200 if (!xo)
119201 return ERR_PTR(-EINVAL);
....@@ -121,7 +203,8 @@
121203 if (!(skb_shinfo(skb)->gso_type & SKB_GSO_ESP))
122204 return ERR_PTR(-EINVAL);
123205
124
- x = skb->sp->xvec[skb->sp->len - 1];
206
+ sp = skb_sec_path(skb);
207
+ x = sp->xvec[sp->len - 1];
125208 aead = x->data;
126209 esph = ip_esp_hdr(skb);
127210
....@@ -135,14 +218,18 @@
135218
136219 skb->encap_hdr_csum = 1;
137220
138
- if (!(features & NETIF_F_HW_ESP) || x->xso.dev != skb->dev)
139
- esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK);
140
- else if (!(features & NETIF_F_HW_ESP_TX_CSUM))
141
- esp_features = features & ~NETIF_F_CSUM_MASK;
221
+ if ((!(skb->dev->gso_partial_features & NETIF_F_HW_ESP) &&
222
+ !(features & NETIF_F_HW_ESP)) || x->xso.dev != skb->dev)
223
+ esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK |
224
+ NETIF_F_SCTP_CRC);
225
+ else if (!(features & NETIF_F_HW_ESP_TX_CSUM) &&
226
+ !(skb->dev->gso_partial_features & NETIF_F_HW_ESP_TX_CSUM))
227
+ esp_features = features & ~(NETIF_F_CSUM_MASK |
228
+ NETIF_F_SCTP_CRC);
142229
143230 xo->flags |= XFRM_GSO_SEGMENT;
144231
145
- return x->outer_mode->gso_segment(x, skb, esp_features);
232
+ return xfrm4_outer_mode_gso_segment(x, skb, esp_features);
146233 }
147234
148235 static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb)
....@@ -178,7 +265,9 @@
178265 if (!xo)
179266 return -EINVAL;
180267
181
- if (!(features & NETIF_F_HW_ESP) || x->xso.dev != skb->dev) {
268
+ if ((!(features & NETIF_F_HW_ESP) &&
269
+ !(skb->dev->gso_partial_features & NETIF_F_HW_ESP)) ||
270
+ x->xso.dev != skb->dev) {
182271 xo->flags |= CRYPTO_FALLBACK;
183272 hw_offload = false;
184273 }
....@@ -223,13 +312,25 @@
223312 xo->seq.low += skb_shinfo(skb)->gso_segs;
224313 }
225314
315
+ if (xo->seq.low < seq)
316
+ xo->seq.hi++;
317
+
226318 esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32));
227319
228320 ip_hdr(skb)->tot_len = htons(skb->len);
229321 ip_send_check(ip_hdr(skb));
230322
231
- if (hw_offload)
323
+ if (hw_offload) {
324
+ if (!skb_ext_add(skb, SKB_EXT_SEC_PATH))
325
+ return -ENOMEM;
326
+
327
+ xo = xfrm_offload(skb);
328
+ if (!xo)
329
+ return -EINVAL;
330
+
331
+ xo->flags |= XFRM_XMIT;
232332 return 0;
333
+ }
233334
234335 err = esp_output_tail(x, skb, &esp);
235336 if (err)
....@@ -237,6 +338,9 @@
237338
238339 secpath_reset(skb);
239340
341
+ if (skb_needs_linearize(skb, skb->dev->features) &&
342
+ __skb_linearize(skb))
343
+ return -ENOMEM;
240344 return 0;
241345 }
242346
....@@ -268,9 +372,7 @@
268372
269373 static void __exit esp4_offload_exit(void)
270374 {
271
- if (xfrm_unregister_type_offload(&esp_type_offload, AF_INET) < 0)
272
- pr_info("%s: can't remove xfrm type offload\n", __func__);
273
-
375
+ xfrm_unregister_type_offload(&esp_type_offload, AF_INET);
274376 inet_del_offload(&esp4_offload, IPPROTO_ESP);
275377 }
276378
....@@ -279,3 +381,4 @@
279381 MODULE_LICENSE("GPL");
280382 MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
281383 MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET, XFRM_PROTO_ESP);
384
+MODULE_DESCRIPTION("IPV4 GSO/GRO offload support");