1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <stdlib.h>
21 #include "os/os.h"
22 #include "mem/mem.h"
23
24 /**
25 * Generic mempool allocation function. Used with basic and extended mempools.
26 */
27 static int
mem_malloc_mempool_gen(uint16_t num_blocks,uint32_t block_size,void ** out_buf)28 mem_malloc_mempool_gen(uint16_t num_blocks, uint32_t block_size,
29 void **out_buf)
30 {
31 block_size = OS_ALIGN(block_size, OS_ALIGNMENT);
32
33 if (num_blocks > 0) {
34 *out_buf = malloc(OS_MEMPOOL_BYTES(num_blocks, block_size));
35 if (*out_buf == NULL) {
36 return OS_ENOMEM;
37 }
38 } else {
39 *out_buf = NULL;
40 }
41
42 return 0;
43 }
44
45 /**
46 * Mallocs a block of memory and initializes a mempool to use it.
47 *
48 * @param mempool The mempool to initialize.
49 * @param num_blocks The total number of memory blocks in the
50 * mempool.
51 * @param block_size The size of each mempool entry.
52 * @param name The name to give the mempool.
53 * @param out_buf On success, this points to the malloced memory.
54 * Pass NULL if you don't need this
55 * information.
56 *
57 * @return 0 on success;
58 * OS_ENOMEM on malloc failure;
59 * Other OS code on unexpected error.
60 */
61 int
mem_malloc_mempool(struct os_mempool * mempool,uint16_t num_blocks,uint32_t block_size,char * name,void ** out_buf)62 mem_malloc_mempool(struct os_mempool *mempool, uint16_t num_blocks,
63 uint32_t block_size, char *name, void **out_buf)
64 {
65 void *buf;
66 int rc;
67
68 rc = mem_malloc_mempool_gen(num_blocks, block_size, &buf);
69 if (rc != 0) {
70 return rc;
71 }
72
73 rc = os_mempool_init(mempool, num_blocks, block_size, buf, name);
74 if (rc != 0) {
75 free(buf);
76 return rc;
77 }
78
79 if (out_buf != NULL) {
80 *out_buf = buf;
81 }
82
83 return 0;
84 }
85
86 /**
87 * Mallocs a block of memory and initializes an extended mempool to use it.
88 *
89 * @param mpe The extended mempool to initialize.
90 * @param num_blocks The total number of memory blocks in the
91 * mempool.
92 * @param block_size The size of each mempool entry.
93 * @param name The name to give the mempool.
94 * @param out_buf On success, this points to the malloced memory.
95 * Pass NULL if you don't need this
96 * information.
97 *
98 * @return 0 on success;
99 * OS_ENOMEM on malloc failure;
100 * Other OS code on unexpected error.
101 */
102 int
mem_malloc_mempool_ext(struct os_mempool_ext * mpe,uint16_t num_blocks,uint32_t block_size,char * name,void ** out_buf)103 mem_malloc_mempool_ext(struct os_mempool_ext *mpe, uint16_t num_blocks,
104 uint32_t block_size, char *name, void **out_buf)
105 {
106 void *buf;
107 int rc;
108
109 rc = mem_malloc_mempool_gen(num_blocks, block_size, &buf);
110 if (rc != 0) {
111 return rc;
112 }
113
114 rc = os_mempool_ext_init(mpe, num_blocks, block_size, buf, name);
115 if (rc != 0) {
116 free(buf);
117 return rc;
118 }
119
120 if (out_buf != NULL) {
121 *out_buf = buf;
122 }
123
124 return 0;
125 }
126
127 /**
128 * Mallocs a block of memory and initializes an mbuf pool to use it. The
129 * specified block_size indicates the size of an mbuf acquired from the pool if
130 * it does not contain a pkthdr.
131 *
132 * @param mempool The mempool to initialize.
133 * @param mbuf_pool The mbuf pool to initialize.
134 * @param num_blocks The total number of mbufs in the pool.
135 * @param block_size The size of each mbuf.
136 * @param name The name to give the mempool.
137 * @param out_buf On success, this points to the malloced memory.
138 * Pass NULL if you don't need this
139 * information.
140 *
141 * @return 0 on success;
142 * OS_ENOMEM on malloc failure;
143 * Other OS code on unexpected error.
144 */
145 int
mem_malloc_mbuf_pool(struct os_mempool * mempool,struct os_mbuf_pool * mbuf_pool,uint16_t num_blocks,uint32_t block_size,char * name,void ** out_buf)146 mem_malloc_mbuf_pool(struct os_mempool *mempool,
147 struct os_mbuf_pool *mbuf_pool, uint16_t num_blocks,
148 uint32_t block_size, char *name,
149 void **out_buf)
150 {
151 void *buf;
152 int rc;
153
154 block_size = OS_ALIGN(block_size + sizeof (struct os_mbuf), OS_ALIGNMENT);
155
156 rc = mem_malloc_mempool(mempool, num_blocks, block_size, name, &buf);
157 if (rc != 0) {
158 return rc;
159 }
160
161 rc = os_mbuf_pool_init(mbuf_pool, mempool, block_size, num_blocks);
162 if (rc != 0) {
163 free(buf);
164 return rc;
165 }
166
167 if (out_buf != NULL) {
168 *out_buf = buf;
169 }
170
171 return 0;
172 }
173
174 /**
175 * Mallocs a block of memory and initializes an mbuf pool to use it. The
176 * specified block_size indicates the size of an mbuf acquired from the pool if
177 * it contains a pkthdr.
178 *
179 * @param mempool The mempool to initialize.
180 * @param mbuf_pool The mbuf pool to initialize.
181 * @param num_blocks The total number of mbufs in the pool.
182 * @param block_size The size of each mbuf.
183 * @param name The name to give the mempool.
184 * @param out_buf On success, this points to the malloced memory.
185 * Pass NULL if you don't need this
186 * information.
187 *
188 * @return 0 on success;
189 * OS_ENOMEM on malloc failure;
190 * Other OS code on unexpected error.
191 */
192 int
mem_malloc_mbufpkt_pool(struct os_mempool * mempool,struct os_mbuf_pool * mbuf_pool,int num_blocks,int block_size,char * name,void ** out_buf)193 mem_malloc_mbufpkt_pool(struct os_mempool *mempool,
194 struct os_mbuf_pool *mbuf_pool, int num_blocks,
195 int block_size, char *name,
196 void **out_buf)
197 {
198 int rc;
199
200 rc = mem_malloc_mbuf_pool(mempool, mbuf_pool, num_blocks,
201 block_size + sizeof (struct os_mbuf_pkthdr),
202 name, out_buf);
203 return rc;
204 }
205
206 int
mem_init_mbuf_pool(void * mem,struct os_mempool * mempool,struct os_mbuf_pool * mbuf_pool,int num_blocks,int block_size,char * name)207 mem_init_mbuf_pool(void *mem, struct os_mempool *mempool,
208 struct os_mbuf_pool *mbuf_pool, int num_blocks,
209 int block_size, char *name)
210 {
211 int rc;
212
213 rc = os_mempool_init(mempool, num_blocks, block_size, mem, name);
214 if (rc != 0) {
215 return rc;
216 }
217
218 rc = os_mbuf_pool_init(mbuf_pool, mempool, block_size, num_blocks);
219 if (rc != 0) {
220 return rc;
221 }
222
223 return 0;
224 }
225
226 /*
227 * Splits an appropriately-sized fragment from the front of an mbuf chain, as
228 * neeeded. If the length of the mbuf chain greater than specified maximum
229 * fragment size, a new mbuf is allocated, and data is moved from the source
230 * mbuf to the new mbuf. If the mbuf chain is small enough to fit in a single
231 * fragment, the source mbuf itself is returned unmodified, and the suplied
232 * pointer is set to NULL.
233 *
234 * This function is expected to be called in a loop until the entire mbuf chain
235 * has been consumed. For example:
236 *
237 * struct os_mbuf *frag;
238 * struct os_mbuf *rsp;
239 * // [...]
240 * while (rsp != NULL) {
241 * frag = mem_split_frag(&rsp, get_mtu(), frag_alloc, NULL);
242 * if (frag == NULL) {
243 * os_mbuf_free_chain(rsp);
244 * return SYS_ENOMEM;
245 * }
246 * send_packet(frag)
247 * }
248 *
249 * @param om The packet to fragment. Upon fragmentation,
250 * this mbuf is adjusted such that the
251 * fragment data is removed. If the packet
252 * constitutes a single fragment, this gets
253 * set to NULL on success.
254 * @param max_frag_sz The maximum payload size of a fragment.
255 * Typically this is the MTU of the
256 * connection.
257 * @param alloc_cb Points to a function that allocates an mbuf to
258 * hold a fragment. This function gets called
259 * before the source mbuf chain is modified,
260 * so it can safely inspect it.
261 * @param cb_arg Generic parameter that gets passed to the
262 * callback function.
263 *
264 * @return The next fragment to send on success;
265 * NULL on failure.
266 */
267 struct os_mbuf *
mem_split_frag(struct os_mbuf ** om,uint16_t max_frag_sz,mem_frag_alloc_fn * alloc_cb,void * cb_arg)268 mem_split_frag(struct os_mbuf **om, uint16_t max_frag_sz,
269 mem_frag_alloc_fn *alloc_cb, void *cb_arg)
270 {
271 struct os_mbuf *frag;
272 int rc;
273
274 if (OS_MBUF_PKTLEN(*om) <= max_frag_sz) {
275 /* Final fragment. */
276 frag = *om;
277 *om = NULL;
278 return frag;
279 }
280
281 /* Packet needs to be split. Allocate a new buffer for the fragment. */
282 frag = alloc_cb(max_frag_sz, cb_arg);
283 if (frag == NULL) {
284 goto err;
285 }
286
287 /* Move data from the front of the packet into the fragment mbuf. */
288 rc = os_mbuf_appendfrom(frag, *om, 0, max_frag_sz);
289 if (rc != 0) {
290 goto err;
291 }
292 os_mbuf_adj(*om, max_frag_sz);
293
294 /* Free unused portion of of source mbuf chain, if possible. */
295 *om = os_mbuf_trim_front(*om);
296
297 return frag;
298
299 err:
300 os_mbuf_free_chain(frag);
301 return NULL;
302 }
303