1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2017 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdbool.h> 35 #include <errno.h> 36 37 #include <rte_memcpy.h> 38 #include <rte_mempool.h> 39 40 #include "gso_common.h" 41 42 static inline void 43 hdr_segment_init(struct rte_mbuf *hdr_segment, struct rte_mbuf *pkt, 44 uint16_t pkt_hdr_offset) 45 { 46 /* Copy MBUF metadata */ 47 hdr_segment->nb_segs = 1; 48 hdr_segment->port = pkt->port; 49 hdr_segment->ol_flags = pkt->ol_flags; 50 hdr_segment->packet_type = pkt->packet_type; 51 hdr_segment->pkt_len = pkt_hdr_offset; 52 hdr_segment->data_len = pkt_hdr_offset; 53 hdr_segment->tx_offload = pkt->tx_offload; 54 55 /* Copy the packet header */ 56 rte_memcpy(rte_pktmbuf_mtod(hdr_segment, char *), 57 rte_pktmbuf_mtod(pkt, char *), 58 pkt_hdr_offset); 59 } 60 61 static inline void 62 free_gso_segment(struct rte_mbuf **pkts, uint16_t nb_pkts) 63 { 64 uint16_t i; 65 66 for (i = 0; i < nb_pkts; i++) 67 rte_pktmbuf_free(pkts[i]); 68 } 69 70 int 71 gso_do_segment(struct rte_mbuf *pkt, 72 uint16_t pkt_hdr_offset, 73 uint16_t pyld_unit_size, 74 struct rte_mempool *direct_pool, 75 struct rte_mempool *indirect_pool, 76 struct rte_mbuf **pkts_out, 77 uint16_t nb_pkts_out) 78 { 79 struct rte_mbuf *pkt_in; 80 struct rte_mbuf *hdr_segment, *pyld_segment, *prev_segment; 81 uint16_t pkt_in_data_pos, segment_bytes_remaining; 82 uint16_t pyld_len, nb_segs; 83 bool more_in_pkt, more_out_segs; 84 85 pkt_in = pkt; 86 nb_segs = 0; 87 more_in_pkt = 1; 88 pkt_in_data_pos = pkt_hdr_offset; 89 90 while (more_in_pkt) { 91 if (unlikely(nb_segs >= nb_pkts_out)) { 92 free_gso_segment(pkts_out, nb_segs); 93 return -EINVAL; 94 } 95 96 /* Allocate a direct MBUF */ 97 hdr_segment = rte_pktmbuf_alloc(direct_pool); 98 if (unlikely(hdr_segment == NULL)) { 99 free_gso_segment(pkts_out, nb_segs); 100 return -ENOMEM; 101 } 102 /* Fill the packet header */ 103 hdr_segment_init(hdr_segment, pkt, pkt_hdr_offset); 104 105 prev_segment = hdr_segment; 106 segment_bytes_remaining = pyld_unit_size; 107 more_out_segs = 1; 108 109 while (more_out_segs && more_in_pkt) { 110 /* Allocate an indirect MBUF */ 111 pyld_segment = rte_pktmbuf_alloc(indirect_pool); 112 if (unlikely(pyld_segment == NULL)) { 113 rte_pktmbuf_free(hdr_segment); 114 free_gso_segment(pkts_out, nb_segs); 115 return -ENOMEM; 116 } 117 /* Attach to current MBUF segment of pkt */ 118 rte_pktmbuf_attach(pyld_segment, pkt_in); 119 120 prev_segment->next = pyld_segment; 121 prev_segment = pyld_segment; 122 123 pyld_len = segment_bytes_remaining; 124 if (pyld_len + pkt_in_data_pos > pkt_in->data_len) 125 pyld_len = pkt_in->data_len - pkt_in_data_pos; 126 127 pyld_segment->data_off = pkt_in_data_pos + 128 pkt_in->data_off; 129 pyld_segment->data_len = pyld_len; 130 131 /* Update header segment */ 132 hdr_segment->pkt_len += pyld_len; 133 hdr_segment->nb_segs++; 134 135 pkt_in_data_pos += pyld_len; 136 segment_bytes_remaining -= pyld_len; 137 138 /* Finish processing a MBUF segment of pkt */ 139 if (pkt_in_data_pos == pkt_in->data_len) { 140 pkt_in = pkt_in->next; 141 pkt_in_data_pos = 0; 142 if (pkt_in == NULL) 143 more_in_pkt = 0; 144 } 145 146 /* Finish generating a GSO segment */ 147 if (segment_bytes_remaining == 0) 148 more_out_segs = 0; 149 } 150 pkts_out[nb_segs++] = hdr_segment; 151 } 152 return nb_segs; 153 } 154