• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }