Skip to content

Commit 3d306c1

Browse files
carlescufijhedberg
authored andcommitted
net: buf: Simplify fragment handling
This patch reworks how fragments are handled in the net_buf infrastructure. In particular, it removes the union around the node and frags members in the main net_buf structure. This is done so that both can be used at the same time, at a cost of 4 bytes per net_buf instance. This implies that the layout of net_buf instances changes whenever being inserted into a queue (fifo or lifo) or a linked list (slist). Until now, this is what happened when enqueueing a net_buf with frags in a queue or linked list: 1.1 Before enqueueing: +--------+ +--------+ +--------+ |#1 node|\ |#2 node|\ |#3 node|\ | | \ | | \ | | \ | frags |------| frags |------| frags |------NULL +--------+ +--------+ +--------+ net_buf #1 has 2 fragments, net_bufs #2 and #3. Both the node and frags pointers (they are the same, since they are unioned) point to the next fragment. 1.2 After enqueueing: +--------+ +--------+ +--------+ +--------+ +--------+ |q/slist |------|#1 node|------|#2 node|------|#3 node|------|q/slist | |node | | *flag | / | *flag | / | | / |node | | | | frags |/ | frags |/ | frags |/ | | +--------+ +--------+ +--------+ +--------+ +--------+ When enqueing a net_buf (in this case #1) that contains fragments, the current net_buf implementation actually enqueues all the fragments (in this case #2 and #3) as actual queue/slist items, since node and frags are one and the same in memory. This makes the enqueuing operation expensive and it makes it impossible to atomically dequeue. The `*flag` notation here means that the `flags` member has been set to `NET_BUF_FRAGS` in order to be able to reconstruct the frags pointers when dequeuing. After this patch, the layout changes considerably: 2.1 Before enqueueing: +--------+ +--------+ +--------+ |#1 node|--NULL |#2 node|--NULL |#3 node|--NULL | | | | | | | frags |-------| frags |-------| frags |------NULL +--------+ +--------+ +--------+ This is very similar to 1.1, except that now node and frags are different pointers, so node is just set to NULL. 2.2 After enqueueing: +--------+ +--------+ +--------+ |q/slist |-------|#1 node|-------|q/slist | |node | | | |node | | | | frags | | | +--------+ +--------+ +--------+ | +--------+ +--------+ | |#2 node|--NULL |#3 node|--NULL | | | | | +------------| frags |-------| frags |------NULL +--------+ +--------+ When enqueuing net_buf #1, now we only enqueue that very item, instead of enqueing the frags as well, since now node and frags are separate pointers. This simplifies the operation and makes it atomic. Resolves zephyrproject-rtos#52718. Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
1 parent 34b88e7 commit 3d306c1

File tree

2 files changed

+9
-57
lines changed

2 files changed

+9
-57
lines changed

include/zephyr/net/buf.h

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -884,15 +884,6 @@ static inline void net_buf_simple_restore(struct net_buf_simple *buf,
884884
buf->len = state->len;
885885
}
886886

887-
/**
888-
* Flag indicating that the buffer has associated fragments. Only used
889-
* internally by the buffer handling code while the buffer is inside a
890-
* FIFO, meaning this never needs to be explicitly set or unset by the
891-
* net_buf API user. As long as the buffer is outside of a FIFO, i.e.
892-
* in practice always for the user for this API, the buf->frags pointer
893-
* should be used instead.
894-
*/
895-
#define NET_BUF_FRAGS BIT(0)
896887
/**
897888
* Flag indicating that the buffer's associated data pointer, points to
898889
* externally allocated memory. Therefore once ref goes down to zero, the
@@ -902,7 +893,7 @@ static inline void net_buf_simple_restore(struct net_buf_simple *buf,
902893
* Reference count mechanism however will behave the same way, and ref
903894
* count going to 0 will free the net_buf but no the data pointer in it.
904895
*/
905-
#define NET_BUF_EXTERNAL_DATA BIT(1)
896+
#define NET_BUF_EXTERNAL_DATA BIT(0)
906897

