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_init(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)) {
71 * @brief adds a previously allocated frame to the buffer pool
73 * @param bp buffer pool to add the frame to
74 * @param frame frame capability
75 * @param buffersize size of a buffer
77 * @return SYS_ERR_OK on success, errval on failure
79 errval_t net_buf_add(struct net_buf_pool *bp, struct capref frame, size_t buffersize)
84 struct net_buf_region *reg = calloc(1, sizeof(struct net_buf_region));
86 return LIB_ERR_MALLOC_FAIL;
89 reg->buffer_size = ROUND_UP(buffersize, NETWORKING_BUFFER_ALIGN);
90 reg->buffer_shift = 0;
91 while(!((reg->buffer_size >> reg->buffer_shift) & 0x1)) {
95 reg->framecap = frame;
98 err = invoke_frame_identify(reg->framecap, ®->frame);
99 if (err_is_fail(err)) {
103 NETDEBUG("bp=%p, framesize=%zu kB, elementsize=%zu\n", bp,
104 reg->frame.bytes >> 10, buffersize);
107 size_t numbuf = reg->frame.bytes / reg->buffer_size;
108 assert(numbuf * reg->buffer_size <= reg->frame.bytes);
110 reg->netbufs = calloc(numbuf, sizeof(struct net_buf_p));
111 if (reg->netbufs == NULL) {
112 err = LIB_ERR_MALLOC_FAIL;
116 err = vspace_map_one_frame_attr(®->vbase, reg->frame.bytes, reg->framecap,
117 NETWORKING_DEFAULT_BUFFER_FLAGS, NULL, NULL);
118 if (err_is_fail(err)) {
122 NETDEBUG("netbufs mapped at %p\n", reg->vbase);
125 debug_printf("netbuf: registering region with devq...\n");
126 err = devq_register(bp->dev_q, reg->framecap, ®->regionid);
127 if (err_is_fail(err)) {
130 NETDEBUG("registered region with devq. pbase=%" PRIxGENPADDR ", regionid=%" PRIx32 "\n",
131 reg->frame.base, reg->regionid);
135 for (size_t i = 0; i < numbuf; i++) {
136 struct net_buf_p *nb = ®->netbufs[i];
139 nb->vbase = reg->vbase + offset;
141 nb->pbuf.custom_free_function = net_buf_free;
146 nb->magic = 0xdeadbeefcafebabe;
148 /* enqueue to freelist */
149 nb->pbuf.pbuf.next = bp->pbufs;
150 bp->pbufs = &nb->pbuf.pbuf;
153 offset += reg->buffer_size;
156 reg->next = bp->regions;
161 NETDEBUG("new region added to pool. free count: %zu / %zu\n",
162 bp->buffer_free, bp->buffer_count);
175 * @brief grows the number of available buffers
177 * @param bp buffer pool to grow
178 * @param numbuf number of buffers to create
179 * @param size size of a buffer
181 * @return SYS_ERR_OK on success, errval on failure
183 errval_t net_buf_grow(struct net_buf_pool *bp, size_t numbuf,
188 NETDEBUG("bp=%p, numbuf=%zu, size=%zu\n", bp, numbuf, size);
190 size = ROUND_UP(size, NETWORKING_BUFFER_ALIGN);
192 size_t alloc_size = ROUND_UP(numbuf * size, BASE_PAGE_SIZE);
194 NETDEBUG("allocate frame of %zu kB\n", alloc_size >> 10);
197 err = frame_alloc(&frame, alloc_size, &alloc_size);
198 if (err_is_fail(err)) {
202 err = net_buf_add(bp, frame, size);
203 if (err_is_fail(err)) {
211 struct pbuf *net_buf_alloc(struct net_buf_pool *bp)
214 struct net_buf_p *nb = (struct net_buf_p *)bp->pbufs;
220 assert(nb->magic == 0xdeadbeefcafebabe);
221 assert(nb->allocated == 0);
222 assert(nb->enqueued == 0);
223 assert(nb->flags == 0);
226 bp->pbufs = bp->pbufs->next;
229 p = pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, &nb->pbuf,
230 nb->vbase, nb->region->buffer_size);
233 assert(p->next == NULL);
235 NETDEBUG("bp=%p, allocated pbuf=%p, free count %zu / %zu\n", bp, p,
236 bp->buffer_free, bp->buffer_count);
237 // printf("alloc: %p\n", p);
242 NETDEBUG("bp=%p has no free buffers. Free %zu / %zu\n", bp, bp->buffer_free,
248 void net_buf_free(struct pbuf *p)
250 NETDEBUG("pbuf=%p\n", p);
253 debug_printf("!!!!!! p->NEXT was not NULL\n");
256 // printf("free: %p\n", p);
258 // TODO sanity checks ?
259 struct net_buf_p *nb = (struct net_buf_p *)p;
262 assert(nb->magic == 0xdeadbeefcafebabe);
264 assert(nb->allocated == 1);
265 assert(nb->enqueued == 0);
266 assert(nb->flags == 0);
271 struct net_buf_pool *bp = nb->region->pool;
277 struct pbuf *net_buf_get_by_region(struct net_buf_pool *bp,
278 uint32_t regionid, size_t offset)
280 NETDEBUG("bp=%p, rid=%u, offset=%zu\n", bp, regionid, offset);
282 struct net_buf_region *reg = bp->regions;
284 if (reg->regionid == regionid) {
286 if (reg->frame.bytes < offset) {
290 assert((offset & (reg->buffer_size - 1)) == 0);
291 assert(offset / reg->buffer_size < reg->pool->buffer_count);
292 struct net_buf_p *nb = reg->netbufs + (offset / reg->buffer_size);
294 assert((offset / reg->buffer_size) == (offset >> reg->buffer_shift));
296 assert(nb->offset == offset);
298 return (struct pbuf *)nb;