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