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