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