907898
/**
908899
* @brief Network buffer representation.
@@ -912,13 +903,11 @@ static inline void net_buf_simple_restore(struct net_buf_simple *buf,
912903
* using the net_buf_alloc() API.
913904
*/
914905
struct net_buf {
915-
union {
916-
/** Allow placing the buffer into sys_slist_t */
917-
sys_snode_t node;
906+
/** Allow placing the buffer into sys_slist_t */
907+
sys_snode_t node;
918908

919-
/** Fragments associated with this buffer. */
920-
struct net_buf *frags;
921-
};
909+
/** Fragments associated with this buffer. */
910+
struct net_buf *frags;
922911

923912
/** Reference count. */
924913
uint8_t ref;

subsys/net/buf.c

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ struct net_buf *net_buf_get_debug(struct k_fifo *fifo, k_timeout_t timeout,
412412
struct net_buf *net_buf_get(struct k_fifo *fifo, k_timeout_t timeout)
413413
#endif
414414
{
415-
struct net_buf *buf, *frag;
415+
struct net_buf *buf;
416416

417417
NET_BUF_DBG("%s():%d: fifo %p", func, line, fifo);
418418

@@ -423,18 +423,6 @@ struct net_buf *net_buf_get(struct k_fifo *fifo, k_timeout_t timeout)
423423

424424
NET_BUF_DBG("%s():%d: buf %p fifo %p", func, line, buf, fifo);
425425

426-
/* Get any fragments belonging to this buffer */
427-
for (frag = buf; (frag->flags & NET_BUF_FRAGS); frag = frag->frags) {
428-
frag->frags = k_fifo_get(fifo, K_NO_WAIT);
429-
__ASSERT_NO_MSG(frag->frags);
430-
431-
/* The fragments flag is only for FIFO-internal usage */
432-
frag->flags &= ~NET_BUF_FRAGS;
433-
}
434-
435-
/* Mark the end of the fragment list */
436-
frag->frags = NULL;
437-
438426
return buf;
439427
}
440428

@@ -460,24 +448,19 @@ static struct k_spinlock net_buf_slist_lock;
460448

461449
void net_buf_slist_put(sys_slist_t *list, struct net_buf *buf)
462450
{
463-
struct net_buf *tail;
464451
k_spinlock_key_t key;
465452

466453
__ASSERT_NO_MSG(list);
467454
__ASSERT_NO_MSG(buf);
468455

469-
for (tail = buf; tail->frags; tail = tail->frags) {
470-
tail->flags |= NET_BUF_FRAGS;
471-
}
472-
473456
key = k_spin_lock(&net_buf_slist_lock);
474-
sys_slist_append_list(list, &buf->node, &tail->node);
457+
sys_slist_append(list, &buf->node);
475458
k_spin_unlock(&net_buf_slist_lock, key);
476459
}
477460

478461
struct net_buf *net_buf_slist_get(sys_slist_t *list)
479462
{
480-
struct net_buf *buf, *frag;
463+
struct net_buf *buf;
481464
k_spinlock_key_t key;
482465

483466
__ASSERT_NO_MSG(list);
@@ -486,37 +469,17 @@ struct net_buf *net_buf_slist_get(sys_slist_t *list)
486469

487470
buf = (void *)sys_slist_get(list);
488471

489-
if (buf) {
490-
/* Get any fragments belonging to this buffer */
491-
for (frag = buf; (frag->flags & NET_BUF_FRAGS); frag = frag->frags) {
492-
frag->frags = (void *)sys_slist_get(list);
493-
__ASSERT_NO_MSG(frag->frags);
494-
495-
/* The fragments flag is only for list-internal usage */
496-
frag->flags &= ~NET_BUF_FRAGS;
497-
}
498-
499-
/* Mark the end of the fragment list */
500-
frag->frags = NULL;
501-
}
502-
503472
k_spin_unlock(&net_buf_slist_lock, key);
504473

505474
return buf;
506475
}
507476

508477
void net_buf_put(struct k_fifo *fifo, struct net_buf *buf)
509478
{
510-
struct net_buf *tail;
511-
512479
__ASSERT_NO_MSG(fifo);
513480
__ASSERT_NO_MSG(buf);
514481

515-
for (tail = buf; tail->frags; tail = tail->frags) {
516-
tail->flags |= NET_BUF_FRAGS;
517-
}
518-
519-
k_fifo_put_list(fifo, buf, tail);
482+
k_fifo_put(fifo, buf);
520483
}
521484

522485
#if defined(CONFIG_NET_BUF_LOG)

0 commit comments

Comments
 (0)