1 /*
2 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 *
32 */
33
34 #include <crypto/aead.h>
35 #include <net/xfrm.h>
36 #include <net/esp.h>
37 #include "accel/ipsec_offload.h"
38 #include "en_accel/ipsec_rxtx.h"
39 #include "en_accel/ipsec.h"
40 #include "accel/accel.h"
41 #include "en.h"
42
43 enum {
44 MLX5E_IPSEC_RX_SYNDROME_DECRYPTED = 0x11,
45 MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED = 0x12,
46 MLX5E_IPSEC_RX_SYNDROME_BAD_PROTO = 0x17,
47 };
48
49 struct mlx5e_ipsec_rx_metadata {
50 unsigned char nexthdr;
51 __be32 sa_handle;
52 } __packed;
53
54 enum {
55 MLX5E_IPSEC_TX_SYNDROME_OFFLOAD = 0x8,
56 MLX5E_IPSEC_TX_SYNDROME_OFFLOAD_WITH_LSO_TCP = 0x9,
57 };
58
59 struct mlx5e_ipsec_tx_metadata {
60 __be16 mss_inv; /* 1/MSS in 16bit fixed point, only for LSO */
61 __be16 seq; /* LSBs of the first TCP seq, only for LSO */
62 u8 esp_next_proto; /* Next protocol of ESP */
63 } __packed;
64
65 struct mlx5e_ipsec_metadata {
66 unsigned char syndrome;
67 union {
68 unsigned char raw[5];
69 /* from FPGA to host, on successful decrypt */
70 struct mlx5e_ipsec_rx_metadata rx;
71 /* from host to FPGA */
72 struct mlx5e_ipsec_tx_metadata tx;
73 } __packed content;
74 /* packet type ID field */
75 __be16 ethertype;
76 } __packed;
77
78 #define MAX_LSO_MSS 2048
79
80 /* Pre-calculated (Q0.16) fixed-point inverse 1/x function */
81 static __be16 mlx5e_ipsec_inverse_table[MAX_LSO_MSS];
82
mlx5e_ipsec_mss_inv(struct sk_buff * skb)83 static inline __be16 mlx5e_ipsec_mss_inv(struct sk_buff *skb)
84 {
85 return mlx5e_ipsec_inverse_table[skb_shinfo(skb)->gso_size];
86 }
87
mlx5e_ipsec_add_metadata(struct sk_buff * skb)88 static struct mlx5e_ipsec_metadata *mlx5e_ipsec_add_metadata(struct sk_buff *skb)
89 {
90 struct mlx5e_ipsec_metadata *mdata;
91 struct ethhdr *eth;
92
93 if (unlikely(skb_cow_head(skb, sizeof(*mdata))))
94 return ERR_PTR(-ENOMEM);
95
96 eth = (struct ethhdr *)skb_push(skb, sizeof(*mdata));
97 skb->mac_header -= sizeof(*mdata);
98 mdata = (struct mlx5e_ipsec_metadata *)(eth + 1);
99
100 memmove(skb->data, skb->data + sizeof(*mdata),
101 2 * ETH_ALEN);
102
103 eth->h_proto = cpu_to_be16(MLX5E_METADATA_ETHER_TYPE);
104
105 memset(mdata->content.raw, 0, sizeof(mdata->content.raw));
106 return mdata;
107 }
108
mlx5e_ipsec_remove_trailer(struct sk_buff * skb,struct xfrm_state * x)109 static int mlx5e_ipsec_remove_trailer(struct sk_buff *skb, struct xfrm_state *x)
110 {
111 unsigned int alen = crypto_aead_authsize(x->data);
112 struct ipv6hdr *ipv6hdr = ipv6_hdr(skb);
113 struct iphdr *ipv4hdr = ip_hdr(skb);
114 unsigned int trailer_len;
115 u8 plen;
116 int ret;
117
118 ret = skb_copy_bits(skb, skb->len - alen - 2, &plen, 1);
119 if (unlikely(ret))
120 return ret;
121
122 trailer_len = alen + plen + 2;
123
124 ret = pskb_trim(skb, skb->len - trailer_len);
125 if (unlikely(ret))
126 return ret;
127 if (skb->protocol == htons(ETH_P_IP)) {
128 ipv4hdr->tot_len = htons(ntohs(ipv4hdr->tot_len) - trailer_len);
129 ip_send_check(ipv4hdr);
130 } else {
131 ipv6hdr->payload_len = htons(ntohs(ipv6hdr->payload_len) -
132 trailer_len);
133 }
134 return 0;
135 }
136
mlx5e_ipsec_set_swp(struct sk_buff * skb,struct mlx5_wqe_eth_seg * eseg,u8 mode,struct xfrm_offload * xo)137 static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
138 struct mlx5_wqe_eth_seg *eseg, u8 mode,
139 struct xfrm_offload *xo)
140 {
141 struct mlx5e_swp_spec swp_spec = {};
142
143 /* Tunnel Mode:
144 * SWP: OutL3 InL3 InL4
145 * Pkt: MAC IP ESP IP L4
146 *
147 * Transport Mode:
148 * SWP: OutL3 InL4
149 * InL3
150 * Pkt: MAC IP ESP L4
151 */
152 swp_spec.l3_proto = skb->protocol;
153 swp_spec.is_tun = mode == XFRM_MODE_TUNNEL;
154 if (swp_spec.is_tun) {
155 if (xo->proto == IPPROTO_IPV6) {
156 swp_spec.tun_l3_proto = htons(ETH_P_IPV6);
157 swp_spec.tun_l4_proto = inner_ipv6_hdr(skb)->nexthdr;
158 } else {
159 swp_spec.tun_l3_proto = htons(ETH_P_IP);
160 swp_spec.tun_l4_proto = inner_ip_hdr(skb)->protocol;
161 }
162 } else {
163 swp_spec.tun_l3_proto = skb->protocol;
164 swp_spec.tun_l4_proto = xo->proto;
165 }
166
167 mlx5e_set_eseg_swp(skb, eseg, &swp_spec);
168 }
169
mlx5e_ipsec_set_iv_esn(struct sk_buff * skb,struct xfrm_state * x,struct xfrm_offload * xo)170 void mlx5e_ipsec_set_iv_esn(struct sk_buff *skb, struct xfrm_state *x,
171 struct xfrm_offload *xo)
172 {
173 struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
174 __u32 oseq = replay_esn->oseq;
175 int iv_offset;
176 __be64 seqno;
177 u32 seq_hi;
178
179 if (unlikely(skb_is_gso(skb) && oseq < MLX5E_IPSEC_ESN_SCOPE_MID &&
180 MLX5E_IPSEC_ESN_SCOPE_MID < (oseq - skb_shinfo(skb)->gso_segs))) {
181 seq_hi = xo->seq.hi - 1;
182 } else {
183 seq_hi = xo->seq.hi;
184 }
185
186 /* Place the SN in the IV field */
187 seqno = cpu_to_be64(xo->seq.low + ((u64)seq_hi << 32));
188 iv_offset = skb_transport_offset(skb) + sizeof(struct ip_esp_hdr);
189 skb_store_bits(skb, iv_offset, &seqno, 8);
190 }
191
mlx5e_ipsec_set_iv(struct sk_buff * skb,struct xfrm_state * x,struct xfrm_offload * xo)192 void mlx5e_ipsec_set_iv(struct sk_buff *skb, struct xfrm_state *x,
193 struct xfrm_offload *xo)
194 {
195 int iv_offset;
196 __be64 seqno;
197
198 /* Place the SN in the IV field */
199 seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32));
200 iv_offset = skb_transport_offset(skb) + sizeof(struct ip_esp_hdr);
201 skb_store_bits(skb, iv_offset, &seqno, 8);
202 }
203
mlx5e_ipsec_set_metadata(struct sk_buff * skb,struct mlx5e_ipsec_metadata * mdata,struct xfrm_offload * xo)204 static void mlx5e_ipsec_set_metadata(struct sk_buff *skb,
205 struct mlx5e_ipsec_metadata *mdata,
206 struct xfrm_offload *xo)
207 {
208 struct ip_esp_hdr *esph;
209 struct tcphdr *tcph;
210
211 if (skb_is_gso(skb)) {
212 /* Add LSO metadata indication */
213 esph = ip_esp_hdr(skb);
214 tcph = inner_tcp_hdr(skb);
215 netdev_dbg(skb->dev, " Offloading GSO packet outer L3 %u; L4 %u; Inner L3 %u; L4 %u\n",
216 skb->network_header,
217 skb->transport_header,
218 skb->inner_network_header,
219 skb->inner_transport_header);
220 netdev_dbg(skb->dev, " Offloading GSO packet of len %u; mss %u; TCP sp %u dp %u seq 0x%x ESP seq 0x%x\n",
221 skb->len, skb_shinfo(skb)->gso_size,
222 ntohs(tcph->source), ntohs(tcph->dest),
223 ntohl(tcph->seq), ntohl(esph->seq_no));
224 mdata->syndrome = MLX5E_IPSEC_TX_SYNDROME_OFFLOAD_WITH_LSO_TCP;
225 mdata->content.tx.mss_inv = mlx5e_ipsec_mss_inv(skb);
226 mdata->content.tx.seq = htons(ntohl(tcph->seq) & 0xFFFF);
227 } else {
228 mdata->syndrome = MLX5E_IPSEC_TX_SYNDROME_OFFLOAD;
229 }
230 mdata->content.tx.esp_next_proto = xo->proto;
231
232 netdev_dbg(skb->dev, " TX metadata syndrome %u proto %u mss_inv %04x seq %04x\n",
233 mdata->syndrome, mdata->content.tx.esp_next_proto,
234 ntohs(mdata->content.tx.mss_inv),
235 ntohs(mdata->content.tx.seq));
236 }
237
mlx5e_ipsec_handle_tx_wqe(struct mlx5e_tx_wqe * wqe,struct mlx5e_accel_tx_ipsec_state * ipsec_st,struct mlx5_wqe_inline_seg * inlseg)238 void mlx5e_ipsec_handle_tx_wqe(struct mlx5e_tx_wqe *wqe,
239 struct mlx5e_accel_tx_ipsec_state *ipsec_st,
240 struct mlx5_wqe_inline_seg *inlseg)
241 {
242 inlseg->byte_count = cpu_to_be32(ipsec_st->tailen | MLX5_INLINE_SEG);
243 esp_output_fill_trailer((u8 *)inlseg->data, 0, ipsec_st->plen, ipsec_st->xo->proto);
244 }
245
mlx5e_ipsec_set_state(struct mlx5e_priv * priv,struct sk_buff * skb,struct xfrm_state * x,struct xfrm_offload * xo,struct mlx5e_accel_tx_ipsec_state * ipsec_st)246 static int mlx5e_ipsec_set_state(struct mlx5e_priv *priv,
247 struct sk_buff *skb,
248 struct xfrm_state *x,
249 struct xfrm_offload *xo,
250 struct mlx5e_accel_tx_ipsec_state *ipsec_st)
251 {
252 unsigned int blksize, clen, alen, plen;
253 struct crypto_aead *aead;
254 unsigned int tailen;
255
256 ipsec_st->x = x;
257 ipsec_st->xo = xo;
258 if (mlx5_is_ipsec_device(priv->mdev)) {
259 aead = x->data;
260 alen = crypto_aead_authsize(aead);
261 blksize = ALIGN(crypto_aead_blocksize(aead), 4);
262 clen = ALIGN(skb->len + 2, blksize);
263 plen = max_t(u32, clen - skb->len, 4);
264 tailen = plen + alen;
265 ipsec_st->plen = plen;
266 ipsec_st->tailen = tailen;
267 }
268
269 return 0;
270 }
271
mlx5e_ipsec_tx_build_eseg(struct mlx5e_priv * priv,struct sk_buff * skb,struct mlx5_wqe_eth_seg * eseg)272 void mlx5e_ipsec_tx_build_eseg(struct mlx5e_priv *priv, struct sk_buff *skb,
273 struct mlx5_wqe_eth_seg *eseg)
274 {
275 struct xfrm_offload *xo = xfrm_offload(skb);
276 struct xfrm_encap_tmpl *encap;
277 struct xfrm_state *x;
278 struct sec_path *sp;
279 u8 l3_proto;
280
281 sp = skb_sec_path(skb);
282 if (unlikely(sp->len != 1))
283 return;
284
285 x = xfrm_input_state(skb);
286 if (unlikely(!x))
287 return;
288
289 if (unlikely(!x->xso.offload_handle ||
290 (skb->protocol != htons(ETH_P_IP) &&
291 skb->protocol != htons(ETH_P_IPV6))))
292 return;
293
294 mlx5e_ipsec_set_swp(skb, eseg, x->props.mode, xo);
295
296 l3_proto = (x->props.family == AF_INET) ?
297 ((struct iphdr *)skb_network_header(skb))->protocol :
298 ((struct ipv6hdr *)skb_network_header(skb))->nexthdr;
299
300 if (mlx5_is_ipsec_device(priv->mdev)) {
301 eseg->flow_table_metadata |= cpu_to_be32(MLX5_ETH_WQE_FT_META_IPSEC);
302 eseg->trailer |= cpu_to_be32(MLX5_ETH_WQE_INSERT_TRAILER);
303 encap = x->encap;
304 if (!encap) {
305 eseg->trailer |= (l3_proto == IPPROTO_ESP) ?
306 cpu_to_be32(MLX5_ETH_WQE_TRAILER_HDR_OUTER_IP_ASSOC) :
307 cpu_to_be32(MLX5_ETH_WQE_TRAILER_HDR_OUTER_L4_ASSOC);
308 } else if (encap->encap_type == UDP_ENCAP_ESPINUDP) {
309 eseg->trailer |= (l3_proto == IPPROTO_ESP) ?
310 cpu_to_be32(MLX5_ETH_WQE_TRAILER_HDR_INNER_IP_ASSOC) :
311 cpu_to_be32(MLX5_ETH_WQE_TRAILER_HDR_INNER_L4_ASSOC);
312 }
313 }
314 }
315
mlx5e_ipsec_handle_tx_skb(struct net_device * netdev,struct sk_buff * skb,struct mlx5e_accel_tx_ipsec_state * ipsec_st)316 bool mlx5e_ipsec_handle_tx_skb(struct net_device *netdev,
317 struct sk_buff *skb,
318 struct mlx5e_accel_tx_ipsec_state *ipsec_st)
319 {
320 struct mlx5e_priv *priv = netdev_priv(netdev);
321 struct xfrm_offload *xo = xfrm_offload(skb);
322 struct mlx5e_ipsec_sa_entry *sa_entry;
323 struct mlx5e_ipsec_metadata *mdata;
324 struct xfrm_state *x;
325 struct sec_path *sp;
326
327 sp = skb_sec_path(skb);
328 if (unlikely(sp->len != 1)) {
329 atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_bundle);
330 goto drop;
331 }
332
333 x = xfrm_input_state(skb);
334 if (unlikely(!x)) {
335 atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_no_state);
336 goto drop;
337 }
338
339 if (unlikely(!x->xso.offload_handle ||
340 (skb->protocol != htons(ETH_P_IP) &&
341 skb->protocol != htons(ETH_P_IPV6)))) {
342 atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_not_ip);
343 goto drop;
344 }
345
346 if (!skb_is_gso(skb))
347 if (unlikely(mlx5e_ipsec_remove_trailer(skb, x))) {
348 atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_trailer);
349 goto drop;
350 }
351
352 if (MLX5_CAP_GEN(priv->mdev, fpga)) {
353 mdata = mlx5e_ipsec_add_metadata(skb);
354 if (IS_ERR(mdata)) {
355 atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_metadata);
356 goto drop;
357 }
358 }
359
360 sa_entry = (struct mlx5e_ipsec_sa_entry *)x->xso.offload_handle;
361 sa_entry->set_iv_op(skb, x, xo);
362 if (MLX5_CAP_GEN(priv->mdev, fpga))
363 mlx5e_ipsec_set_metadata(skb, mdata, xo);
364
365 mlx5e_ipsec_set_state(priv, skb, x, xo, ipsec_st);
366
367 return true;
368
369 drop:
370 kfree_skb(skb);
371 return false;
372 }
373
374 static inline struct xfrm_state *
mlx5e_ipsec_build_sp(struct net_device * netdev,struct sk_buff * skb,struct mlx5e_ipsec_metadata * mdata)375 mlx5e_ipsec_build_sp(struct net_device *netdev, struct sk_buff *skb,
376 struct mlx5e_ipsec_metadata *mdata)
377 {
378 struct mlx5e_priv *priv = netdev_priv(netdev);
379 struct xfrm_offload *xo;
380 struct xfrm_state *xs;
381 struct sec_path *sp;
382 u32 sa_handle;
383
384 sp = secpath_set(skb);
385 if (unlikely(!sp)) {
386 atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_sp_alloc);
387 return NULL;
388 }
389
390 sa_handle = be32_to_cpu(mdata->content.rx.sa_handle);
391 xs = mlx5e_ipsec_sadb_rx_lookup(priv->ipsec, sa_handle);
392 if (unlikely(!xs)) {
393 atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_sadb_miss);
394 return NULL;
395 }
396
397 sp = skb_sec_path(skb);
398 sp->xvec[sp->len++] = xs;
399 sp->olen++;
400
401 xo = xfrm_offload(skb);
402 xo->flags = CRYPTO_DONE;
403 switch (mdata->syndrome) {
404 case MLX5E_IPSEC_RX_SYNDROME_DECRYPTED:
405 xo->status = CRYPTO_SUCCESS;
406 if (likely(priv->ipsec->no_trailer)) {
407 xo->flags |= XFRM_ESP_NO_TRAILER;
408 xo->proto = mdata->content.rx.nexthdr;
409 }
410 break;
411 case MLX5E_IPSEC_RX_SYNDROME_AUTH_FAILED:
412 xo->status = CRYPTO_TUNNEL_ESP_AUTH_FAILED;
413 break;
414 case MLX5E_IPSEC_RX_SYNDROME_BAD_PROTO:
415 xo->status = CRYPTO_INVALID_PROTOCOL;
416 break;
417 default:
418 atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_syndrome);
419 return NULL;
420 }
421 return xs;
422 }
423
mlx5e_ipsec_handle_rx_skb(struct net_device * netdev,struct sk_buff * skb,u32 * cqe_bcnt)424 struct sk_buff *mlx5e_ipsec_handle_rx_skb(struct net_device *netdev,
425 struct sk_buff *skb, u32 *cqe_bcnt)
426 {
427 struct mlx5e_ipsec_metadata *mdata;
428 struct xfrm_state *xs;
429
430 if (!is_metadata_hdr_valid(skb))
431 return skb;
432
433 /* Use the metadata */
434 mdata = (struct mlx5e_ipsec_metadata *)(skb->data + ETH_HLEN);
435 xs = mlx5e_ipsec_build_sp(netdev, skb, mdata);
436 if (unlikely(!xs)) {
437 kfree_skb(skb);
438 return NULL;
439 }
440
441 remove_metadata_hdr(skb);
442 *cqe_bcnt -= MLX5E_METADATA_ETHER_LEN;
443
444 return skb;
445 }
446
447 enum {
448 MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED,
449 MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_AUTH_FAILED,
450 MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_BAD_TRAILER,
451 };
452
mlx5e_ipsec_offload_handle_rx_skb(struct net_device * netdev,struct sk_buff * skb,struct mlx5_cqe64 * cqe)453 void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
454 struct sk_buff *skb,
455 struct mlx5_cqe64 *cqe)
456 {
457 u32 ipsec_meta_data = be32_to_cpu(cqe->ft_metadata);
458 struct mlx5e_priv *priv;
459 struct xfrm_offload *xo;
460 struct xfrm_state *xs;
461 struct sec_path *sp;
462 u32 sa_handle;
463
464 sa_handle = MLX5_IPSEC_METADATA_HANDLE(ipsec_meta_data);
465 priv = netdev_priv(netdev);
466 sp = secpath_set(skb);
467 if (unlikely(!sp)) {
468 atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_sp_alloc);
469 return;
470 }
471
472 xs = mlx5e_ipsec_sadb_rx_lookup(priv->ipsec, sa_handle);
473 if (unlikely(!xs)) {
474 atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_sadb_miss);
475 return;
476 }
477
478 sp = skb_sec_path(skb);
479 sp->xvec[sp->len++] = xs;
480 sp->olen++;
481
482 xo = xfrm_offload(skb);
483 xo->flags = CRYPTO_DONE;
484
485 switch (MLX5_IPSEC_METADATA_SYNDROM(ipsec_meta_data)) {
486 case MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED:
487 xo->status = CRYPTO_SUCCESS;
488 if (WARN_ON_ONCE(priv->ipsec->no_trailer))
489 xo->flags |= XFRM_ESP_NO_TRAILER;
490 break;
491 case MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_AUTH_FAILED:
492 xo->status = CRYPTO_TUNNEL_ESP_AUTH_FAILED;
493 break;
494 case MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_BAD_TRAILER:
495 xo->status = CRYPTO_INVALID_PACKET_SYNTAX;
496 break;
497 default:
498 atomic64_inc(&priv->ipsec->sw_stats.ipsec_rx_drop_syndrome);
499 }
500 }
501
mlx5e_ipsec_feature_check(struct sk_buff * skb,struct net_device * netdev,netdev_features_t features)502 bool mlx5e_ipsec_feature_check(struct sk_buff *skb, struct net_device *netdev,
503 netdev_features_t features)
504 {
505 struct sec_path *sp = skb_sec_path(skb);
506 struct xfrm_state *x;
507
508 if (sp && sp->len) {
509 x = sp->xvec[0];
510 if (x && x->xso.offload_handle)
511 return true;
512 }
513 return false;
514 }
515
mlx5e_ipsec_build_inverse_table(void)516 void mlx5e_ipsec_build_inverse_table(void)
517 {
518 u16 mss_inv;
519 u32 mss;
520
521 /* Calculate 1/x inverse table for use in GSO data path.
522 * Using this table, we provide the IPSec accelerator with the value of
523 * 1/gso_size so that it can infer the position of each segment inside
524 * the GSO, and increment the ESP sequence number, and generate the IV.
525 * The HW needs this value in Q0.16 fixed-point number format
526 */
527 mlx5e_ipsec_inverse_table[1] = htons(0xFFFF);
528 for (mss = 2; mss < MAX_LSO_MSS; mss++) {
529 mss_inv = div_u64(1ULL << 32, mss) >> 16;
530 mlx5e_ipsec_inverse_table[mss] = htons(mss_inv);
531 }
532 }
533