1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Intel Corporation 3 */ 4 5 #include <stdbool.h> 6 #include <errno.h> 7 8 #include <rte_memcpy.h> 9 #include <rte_mempool.h> 10 11 #include "gso_common.h" 12 13 static inline void 14 hdr_segment_init(struct rte_mbuf *hdr_segment, struct rte_mbuf *pkt, 15 uint16_t pkt_hdr_offset) 16 { 17 /* Copy MBUF metadata */ 18 hdr_segment->nb_segs = 1; 19 hdr_segment->port = pkt->port; 20 hdr_segment->ol_flags = pkt->ol_flags; 21 hdr_segment->packet_type = pkt->packet_type; 22 hdr_segment->pkt_len = pkt_hdr_offset; 23 hdr_segment->data_len = pkt_hdr_offset; 24 hdr_segment->tx_offload = pkt->tx_offload; 25 26 /* Copy the packet header */ 27 rte_memcpy(rte_pktmbuf_mtod(hdr_segment, char *), 28 rte_pktmbuf_mtod(pkt, char *), 29 pkt_hdr_offset); 30 } 31 32 static inline void 33 free_gso_segment(struct rte_mbuf **pkts, uint16_t nb_pkts) 34 { 35 uint16_t i; 36 37 for (i = 0; i < nb_pkts; i++) 38 rte_pktmbuf_free(pkts[i]); 39 } 40 41 int 42 gso_do_segment(struct rte_mbuf *pkt, 43 uint16_t pkt_hdr_offset, 44 uint16_t pyld_unit_size, 45 struct rte_mempool *direct_pool, 46 struct rte_mempool *indirect_pool, 47 struct rte_mbuf **pkts_out, 48 uint16_t nb_pkts_out) 49 { 50 struct rte_mbuf *pkt_in; 51 struct rte_mbuf *hdr_segment, *pyld_segment, *prev_segment; 52 uint16_t pkt_in_data_pos, segment_bytes_remaining; 53 uint16_t pyld_len, nb_segs; 54 bool more_in_pkt, more_out_segs; 55 56 pkt_in = pkt; 57 nb_segs = 0; 58 more_in_pkt = 1; 59 pkt_in_data_pos = pkt_hdr_offset; 60 61 while (more_in_pkt) { 62 if (unlikely(nb_segs >= nb_pkts_out)) { 63 free_gso_segment(pkts_out, nb_segs); 64 return -EINVAL; 65 } 66 67 /* Allocate a direct MBUF */ 68 hdr_segment = rte_pktmbuf_alloc(direct_pool); 69 if (unlikely(hdr_segment == NULL)) { 70 free_gso_segment(pkts_out, nb_segs); 71 return -ENOMEM; 72 } 73 /* Fill the packet header */ 74 hdr_segment_init(hdr_segment, pkt, pkt_hdr_offset); 75 76 prev_segment = hdr_segment; 77 segment_bytes_remaining = pyld_unit_size; 78 more_out_segs = 1; 79 80 while (more_out_segs && more_in_pkt) { 81 /* Allocate an indirect MBUF */ 82 pyld_segment = rte_pktmbuf_alloc(indirect_pool); 83 if (unlikely(pyld_segment == NULL)) { 84 rte_pktmbuf_free(hdr_segment); 85 free_gso_segment(pkts_out, nb_segs); 86 return -ENOMEM; 87 } 88 /* Attach to current MBUF segment of pkt */ 89 rte_pktmbuf_attach(pyld_segment, pkt_in); 90 91 prev_segment->next = pyld_segment; 92 prev_segment = pyld_segment; 93 94 pyld_len = segment_bytes_remaining; 95 if (pyld_len + pkt_in_data_pos > pkt_in->data_len) 96 pyld_len = pkt_in->data_len - pkt_in_data_pos; 97 98 pyld_segment->data_off = pkt_in_data_pos + 99 pkt_in->data_off; 100 pyld_segment->data_len = pyld_len; 101 102 /* Update header segment */ 103 hdr_segment->pkt_len += pyld_len; 104 hdr_segment->nb_segs++; 105 106 pkt_in_data_pos += pyld_len; 107 segment_bytes_remaining -= pyld_len; 108 109 /* Finish processing a MBUF segment of pkt */ 110 if (pkt_in_data_pos == pkt_in->data_len) { 111 pkt_in = pkt_in->next; 112 pkt_in_data_pos = 0; 113 if (pkt_in == NULL) 114 more_in_pkt = 0; 115 } 116 117 /* Finish generating a GSO segment */ 118 if (segment_bytes_remaining == 0) 119 more_out_segs = 0; 120 } 121 pkts_out[nb_segs++] = hdr_segment; 122 } 123 return nb_segs; 124 } 125