hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/ipv6/esp6_offload.c
....@@ -1,13 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * IPV6 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 */
....@@ -68,27 +65,28 @@
6865
6966 xo = xfrm_offload(skb);
7067 if (!xo || !(xo->flags & CRYPTO_DONE)) {
71
- err = secpath_set(skb);
72
- if (err)
68
+ struct sec_path *sp = secpath_set(skb);
69
+
70
+ if (!sp)
7371 goto out;
7472
75
- if (skb->sp->len == XFRM_MAX_DEPTH)
76
- goto out;
73
+ if (sp->len == XFRM_MAX_DEPTH)
74
+ goto out_reset;
7775
7876 x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
7977 (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
8078 spi, IPPROTO_ESP, AF_INET6);
8179 if (!x)
82
- goto out;
80
+ goto out_reset;
8381
84
- skb->sp->xvec[skb->sp->len++] = x;
85
- skb->sp->olen++;
82
+ skb->mark = xfrm_smark_get(skb->mark, x);
83
+
84
+ sp->xvec[sp->len++] = x;
85
+ sp->olen++;
8686
8787 xo = xfrm_offload(skb);
88
- if (!xo) {
89
- xfrm_state_put(x);
90
- goto out;
91
- }
88
+ if (!xo)
89
+ goto out_reset;
9290 }
9391
9492 xo->flags |= XFRM_GRO;
....@@ -108,6 +106,8 @@
108106 xfrm_input(skb, IPPROTO_ESP, spi, -2);
109107
110108 return ERR_PTR(-EINPROGRESS);
109
+out_reset:
110
+ secpath_reset(skb);
111111 out:
112112 skb_push(skb, offset);
113113 NAPI_GRO_CB(skb)->same_flow = 0;
....@@ -125,7 +125,7 @@
125125
126126 skb_push(skb, -skb_network_offset(skb));
127127
128
- if (x->outer_mode->encap == XFRM_MODE_TRANSPORT) {
128
+ if (x->outer_mode.encap == XFRM_MODE_TRANSPORT) {
129129 __be16 frag;
130130
131131 ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &proto, &frag);
....@@ -140,6 +140,91 @@
140140 xo->proto = proto;
141141 }
142142
143
+static struct sk_buff *xfrm6_tunnel_gso_segment(struct xfrm_state *x,
144
+ struct sk_buff *skb,
145
+ netdev_features_t features)
146
+{
147
+ __skb_push(skb, skb->mac_len);
148
+ return skb_mac_gso_segment(skb, features);
149
+}
150
+
151
+static struct sk_buff *xfrm6_transport_gso_segment(struct xfrm_state *x,
152
+ struct sk_buff *skb,
153
+ netdev_features_t features)
154
+{
155
+ const struct net_offload *ops;
156
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
157
+ struct xfrm_offload *xo = xfrm_offload(skb);
158
+
159
+ skb->transport_header += x->props.header_len;
160
+ ops = rcu_dereference(inet6_offloads[xo->proto]);
161
+ if (likely(ops && ops->callbacks.gso_segment))
162
+ segs = ops->callbacks.gso_segment(skb, features);
163
+
164
+ return segs;
165
+}
166
+
167
+static struct sk_buff *xfrm6_beet_gso_segment(struct xfrm_state *x,
168
+ struct sk_buff *skb,
169
+ netdev_features_t features)
170
+{
171
+ struct xfrm_offload *xo = xfrm_offload(skb);
172
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
173
+ const struct net_offload *ops;
174
+ u8 proto = xo->proto;
175
+
176
+ skb->transport_header += x->props.header_len;
177
+
178
+ if (x->sel.family != AF_INET6) {
179
+ skb->transport_header -=
180
+ (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
181
+
182
+ if (proto == IPPROTO_BEETPH) {
183
+ struct ip_beet_phdr *ph =
184
+ (struct ip_beet_phdr *)skb->data;
185
+
186
+ skb->transport_header += ph->hdrlen * 8;
187
+ proto = ph->nexthdr;
188
+ } else {
189
+ skb->transport_header -= IPV4_BEET_PHMAXLEN;
190
+ }
191
+
192
+ if (proto == IPPROTO_TCP)
193
+ skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
194
+ } else {
195
+ __be16 frag;
196
+
197
+ skb->transport_header +=
198
+ ipv6_skip_exthdr(skb, 0, &proto, &frag);
199
+ }
200
+
201
+ if (proto == IPPROTO_IPIP)
202
+ skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP6;
203
+
204
+ __skb_pull(skb, skb_transport_offset(skb));
205
+ ops = rcu_dereference(inet6_offloads[proto]);
206
+ if (likely(ops && ops->callbacks.gso_segment))
207
+ segs = ops->callbacks.gso_segment(skb, features);
208
+
209
+ return segs;
210
+}
211
+
212
+static struct sk_buff *xfrm6_outer_mode_gso_segment(struct xfrm_state *x,
213
+ struct sk_buff *skb,
214
+ netdev_features_t features)
215
+{
216
+ switch (x->outer_mode.encap) {
217
+ case XFRM_MODE_TUNNEL:
218
+ return xfrm6_tunnel_gso_segment(x, skb, features);
219
+ case XFRM_MODE_TRANSPORT:
220
+ return xfrm6_transport_gso_segment(x, skb, features);
221
+ case XFRM_MODE_BEET:
222
+ return xfrm6_beet_gso_segment(x, skb, features);
223
+ }
224
+
225
+ return ERR_PTR(-EOPNOTSUPP);
226
+}
227
+
143228 static struct sk_buff *esp6_gso_segment(struct sk_buff *skb,
144229 netdev_features_t features)
145230 {
....@@ -148,6 +233,7 @@
148233 struct crypto_aead *aead;
149234 netdev_features_t esp_features = features;
150235 struct xfrm_offload *xo = xfrm_offload(skb);
236
+ struct sec_path *sp;
151237
152238 if (!xo)
153239 return ERR_PTR(-EINVAL);
....@@ -155,7 +241,8 @@
155241 if (!(skb_shinfo(skb)->gso_type & SKB_GSO_ESP))
156242 return ERR_PTR(-EINVAL);
157243
158
- x = skb->sp->xvec[skb->sp->len - 1];
244
+ sp = skb_sec_path(skb);
245
+ x = sp->xvec[sp->len - 1];
159246 aead = x->data;
160247 esph = ip_esp_hdr(skb);
161248
....@@ -170,13 +257,15 @@
170257 skb->encap_hdr_csum = 1;
171258
172259 if (!(features & NETIF_F_HW_ESP) || x->xso.dev != skb->dev)
173
- esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK);
260
+ esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK |
261
+ NETIF_F_SCTP_CRC);
174262 else if (!(features & NETIF_F_HW_ESP_TX_CSUM))
175
- esp_features = features & ~NETIF_F_CSUM_MASK;
263
+ esp_features = features & ~(NETIF_F_CSUM_MASK |
264
+ NETIF_F_SCTP_CRC);
176265
177266 xo->flags |= XFRM_GSO_SEGMENT;
178267
179
- return x->outer_mode->gso_segment(x, skb, esp_features);
268
+ return xfrm6_outer_mode_gso_segment(x, skb, esp_features);
180269 }
181270
182271 static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb)
....@@ -200,7 +289,6 @@
200289 int alen;
201290 int blksize;
202291 struct xfrm_offload *xo;
203
- struct ip_esp_hdr *esph;
204292 struct crypto_aead *aead;
205293 struct esp_info esp;
206294 bool hw_offload = true;
....@@ -241,19 +329,22 @@
241329
242330 seq = xo->seq.low;
243331
244
- esph = ip_esp_hdr(skb);
245
- esph->spi = x->id.spi;
332
+ esp.esph = ip_esp_hdr(skb);
333
+ esp.esph->spi = x->id.spi;
246334
247335 skb_push(skb, -skb_network_offset(skb));
248336
249337 if (xo->flags & XFRM_GSO_SEGMENT) {
250
- esph->seq_no = htonl(seq);
338
+ esp.esph->seq_no = htonl(seq);
251339
252340 if (!skb_is_gso(skb))
253341 xo->seq.low++;
254342 else
255343 xo->seq.low += skb_shinfo(skb)->gso_segs;
256344 }
345
+
346
+ if (xo->seq.low < seq)
347
+ xo->seq.hi++;
257348
258349 esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
259350
....@@ -263,8 +354,17 @@
263354
264355 ipv6_hdr(skb)->payload_len = htons(len);
265356
266
- if (hw_offload)
357
+ if (hw_offload) {
358
+ if (!skb_ext_add(skb, SKB_EXT_SEC_PATH))
359
+ return -ENOMEM;
360
+
361
+ xo = xfrm_offload(skb);
362
+ if (!xo)
363
+ return -EINVAL;
364
+
365
+ xo->flags |= XFRM_XMIT;
267366 return 0;
367
+ }
268368
269369 err = esp6_output_tail(x, skb, &esp);
270370 if (err)
....@@ -272,6 +372,9 @@
272372
273373 secpath_reset(skb);
274374
375
+ if (skb_needs_linearize(skb, skb->dev->features) &&
376
+ __skb_linearize(skb))
377
+ return -ENOMEM;
275378 return 0;
276379 }
277380
....@@ -303,9 +406,7 @@
303406
304407 static void __exit esp6_offload_exit(void)
305408 {
306
- if (xfrm_unregister_type_offload(&esp6_type_offload, AF_INET6) < 0)
307
- pr_info("%s: can't remove xfrm type offload\n", __func__);
308
-
409
+ xfrm_unregister_type_offload(&esp6_type_offload, AF_INET6);
309410 inet6_del_offload(&esp6_offload, IPPROTO_ESP);
310411 }
311412
....@@ -314,3 +415,4 @@
314415 MODULE_LICENSE("GPL");
315416 MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
316417 MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET6, XFRM_PROTO_ESP);
418
+MODULE_DESCRIPTION("IPV6 GSO/GRO offload support");