1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 #include <string.h> 5 6 #include <rte_ether.h> 7 #include <rte_ip_frag.h> 8 #include <rte_memory.h> 9 10 #include "rte_port_frag.h" 11 12 /* Max number of fragments per packet allowed */ 13 #define RTE_PORT_FRAG_MAX_FRAGS_PER_PACKET 0x80 14 15 #ifdef RTE_PORT_STATS_COLLECT 16 17 #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_IN_ADD(port, val) \ 18 port->stats.n_pkts_in += val 19 #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_DROP_ADD(port, val) \ 20 port->stats.n_pkts_drop += val 21 22 #else 23 24 #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_IN_ADD(port, val) 25 #define RTE_PORT_RING_READER_FRAG_STATS_PKTS_DROP_ADD(port, val) 26 27 #endif 28 29 typedef int32_t 30 (*frag_op)(struct rte_mbuf *pkt_in, 31 struct rte_mbuf **pkts_out, 32 uint16_t nb_pkts_out, 33 uint16_t mtu_size, 34 struct rte_mempool *pool_direct, 35 struct rte_mempool *pool_indirect); 36 37 struct rte_port_ring_reader_frag { 38 struct rte_port_in_stats stats; 39 40 /* Input parameters */ 41 struct rte_ring *ring; 42 uint32_t mtu; 43 uint32_t metadata_size; 44 struct rte_mempool *pool_direct; 45 struct rte_mempool *pool_indirect; 46 47 /* Internal buffers */ 48 struct rte_mbuf *pkts[RTE_PORT_IN_BURST_SIZE_MAX]; 49 struct rte_mbuf *frags[RTE_PORT_FRAG_MAX_FRAGS_PER_PACKET]; 50 uint32_t n_pkts; 51 uint32_t pos_pkts; 52 uint32_t n_frags; 53 uint32_t pos_frags; 54 55 frag_op f_frag; 56 } __rte_cache_aligned; 57 58 static void * 59 rte_port_ring_reader_frag_create(void *params, int socket_id, int is_ipv4) 60 { 61 struct rte_port_ring_reader_frag_params *conf = 62 params; 63 struct rte_port_ring_reader_frag *port; 64 65 /* Check input parameters */ 66 if (conf == NULL) { 67 RTE_LOG(ERR, PORT, "%s: Parameter conf is NULL\n", __func__); 68 return NULL; 69 } 70 if (conf->ring == NULL) { 71 RTE_LOG(ERR, PORT, "%s: Parameter ring is NULL\n", __func__); 72 return NULL; 73 } 74 if (conf->mtu == 0) { 75 RTE_LOG(ERR, PORT, "%s: Parameter mtu is invalid\n", __func__); 76 return NULL; 77 } 78 if (conf->pool_direct == NULL) { 79 RTE_LOG(ERR, PORT, "%s: Parameter pool_direct is NULL\n", 80 __func__); 81 return NULL; 82 } 83 if (conf->pool_indirect == NULL) { 84 RTE_LOG(ERR, PORT, "%s: Parameter pool_indirect is NULL\n", 85 __func__); 86 return NULL; 87 } 88 89 /* Memory allocation */ 90 port = rte_zmalloc_socket("PORT", sizeof(*port), RTE_CACHE_LINE_SIZE, 91 socket_id); 92 if (port == NULL) { 93 RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__); 94 return NULL; 95 } 96 97 /* Initialization */ 98 port->ring = conf->ring; 99 port->mtu = conf->mtu; 100 port->metadata_size = conf->metadata_size; 101 port->pool_direct = conf->pool_direct; 102 port->pool_indirect = conf->pool_indirect; 103 104 port->n_pkts = 0; 105 port->pos_pkts = 0; 106 port->n_frags = 0; 107 port->pos_frags = 0; 108 109 port->f_frag = (is_ipv4) ? 110 rte_ipv4_fragment_packet : rte_ipv6_fragment_packet; 111 112 return port; 113 } 114 115 static void * 116 rte_port_ring_reader_ipv4_frag_create(void *params, int socket_id) 117 { 118 return rte_port_ring_reader_frag_create(params, socket_id, 1); 119 } 120 121 static void * 122 rte_port_ring_reader_ipv6_frag_create(void *params, int socket_id) 123 { 124 return rte_port_ring_reader_frag_create(params, socket_id, 0); 125 } 126 127 static int 128 rte_port_ring_reader_frag_rx(void *port, 129 struct rte_mbuf **pkts, 130 uint32_t n_pkts) 131 { 132 struct rte_port_ring_reader_frag *p = 133 port; 134 uint32_t n_pkts_out; 135 136 n_pkts_out = 0; 137 138 /* Get packets from the "frag" buffer */ 139 if (p->n_frags >= n_pkts) { 140 memcpy(pkts, &p->frags[p->pos_frags], n_pkts * sizeof(void *)); 141 p->pos_frags += n_pkts; 142 p->n_frags -= n_pkts; 143 144 return n_pkts; 145 } 146 147 memcpy(pkts, &p->frags[p->pos_frags], p->n_frags * sizeof(void *)); 148 n_pkts_out = p->n_frags; 149 p->n_frags = 0; 150 151 /* Look to "pkts" buffer to get more packets */ 152 for ( ; ; ) { 153 struct rte_mbuf *pkt; 154 uint32_t n_pkts_to_provide, i; 155 int status; 156 157 /* If "pkts" buffer is empty, read packet burst from ring */ 158 if (p->n_pkts == 0) { 159 p->n_pkts = rte_ring_sc_dequeue_burst(p->ring, 160 (void **) p->pkts, RTE_PORT_IN_BURST_SIZE_MAX, 161 NULL); 162 RTE_PORT_RING_READER_FRAG_STATS_PKTS_IN_ADD(p, p->n_pkts); 163 if (p->n_pkts == 0) 164 return n_pkts_out; 165 p->pos_pkts = 0; 166 } 167 168 /* Read next packet from "pkts" buffer */ 169 pkt = p->pkts[p->pos_pkts++]; 170 p->n_pkts--; 171 172 /* If not jumbo, pass current packet to output */ 173 if (pkt->pkt_len <= p->mtu) { 174 pkts[n_pkts_out++] = pkt; 175 176 n_pkts_to_provide = n_pkts - n_pkts_out; 177 if (n_pkts_to_provide == 0) 178 return n_pkts; 179 180 continue; 181 } 182 183 /* Fragment current packet into the "frags" buffer */ 184 status = p->f_frag( 185 pkt, 186 p->frags, 187 RTE_PORT_FRAG_MAX_FRAGS_PER_PACKET, 188 p->mtu, 189 p->pool_direct, 190 p->pool_indirect 191 ); 192 193 if (status < 0) { 194 rte_pktmbuf_free(pkt); 195 RTE_PORT_RING_READER_FRAG_STATS_PKTS_DROP_ADD(p, 1); 196 continue; 197 } 198 199 p->n_frags = (uint32_t) status; 200 p->pos_frags = 0; 201 202 /* Copy meta-data from input jumbo packet to its fragments */ 203 for (i = 0; i < p->n_frags; i++) { 204 uint8_t *src = 205 RTE_MBUF_METADATA_UINT8_PTR(pkt, sizeof(struct rte_mbuf)); 206 uint8_t *dst = 207 RTE_MBUF_METADATA_UINT8_PTR(p->frags[i], sizeof(struct rte_mbuf)); 208 209 memcpy(dst, src, p->metadata_size); 210 } 211 212 /* Free input jumbo packet */ 213 rte_pktmbuf_free(pkt); 214 215 /* Get packets from "frag" buffer */ 216 n_pkts_to_provide = n_pkts - n_pkts_out; 217 if (p->n_frags >= n_pkts_to_provide) { 218 memcpy(&pkts[n_pkts_out], p->frags, 219 n_pkts_to_provide * sizeof(void *)); 220 p->n_frags -= n_pkts_to_provide; 221 p->pos_frags += n_pkts_to_provide; 222 223 return n_pkts; 224 } 225 226 memcpy(&pkts[n_pkts_out], p->frags, 227 p->n_frags * sizeof(void *)); 228 n_pkts_out += p->n_frags; 229 p->n_frags = 0; 230 } 231 } 232 233 static int 234 rte_port_ring_reader_frag_free(void *port) 235 { 236 if (port == NULL) { 237 RTE_LOG(ERR, PORT, "%s: Parameter port is NULL\n", __func__); 238 return -1; 239 } 240 241 rte_free(port); 242 243 return 0; 244 } 245 246 static int 247 rte_port_frag_reader_stats_read(void *port, 248 struct rte_port_in_stats *stats, int clear) 249 { 250 struct rte_port_ring_reader_frag *p = 251 port; 252 253 if (stats != NULL) 254 memcpy(stats, &p->stats, sizeof(p->stats)); 255 256 if (clear) 257 memset(&p->stats, 0, sizeof(p->stats)); 258 259 return 0; 260 } 261 262 /* 263 * Summary of port operations 264 */ 265 struct rte_port_in_ops rte_port_ring_reader_ipv4_frag_ops = { 266 .f_create = rte_port_ring_reader_ipv4_frag_create, 267 .f_free = rte_port_ring_reader_frag_free, 268 .f_rx = rte_port_ring_reader_frag_rx, 269 .f_stats = rte_port_frag_reader_stats_read, 270 }; 271 272 struct rte_port_in_ops rte_port_ring_reader_ipv6_frag_ops = { 273 .f_create = rte_port_ring_reader_ipv6_frag_create, 274 .f_free = rte_port_ring_reader_frag_free, 275 .f_rx = rte_port_ring_reader_frag_rx, 276 .f_stats = rte_port_frag_reader_stats_read, 277 }; 278