xref: /qemu/hw/net/net_rx_pkt.c (revision 7edf2f1d54454c0c0e5596b1112318cb91ec1afe)
1 /*
2  * QEMU RX packets abstractions
3  *
4  * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
5  *
6  * Developed by Daynix Computing LTD (http://www.daynix.com)
7  *
8  * Authors:
9  * Dmitry Fleytman <dmitry@daynix.com>
10  * Tamir Shomer <tamirs@daynix.com>
11  * Yan Vugenfirer <yan@daynix.com>
12  *
13  * This work is licensed under the terms of the GNU GPL, version 2 or later.
14  * See the COPYING file in the top-level directory.
15  *
16  */
17 
18 #include "qemu/osdep.h"
19 #include "trace.h"
20 #include "net_rx_pkt.h"
21 #include "net/checksum.h"
22 #include "net/tap.h"
23 
24 struct NetRxPkt {
25     struct virtio_net_hdr virt_hdr;
26     struct {
27         struct eth_header eth;
28         struct vlan_header vlan;
29     } ehdr_buf;
30     struct iovec *vec;
31     uint16_t vec_len_total;
32     uint16_t vec_len;
33     uint32_t tot_len;
34     uint16_t tci;
35     size_t ehdr_buf_len;
36     eth_pkt_types_e packet_type;
37 
38     /* Analysis results */
39     bool hasip4;
40     bool hasip6;
41 
42     size_t l3hdr_off;
43     size_t l4hdr_off;
44     size_t l5hdr_off;
45 
46     eth_ip6_hdr_info ip6hdr_info;
47     eth_ip4_hdr_info ip4hdr_info;
48     eth_l4_hdr_info  l4hdr_info;
49 };
50 
51 void net_rx_pkt_init(struct NetRxPkt **pkt)
52 {
53     struct NetRxPkt *p = g_malloc0(sizeof *p);
54     p->vec = NULL;
55     p->vec_len_total = 0;
56     *pkt = p;
57 }
58 
59 void net_rx_pkt_uninit(struct NetRxPkt *pkt)
60 {
61     if (pkt->vec_len_total != 0) {
62         g_free(pkt->vec);
63     }
64 
65     g_free(pkt);
66 }
67 
68 struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt *pkt)
69 {
70     assert(pkt);
71     return &pkt->virt_hdr;
72 }
73 
74 static inline void
75 net_rx_pkt_iovec_realloc(struct NetRxPkt *pkt,
76                             int new_iov_len)
77 {
78     if (pkt->vec_len_total < new_iov_len) {
79         g_free(pkt->vec);
80         pkt->vec = g_malloc(sizeof(*pkt->vec) * new_iov_len);
81         pkt->vec_len_total = new_iov_len;
82     }
83 }
84 
85 static void
86 net_rx_pkt_pull_data(struct NetRxPkt *pkt,
87                         const struct iovec *iov, int iovcnt,
88                         size_t ploff)
89 {
90     uint32_t pllen = iov_size(iov, iovcnt) - ploff;
91 
92     if (pkt->ehdr_buf_len) {
93         net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
94 
95         pkt->vec[0].iov_base = &pkt->ehdr_buf;
96         pkt->vec[0].iov_len = pkt->ehdr_buf_len;
97 
98         pkt->tot_len = pllen + pkt->ehdr_buf_len;
99         pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1,
100                                 iov, iovcnt, ploff, pllen) + 1;
101     } else {
102         net_rx_pkt_iovec_realloc(pkt, iovcnt);
103 
104         pkt->tot_len = pllen;
105         pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total,
106                                 iov, iovcnt, ploff, pkt->tot_len);
107     }
108 
109     eth_get_protocols(pkt->vec, pkt->vec_len, 0, &pkt->hasip4, &pkt->hasip6,
110                       &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
111                       &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
112 
113     trace_net_rx_pkt_parsed(pkt->hasip4, pkt->hasip6, pkt->l4hdr_info.proto,
114                             pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off);
115 }
116 
117 void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
118                                 const struct iovec *iov, int iovcnt,
119                                 size_t iovoff, bool strip_vlan)
120 {
121     uint16_t tci = 0;
122     uint16_t ploff = iovoff;
123     assert(pkt);
124 
125     if (strip_vlan) {
126         pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, &pkt->ehdr_buf,
127                                            &ploff, &tci);
128     } else {
129         pkt->ehdr_buf_len = 0;
130     }
131 
132     pkt->tci = tci;
133 
134     net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff);
135 }
136 
137 void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
138                                 const struct iovec *iov, int iovcnt,
139                                 size_t iovoff, bool strip_vlan,
140                                 uint16_t vet)
141 {
142     uint16_t tci = 0;
143     uint16_t ploff = iovoff;
144     assert(pkt);
145 
146     if (strip_vlan) {
147         pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
148                                               &pkt->ehdr_buf,
149                                               &ploff, &tci);
150     } else {
151         pkt->ehdr_buf_len = 0;
152     }
153 
154     pkt->tci = tci;
155 
156     net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff);
157 }
158 
159 void net_rx_pkt_dump(struct NetRxPkt *pkt)
160 {
161 #ifdef NET_RX_PKT_DEBUG
162     assert(pkt);
163 
164     printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n",
165               pkt->tot_len, pkt->ehdr_buf_len, pkt->tci);
166 #endif
167 }
168 
169 void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt,
170     eth_pkt_types_e packet_type)
171 {
172     assert(pkt);
173 
174     pkt->packet_type = packet_type;
175 
176 }
177 
178 eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt)
179 {
180     assert(pkt);
181 
182     return pkt->packet_type;
183 }
184 
185 size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt)
186 {
187     assert(pkt);
188 
189     return pkt->tot_len;
190 }
191 
192 void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
193                               const struct iovec *iov, size_t iovcnt,
194                               size_t iovoff)
195 {
196     assert(pkt);
197 
198     eth_get_protocols(iov, iovcnt, iovoff, &pkt->hasip4, &pkt->hasip6,
199                       &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
200                       &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
201 }
202 
203 void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
204                               bool *hasip4, bool *hasip6,
205                               EthL4HdrProto *l4hdr_proto)
206 {
207     assert(pkt);
208 
209     *hasip4 = pkt->hasip4;
210     *hasip6 = pkt->hasip6;
211     *l4hdr_proto = pkt->l4hdr_info.proto;
212 }
213 
214 size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt)
215 {
216     assert(pkt);
217     return pkt->l3hdr_off;
218 }
219 
220 size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt)
221 {
222     assert(pkt);
223     return pkt->l4hdr_off;
224 }
225 
226 size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt)
227 {
228     assert(pkt);
229     return pkt->l5hdr_off;
230 }
231 
232 eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt)
233 {
234     return &pkt->ip6hdr_info;
235 }
236 
237 eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt)
238 {
239     return &pkt->ip4hdr_info;
240 }
241 
242 static inline void
243 _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written,
244                       void *ptr, size_t size)
245 {
246     memcpy(&rss_input[*bytes_written], ptr, size);
247     trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written);
248     *bytes_written += size;
249 }
250 
251 static inline void
252 _net_rx_rss_prepare_ip4(uint8_t *rss_input,
253                         struct NetRxPkt *pkt,
254                         size_t *bytes_written)
255 {
256     struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr;
257 
258     _net_rx_rss_add_chunk(rss_input, bytes_written,
259                           &ip4_hdr->ip_src, sizeof(uint32_t));
260 
261     _net_rx_rss_add_chunk(rss_input, bytes_written,
262                           &ip4_hdr->ip_dst, sizeof(uint32_t));
263 }
264 
265 static inline void
266 _net_rx_rss_prepare_ip6(uint8_t *rss_input,
267                         struct NetRxPkt *pkt,
268                         bool ipv6ex, size_t *bytes_written)
269 {
270     eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info;
271 
272     _net_rx_rss_add_chunk(rss_input, bytes_written,
273            (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src
274                                                  : &ip6info->ip6_hdr.ip6_src,
275            sizeof(struct in6_address));
276 
277     _net_rx_rss_add_chunk(rss_input, bytes_written,
278            (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst
279                                                  : &ip6info->ip6_hdr.ip6_dst,
280            sizeof(struct in6_address));
281 }
282 
283 static inline void
284 _net_rx_rss_prepare_tcp(uint8_t *rss_input,
285                         struct NetRxPkt *pkt,
286                         size_t *bytes_written)
287 {
288     struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp;
289 
290     _net_rx_rss_add_chunk(rss_input, bytes_written,
291                           &tcphdr->th_sport, sizeof(uint16_t));
292 
293     _net_rx_rss_add_chunk(rss_input, bytes_written,
294                           &tcphdr->th_dport, sizeof(uint16_t));
295 }
296 
297 static inline void
298 _net_rx_rss_prepare_udp(uint8_t *rss_input,
299                         struct NetRxPkt *pkt,
300                         size_t *bytes_written)
301 {
302     struct udp_header *udphdr = &pkt->l4hdr_info.hdr.udp;
303 
304     _net_rx_rss_add_chunk(rss_input, bytes_written,
305                           &udphdr->uh_sport, sizeof(uint16_t));
306 
307     _net_rx_rss_add_chunk(rss_input, bytes_written,
308                           &udphdr->uh_dport, sizeof(uint16_t));
309 }
310 
311 uint32_t
312 net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt,
313                          NetRxPktRssType type,
314                          uint8_t *key)
315 {
316     uint8_t rss_input[36];
317     size_t rss_length = 0;
318     uint32_t rss_hash = 0;
319     net_toeplitz_key key_data;
320 
321     switch (type) {
322     case NetPktRssIpV4:
323         assert(pkt->hasip4);
324         trace_net_rx_pkt_rss_ip4();
325         _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
326         break;
327     case NetPktRssIpV4Tcp:
328         assert(pkt->hasip4);
329         assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
330         trace_net_rx_pkt_rss_ip4_tcp();
331         _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
332         _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
333         break;
334     case NetPktRssIpV6Tcp:
335         assert(pkt->hasip6);
336         assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
337         trace_net_rx_pkt_rss_ip6_tcp();
338         _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
339         _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
340         break;
341     case NetPktRssIpV6:
342         assert(pkt->hasip6);
343         trace_net_rx_pkt_rss_ip6();
344         _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
345         break;
346     case NetPktRssIpV6Ex:
347         assert(pkt->hasip6);
348         trace_net_rx_pkt_rss_ip6_ex();
349         _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
350         break;
351     case NetPktRssIpV6TcpEx:
352         assert(pkt->hasip6);
353         assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
354         trace_net_rx_pkt_rss_ip6_ex_tcp();
355         _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
356         _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
357         break;
358     case NetPktRssIpV4Udp:
359         assert(pkt->hasip4);
360         assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
361         trace_net_rx_pkt_rss_ip4_udp();
362         _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
363         _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
364         break;
365     case NetPktRssIpV6Udp:
366         assert(pkt->hasip6);
367         assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
368         trace_net_rx_pkt_rss_ip6_udp();
369         _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
370         _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
371         break;
372     case NetPktRssIpV6UdpEx:
373         assert(pkt->hasip6);
374         assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
375         trace_net_rx_pkt_rss_ip6_ex_udp();
376         _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
377         _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
378         break;
379     default:
380         assert(false);
381         break;
382     }
383 
384     net_toeplitz_key_init(&key_data, key);
385     net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data);
386 
387     trace_net_rx_pkt_rss_hash(rss_length, rss_hash);
388 
389     return rss_hash;
390 }
391 
392 uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt)
393 {
394     assert(pkt);
395 
396     if (pkt->hasip4) {
397         return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id);
398     }
399 
400     return 0;
401 }
402 
403 bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt)
404 {
405     assert(pkt);
406 
407     if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) {
408         return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK;
409     }
410 
411     return false;
412 }
413 
414 bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt)
415 {
416     assert(pkt);
417 
418     if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) {
419         return pkt->l4hdr_info.has_tcp_data;
420     }
421 
422     return false;
423 }
424 
425 struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt)
426 {
427     assert(pkt);
428 
429     return pkt->vec;
430 }
431 
432 uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt)
433 {
434     assert(pkt);
435 
436     return pkt->vec_len;
437 }
438 
439 void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt,
440                             struct virtio_net_hdr *vhdr)
441 {
442     assert(pkt);
443 
444     memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr);
445 }
446 
447 void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt,
448     const struct iovec *iov, int iovcnt)
449 {
450     assert(pkt);
451 
452     iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr);
453 }
454 
455 void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt)
456 {
457     assert(pkt);
458 
459     memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr));
460 }
461 
462 bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
463 {
464     assert(pkt);
465 
466     return pkt->ehdr_buf_len ? true : false;
467 }
468 
469 uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt)
470 {
471     assert(pkt);
472 
473     return pkt->tci;
474 }
475 
476 bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid)
477 {
478     uint32_t cntr;
479     uint16_t csum;
480     uint32_t csl;
481 
482     trace_net_rx_pkt_l3_csum_validate_entry();
483 
484     if (!pkt->hasip4) {
485         trace_net_rx_pkt_l3_csum_validate_not_ip4();
486         return false;
487     }
488 
489     csl = pkt->l4hdr_off - pkt->l3hdr_off;
490 
491     cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len,
492                                 pkt->l3hdr_off,
493                                 csl, 0);
494 
495     csum = net_checksum_finish(cntr);
496 
497     *csum_valid = (csum == 0);
498 
499     trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl,
500                                            cntr, csum, *csum_valid);
501 
502     return true;
503 }
504 
505 static uint16_t
506 _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
507 {
508     uint32_t cntr;
509     uint16_t csum;
510     uint16_t csl;
511     uint32_t cso;
512 
513     trace_net_rx_pkt_l4_csum_calc_entry();
514 
515     if (pkt->hasip4) {
516         if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) {
517             csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen);
518             trace_net_rx_pkt_l4_csum_calc_ip4_udp();
519         } else {
520             csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) -
521                   IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr);
522             trace_net_rx_pkt_l4_csum_calc_ip4_tcp();
523         }
524 
525         cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr,
526                                             csl, &cso);
527         trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl);
528     } else {
529         if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) {
530             csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen);
531             trace_net_rx_pkt_l4_csum_calc_ip6_udp();
532         } else {
533             struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr;
534             size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off;
535             size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header);
536 
537             csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) -
538                   ip6opts_len;
539             trace_net_rx_pkt_l4_csum_calc_ip6_tcp();
540         }
541 
542         cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl,
543                                             pkt->ip6hdr_info.l4proto, &cso);
544         trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl);
545     }
546 
547     cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len,
548                                  pkt->l4hdr_off, csl, cso);
549 
550     csum = net_checksum_finish_nozero(cntr);
551 
552     trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum);
553 
554     return csum;
555 }
556 
557 bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
558 {
559     uint16_t csum;
560 
561     trace_net_rx_pkt_l4_csum_validate_entry();
562 
563     if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
564         pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
565         trace_net_rx_pkt_l4_csum_validate_not_xxp();
566         return false;
567     }
568 
569     if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
570         pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
571         trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
572         return false;
573     }
574 
575     if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
576         trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
577         return false;
578     }
579 
580     csum = _net_rx_pkt_calc_l4_csum(pkt);
581 
582     *csum_valid = ((csum == 0) || (csum == 0xFFFF));
583 
584     trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
585 
586     return true;
587 }
588 
589 bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt)
590 {
591     uint16_t csum = 0;
592     uint32_t l4_cso;
593 
594     trace_net_rx_pkt_l4_csum_fix_entry();
595 
596     switch (pkt->l4hdr_info.proto) {
597     case ETH_L4_HDR_PROTO_TCP:
598         l4_cso = offsetof(struct tcp_header, th_sum);
599         trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso);
600         break;
601 
602     case ETH_L4_HDR_PROTO_UDP:
603         if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
604             trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum();
605             return false;
606         }
607         l4_cso = offsetof(struct udp_header, uh_sum);
608         trace_net_rx_pkt_l4_csum_fix_udp(l4_cso);
609         break;
610 
611     default:
612         trace_net_rx_pkt_l4_csum_fix_not_xxp();
613         return false;
614     }
615 
616     if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
617             trace_net_rx_pkt_l4_csum_fix_ip4_fragment();
618             return false;
619     }
620 
621     /* Set zero to checksum word */
622     iov_from_buf(pkt->vec, pkt->vec_len,
623                  pkt->l4hdr_off + l4_cso,
624                  &csum, sizeof(csum));
625 
626     /* Calculate L4 checksum */
627     csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt));
628 
629     /* Set calculated checksum to checksum word */
630     iov_from_buf(pkt->vec, pkt->vec_len,
631                  pkt->l4hdr_off + l4_cso,
632                  &csum, sizeof(csum));
633 
634     trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum);
635 
636     return true;
637 }
638