Mbed OS Reference
Loading...
Searching...
No Matches
NetStackMemoryManager.h
1/*
2 * Copyright (c) 2018 ARM Limited
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#ifndef NET_STACK_MEMORY_MANAGER_H
19#define NET_STACK_MEMORY_MANAGER_H
20
21/**
22 * Network Stack interface memory manager
23 *
24 * \par
25 * This interface provides abstraction for memory modules used in different IP stacks (often to accommodate zero
26 * copy). NetStack interface is required to accept output packets and provide received data using this stack-
27 * independent API. This header should be implemented for each IP stack, so that we keep EMAC module independent.
28 *
29 * \par
30 * NetStack memory interface uses memory buffer chains to store data. Data passed in either direction
31 * may either be contiguous (a single-buffer chain), or may consist of multiple buffers.
32 * Chaining of the buffers is made using singly-linked list. The NetStack data-passing APIs do not specify
33 * alignment or structure of the chain in either direction.
34 *
35 * \par
36 * Memory buffers can be allocated either from heap or from memory pools. Heap buffers are always contiguous.
37 * Memory pool buffers may be either contiguous or chained depending on allocation size. By LwIP convention,
38 * the pool should only be used for Rx packets -- the EMAC may opt to keep buffers pre-allocated from the pool
39 * for receiving packets into. This is done because LwIP will do special stuff when the pool runs out of space,
40 * e.g. flushing TCP out-of-sequence segment buffers to free up memory.
41 *
42 * On NetStack interface buffer chain ownership is transferred. EMAC must free buffer chain that it is given for
43 * link output and the stack must free the buffer chain that it is given for link input.
44 *
45 */
46
47#include "nsapi.h"
48#include "Callback.h"
49
50typedef void net_stack_mem_buf_t; // Memory buffer
51
53protected:
54 /// Callback which shall be called (if set) by the implementation after one or more buffer spaces
55 /// become free in the pool. This is used by zero-copy Ethernet MACs as a hint that
56 /// now is a good time to allocate fresh buffers off the pool into Ethernet descriptors.
57 /// It *is* legal to call this function if you aren't totally sure new memory is available --
58 /// the mac will try to allocate more buffers, and if it can't, oh well.
59 /// However, it is not legal for memory to become available without a call to this function.
60 /// Such a situation might lead to a lockup of the MAC due to not having memory allocated for Rx.
61 // TODO this eventually needs to get converted to a list once we support boards with more than 1 EMAC
63
64public:
65
66 /**
67 * Allocates memory buffer from the heap
68 *
69 * Memory buffer allocated from heap is always contiguous and can be arbitrary size.
70 *
71 * @param size Size of the memory to allocate in bytes
72 * @param align Memory alignment requirement in bytes
73 * @return Allocated memory buffer, or NULL in case of error
74 */
75 virtual net_stack_mem_buf_t *alloc_heap(uint32_t size, uint32_t align) = 0;
76
77 /**
78 * Allocates memory buffer chain from a pool
79 *
80 * Memory allocated from pool is contiguous if size is equal or less than
81 * (aligned) allocation unit, otherwise may be chained. Will typically come from
82 * fixed-size packet pool memory.
83 *
84 * @param size Total size of the memory to allocate in bytes
85 * @param align Memory alignment requirement for each buffer in bytes
86 * @return Allocated memory buffer chain, or NULL in case of error
87 */
88 virtual net_stack_mem_buf_t *alloc_pool(uint32_t size, uint32_t align) = 0;
89
90 /**
91 * Get memory buffer pool allocation unit
92 *
93 * Returns the maximum size of contiguous memory that can be allocated from a pool.
94 *
95 * @param align Memory alignment requirement in bytes
96 * @return Contiguous memory size
97 */
98 virtual uint32_t get_pool_alloc_unit(uint32_t align) const = 0;
99
100 /**
101 * Get memory buffer pool size.
102 *
103 * @return The maximum size of contiguous memory that can be allocated from a pool.
104 */
105 virtual uint32_t get_pool_size() const = 0;
106
107 /**
108 * Free memory buffer chain
109 *
110 * Frees all buffers from the chained list.
111 *
112 * @param buf Memory buffer chain to be freed.
113 */
114 virtual void free(net_stack_mem_buf_t *buf) = 0;
115
116 /**
117 * Return total length of a memory buffer chain
118 *
119 * Returns a total length of this buffer and any following buffers in the chain.
120 *
121 * @param buf Memory buffer chain
122 * @return Total length in bytes
123 */
124 virtual uint32_t get_total_len(const net_stack_mem_buf_t *buf) const = 0;
125
126 /**
127 * Copy a memory buffer chain
128 *
129 * Copies data from one buffer chain to another. Copy operation does not adjust the lengths
130 * of the copied-to memory buffer chain, so chain total lengths must be the same.
131 *
132 * @param to_buf Memory buffer chain to copy to
133 * @param from_buf Memory buffer chain to copy from
134 */
135 virtual void copy(net_stack_mem_buf_t *to_buf, const net_stack_mem_buf_t *from_buf) = 0;
136
137 /**
138 * Copy to a memory buffer chain
139 *
140 * Copies data to a buffer chain. Copy operation does not adjust the lengths
141 * of the copied-to memory buffer chain, so chain total length must match the
142 * copied length.
143 *
144 * @param to_buf Memory buffer chain to copy to
145 * @param ptr Pointer to data
146 * @param len Data length
147 */
148 virtual void copy_to_buf(net_stack_mem_buf_t *to_buf, const void *ptr, uint32_t len);
149
150 /**
151 * Copy from a memory buffer chain
152 *
153 * Copies data from a memory buffer chain.
154 *
155 * @param len Data length
156 * @param ptr Pointer to data
157 * @param from_buf Memory buffer chain to copy from
158 * @return Length of the data that was copied
159 */
160 virtual uint32_t copy_from_buf(void *ptr, uint32_t len, const net_stack_mem_buf_t *from_buf) const;
161
162 /**
163 * Concatenate two memory buffer chains
164 *
165 * Concatenates buffer chain to end of the other buffer chain. Concatenated-to buffer total length
166 * is adjusted accordingly. cat_buf must point to the start of a the chain. After concatenation
167 * to_buf's chain now owns those buffers, and they will be freed when the to_buf chain is freed.
168 *
169 * @param to_buf Memory buffer chain to concatenate to
170 * @param cat_buf Memory buffer chain to concatenate
171 */
172 virtual void cat(net_stack_mem_buf_t *to_buf, net_stack_mem_buf_t *cat_buf) = 0;
173
174 /**
175 * Returns the next buffer
176 *
177 * Returns the next buffer from the memory buffer chain.
178 *
179 * @param buf Memory buffer
180 * @return The next memory buffer, or NULL if last
181 */
182 virtual net_stack_mem_buf_t *get_next(const net_stack_mem_buf_t *buf) const = 0;
183
184 /**
185 * @brief Count the number of buffers in a buffer chain
186 *
187 * @param buf Memory buffer
188 * @return The number of buffers in the chain
189 */
190 size_t count_buffers(const net_stack_mem_buf_t *buf)
191 {
192 size_t count = 0;
193 while (buf != nullptr) {
194 count += 1;
195 buf = get_next(buf);
196 }
197 return count;
198 }
199
200 /**
201 * Return pointer to the payload of the buffer
202 *
203 * @param buf Memory buffer
204 * @return Pointer to the payload
205 */
206 virtual void *get_ptr(const net_stack_mem_buf_t *buf) const = 0;
207
208 /**
209 * Return payload size of this individual buffer (NOT including any chained buffers)
210 *
211 * @param buf Memory buffer
212 * @return Size in bytes
213 */
214 virtual uint32_t get_len(const net_stack_mem_buf_t *buf) const = 0;
215
216 /**
217 * Sets the payload size of the buffer
218 *
219 * The allocated payload size will not change. It is not permitted
220 * to change the length of a buffer that is not the first (or only) in a chain.
221 *
222 * *Note as of Dec 2024: Different implementations (Nanostack vs LwIP) disagree about
223 * how to implement this operation. Specifically, if called on the head of a buffer
224 * chain, the LwIP implementation allows changing the length of the chain as a whole.
225 * However, the Nanostack implementation does not and only can change the length of the head buffer.
226 * For fear of breaking existing code, I do not want to change this behavior.
227 * So, if constructing a buffer chain, it is safest to set the buffer lengths first before
228 * building the chain.
229 *
230 * @param buf Memory buffer
231 * @param len Payload size, must be less or equal to the allocated size
232 */
233 virtual void set_len(net_stack_mem_buf_t *buf, uint32_t len) = 0;
234
235 enum class Lifetime {
236 POOL_ALLOCATED, ///< Allocated from the memory manager's pool
237 HEAP_ALLOCATED, ///< Allocated from the memory manager's heap
238 CONSTANT, ///< Buffer points to constant data (e.g. in ROM) that will live forever
239 VOLATILE ///< Buffer points to data from the application that will not live past the current network stack call.
240 };
241
242 /**
243 * Gets the lifetime of the buffer
244 *
245 * @param buf Memory buffer
246 */
247 virtual Lifetime get_lifetime(net_stack_mem_buf_t const *buf) const = 0;
248
249 /**
250 * @brief Set callback which will be called when pool space becomes available
251 *
252 * \warning The callback could be called from any thread, and should make no assumptions about
253 * being in the same thread as anything else.
254 *
255 * @param cb Callback to call
256 */
261
262protected:
263 ~NetStackMemoryManager() = default;
264};
265
266#endif /* NET_STACK_MEMORY_MANAGER_H */
virtual uint32_t get_pool_alloc_unit(uint32_t align) const =0
Get memory buffer pool allocation unit.
virtual void copy_to_buf(net_stack_mem_buf_t *to_buf, const void *ptr, uint32_t len)
Copy to a memory buffer chain.
virtual net_stack_mem_buf_t * alloc_pool(uint32_t size, uint32_t align)=0
Allocates memory buffer chain from a pool.
virtual void cat(net_stack_mem_buf_t *to_buf, net_stack_mem_buf_t *cat_buf)=0
Concatenate two memory buffer chains.
virtual uint32_t copy_from_buf(void *ptr, uint32_t len, const net_stack_mem_buf_t *from_buf) const
Copy from a memory buffer chain.
virtual net_stack_mem_buf_t * alloc_heap(uint32_t size, uint32_t align)=0
Allocates memory buffer from the heap.
virtual void * get_ptr(const net_stack_mem_buf_t *buf) const =0
Return pointer to the payload of the buffer.
virtual uint32_t get_len(const net_stack_mem_buf_t *buf) const =0
Return payload size of this individual buffer (NOT including any chained buffers)
virtual uint32_t get_pool_size() const =0
Get memory buffer pool size.
virtual void free(net_stack_mem_buf_t *buf)=0
Free memory buffer chain.
@ HEAP_ALLOCATED
Allocated from the memory manager's heap.
@ VOLATILE
Buffer points to data from the application that will not live past the current network stack call.
@ CONSTANT
Buffer points to constant data (e.g. in ROM) that will live forever.
@ POOL_ALLOCATED
Allocated from the memory manager's pool.
virtual net_stack_mem_buf_t * get_next(const net_stack_mem_buf_t *buf) const =0
Returns the next buffer.
virtual Lifetime get_lifetime(net_stack_mem_buf_t const *buf) const =0
Gets the lifetime of the buffer.
virtual void copy(net_stack_mem_buf_t *to_buf, const net_stack_mem_buf_t *from_buf)=0
Copy a memory buffer chain.
mbed::Callback< void()> onPoolSpaceAvailCallback
Callback which shall be called (if set) by the implementation after one or more buffer spaces become ...
size_t count_buffers(const net_stack_mem_buf_t *buf)
Count the number of buffers in a buffer chain.
void set_on_pool_space_avail_cb(mbed::Callback< void()> cb)
Set callback which will be called when pool space becomes available.
virtual void set_len(net_stack_mem_buf_t *buf, uint32_t len)=0
Sets the payload size of the buffer.
virtual uint32_t get_total_len(const net_stack_mem_buf_t *buf) const =0
Return total length of a memory buffer chain.
Callback class based on template specialization.
Definition Callback.h:53