2 * Copyright (c) 2017, ETH Zurich.
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
15 #include <barrelfish/barrelfish.h>
17 #include <devif/queue_interface.h>
19 #include <lwip/pbuf.h>
21 #include "networking_internal.h"
22 #define NETDEBUG_SUBSYSTEM "net_buf"
25 ///< the default flags to map the buffers
26 #define NETWORKING_DEFAULT_BUFFER_FLAGS VREGION_FLAGS_READ_WRITE
29 #define NETWORKING_BUFFER_ALIGN 2048
34 * @brief initializes the networking buffer pools
36 * @param dev_q the device queue to create the buffer pool for
37 * @param numbuf number of initial buffers
38 * @param size size of the networking buffer
39 * @param retbp buffer pool to initialize
41 * @return SYS_ERR_OK on success, errval on failure
43 errval_t net_buf_pool_alloc(struct devq *dev_q, size_t numbuf, size_t size,
44 struct net_buf_pool **retbp)
50 NETDEBUG("initializing buffer pool with %zu x %zu buffers...\n", numbuf, size);
52 struct net_buf_pool *netbp = calloc(1, sizeof(*netbp));
54 return LIB_ERR_MALLOC_FAIL;
59 err = net_buf_grow(netbp, numbuf, size);
60 if (err_is_fail(err)) {
70 errval_t net_buf_pool_free(struct net_buf_pool *retbp)
76 * @brief adds a previously allocated frame to the buffer pool
78 * @param bp buffer pool to add the frame to
79 * @param frame frame capability
80 * @param buffersize size of a buffer
82 * @return SYS_ERR_OK on success, errval on failure
84 errval_t net_buf_add(struct net_buf_pool *bp, struct capref frame, size_t buffersize)
89 struct net_buf_region *reg = calloc(1, sizeof(struct net_buf_region));
91 return LIB_ERR_MALLOC_FAIL;
94 reg->buffer_size = ROUND_UP(buffersize, NETWORKING_BUFFER_ALIGN);
95 reg->buffer_shift = 0;
96 while(!((reg->buffer_size >> reg->buffer_shift) & 0x1)) {
100 reg->framecap = frame;
103 err = invoke_frame_identify(reg->framecap, ®->frame);
104 if (err_is_fail(err)) {
108 NETDEBUG("bp=%p, framesize=%zu kB, elementsize=%zu\n", bp,
109 reg->frame.bytes >> 10, buffersize);
112 size_t numbuf = reg->frame.bytes / reg->buffer_size;
113 assert(numbuf * reg->buffer_size <= reg->frame.bytes);
115 reg->netbufs = calloc(numbuf, sizeof(struct net_buf_p));
116 if (reg->netbufs == NULL) {
117 err = LIB_ERR_MALLOC_FAIL;
121 err = vspace_map_one_frame_attr(®->vbase, reg->frame.bytes, reg->framecap,
122 NETWORKING_DEFAULT_BUFFER_FLAGS, NULL, NULL);
123 if (err_is_fail(err)) {
127 NETDEBUG("netbufs mapped at %p\n", reg->vbase);
130 debug_printf("netbuf: registering region with devq...\n");
131 err = devq_register(bp->dev_q, reg->framecap, ®->regionid);
132 if (err_is_fail(err)) {
135 NETDEBUG("registered region with devq. pbase=%" PRIxGENPADDR ", regionid=%" PRIx32 "\n",
136 reg->frame.base, reg->regionid);
140 for (size_t i = 0; i < numbuf; i++) {
141 struct net_buf_p *nb = ®->netbufs[i];
144 nb->vbase = reg->vbase + offset;
146 nb->pbuf.custom_free_function = net_buf_free;
151 nb->magic = 0xdeadbeefcafebabe;
153 /* enqueue to freelist */
154 nb->pbuf.pbuf.next = bp->pbufs;
155 bp->pbufs = &nb->pbuf.pbuf;
158 offset += reg->buffer_size;
161 reg->next = bp->regions;
166 NETDEBUG("new region added to pool. free count: %zu / %zu\n",
167 bp->buffer_free, bp->buffer_count);
180 * @brief grows the number of available buffers
182 * @param bp buffer pool to grow
183 * @param numbuf number of buffers to create
184 * @param size size of a buffer
186 * @return SYS_ERR_OK on success, errval on failure
188 errval_t net_buf_grow(struct net_buf_pool *bp, size_t numbuf,
193 NETDEBUG("bp=%p, numbuf=%zu, size=%zu\n", bp, numbuf, size);
195 size = ROUND_UP(size, NETWORKING_BUFFER_ALIGN);
197 size_t alloc_size = ROUND_UP(numbuf * size, BASE_PAGE_SIZE);
199 NETDEBUG("allocate frame of %zu kB\n", alloc_size >> 10);
202 err = frame_alloc(&frame, alloc_size, &alloc_size);
203 if (err_is_fail(err)) {
207 err = net_buf_add(bp, frame, size);
208 if (err_is_fail(err)) {
216 struct pbuf *net_buf_alloc(struct net_buf_pool *bp)
219 struct net_buf_p *nb = (struct net_buf_p *)bp->pbufs;
225 assert(nb->magic == 0xdeadbeefcafebabe);
226 assert(nb->allocated == 0);
227 assert(nb->enqueued == 0);
228 assert(nb->flags == 0);
231 bp->pbufs = bp->pbufs->next;
234 p = pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, &nb->pbuf,
235 nb->vbase, nb->region->buffer_size);
238 assert(p->next == NULL);
240 NETDEBUG("bp=%p, allocated pbuf=%p, free count %zu / %zu\n", bp, p,
241 bp->buffer_free, bp->buffer_count);
242 // printf("alloc: %p\n", p);
247 NETDEBUG("bp=%p has no free buffers. Free %zu / %zu\n", bp, bp->buffer_free,
253 void net_buf_free(struct pbuf *p)
255 NETDEBUG("pbuf=%p\n", p);
258 debug_printf("!!!!!! p->NEXT was not NULL (%p)\n", p->next);
261 // printf("free: %p\n", p);
263 // TODO sanity checks ?
264 struct net_buf_p *nb = (struct net_buf_p *)p;
267 assert(nb->magic == 0xdeadbeefcafebabe);
269 assert(nb->allocated == 1);
270 assert(nb->enqueued == 0);
271 assert(nb->flags == 0);
276 struct net_buf_pool *bp = nb->region->pool;
282 struct pbuf *net_buf_get_by_region(struct net_buf_pool *bp,
283 uint32_t regionid, size_t offset)
285 NETDEBUG("bp=%p, rid=%u, offset=%zu\n", bp, regionid, offset);
287 struct net_buf_region *reg = bp->regions;
289 if (reg->regionid == regionid) {
291 if (reg->frame.bytes < offset) {
295 assert((offset & (reg->buffer_size - 1)) == 0);
296 assert(offset / reg->buffer_size < reg->pool->buffer_count);
297 struct net_buf_p *nb = reg->netbufs + (offset / reg->buffer_size);
299 assert((offset / reg->buffer_size) == (offset >> reg->buffer_shift));
301 assert(nb->offset == offset);
303 return (struct pbuf *)nb;