Skip to content

Commit 77e1a9d

Browse files
jori-nordiccarlescufi
authored andcommitted
Bluetooth: host: l2cap: add alloc_seg callback
This callback allows use-cases where the SDU is much larger than the l2cap MPS. The stack will then try to allocate using this callback if specified, and fall-back on using the buffer's pool (previous behavior). This way one can define two buffer pools, one with a very large buffer size, and one with a buffer size >= MPS, and the stack will allocate from that instead. Signed-off-by: Jonathan Rico <[email protected]>
1 parent 8e207fe commit 77e1a9d

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed

include/zephyr/bluetooth/l2cap.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,19 @@ struct bt_l2cap_chan_ops {
279279
*/
280280
void (*encrypt_change)(struct bt_l2cap_chan *chan, uint8_t hci_status);
281281

282+
/** @brief Channel alloc_seg callback
283+
*
284+
* If this callback is provided the channel will use it to allocate
285+
* buffers to store segments. This avoids wasting big SDU buffers with
286+
* potentially much smaller PDUs. If this callback is supplied, it must
287+
* return a valid buffer.
288+
*
289+
* @param chan The channel requesting a buffer.
290+
*
291+
* @return Allocated buffer.
292+
*/
293+
struct net_buf *(*alloc_seg)(struct bt_l2cap_chan *chan);
294+
282295
/** @brief Channel alloc_buf callback
283296
*
284297
* If this callback is provided the channel will use it to allocate

subsys/bluetooth/host/l2cap.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,13 +1779,20 @@ static void le_disconn_rsp(struct bt_l2cap *l2cap, uint8_t ident,
17791779
bt_l2cap_chan_del(&chan->chan);
17801780
}
17811781

1782-
static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf)
1782+
static inline struct net_buf *l2cap_alloc_seg(struct net_buf *buf, struct bt_l2cap_le_chan *ch)
17831783
{
17841784
struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id);
17851785
struct net_buf *seg;
17861786

1787-
/* Try to use original pool if possible */
1788-
seg = net_buf_alloc(pool, K_NO_WAIT);
1787+
/* Use the dedicated segment callback if registered */
1788+
if (ch->chan.ops->alloc_seg) {
1789+
seg = ch->chan.ops->alloc_seg(&ch->chan);
1790+
__ASSERT_NO_MSG(seg);
1791+
} else {
1792+
/* Try to use original pool if possible */
1793+
seg = net_buf_alloc(pool, K_NO_WAIT);
1794+
}
1795+
17891796
if (seg) {
17901797
net_buf_reserve(seg, BT_L2CAP_CHAN_SEND_RESERVE);
17911798
return seg;
@@ -1822,7 +1829,8 @@ static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch,
18221829
}
18231830

18241831
segment:
1825-
seg = l2cap_alloc_seg(buf);
1832+
seg = l2cap_alloc_seg(buf, ch);
1833+
18261834
if (!seg) {
18271835
return NULL;
18281836
}

tests/bluetooth/bsim_bt/bsim_test_l2cap_stress/prj.conf

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@ CONFIG_BT_BUF_ACL_TX_COUNT=4
2525
# L2AP MPS + L2CAP header (4)
2626
CONFIG_BT_BUF_ACL_RX_SIZE=81
2727

28-
# TODO: find out why we can't use 16 buffers. It should fit.
29-
30-
CONFIG_BT_L2CAP_TX_BUF_COUNT=30
31-
# CONFIG_BT_L2CAP_TX_BUF_COUNT=100
32-
33-
CONFIG_BT_BUF_ACL_TX_COUNT=4
28+
# Governs BT_CONN_TX_MAX, and so must be >= than the max number of
29+
# peers, since we attempt to send one SDU per peer. The test execution
30+
# is a bit slowed down by having this at the very minimum, but we want
31+
# to keep it that way as to stress the stack as much as possible.
32+
CONFIG_BT_L2CAP_TX_BUF_COUNT=6
3433

3534
CONFIG_BT_CTLR_RX_BUFFERS=10
3635
# The ring buffer now has space for three times as much data

tests/bluetooth/bsim_bt/bsim_test_l2cap_stress/src/main.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ CREATE_FLAG(flag_l2cap_connected);
2121
#define INIT_CREDITS 10
2222
#define SDU_NUM 20
2323
#define SDU_LEN 1230
24+
#define NUM_SEGMENTS 30
2425

2526
/* Only one SDU per link will be transmitted at a time */
26-
/* FIXME: decrease size */
2727
NET_BUF_POOL_DEFINE(sdu_tx_pool,
28-
100, BT_L2CAP_BUF_SIZE(SDU_LEN),
28+
CONFIG_BT_MAX_CONN, BT_L2CAP_BUF_SIZE(SDU_LEN),
29+
8, NULL);
30+
31+
NET_BUF_POOL_DEFINE(segment_pool,
32+
NUM_SEGMENTS, BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
2933
8, NULL);
3034

3135
/* Only one SDU per link will be received at a time */
@@ -66,6 +70,15 @@ int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len)
6670
return ret;
6771
}
6872

73+
struct net_buf *alloc_seg_cb(struct bt_l2cap_chan *chan)
74+
{
75+
struct net_buf *buf = net_buf_alloc(&segment_pool, K_NO_WAIT);
76+
77+
ASSERT(buf, "Ran out of segment buffers");
78+
79+
return buf;
80+
}
81+
6982
struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
7083
{
7184
return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT);
@@ -137,6 +150,7 @@ static struct bt_l2cap_chan_ops ops = {
137150
.connected = l2cap_chan_connected_cb,
138151
.disconnected = l2cap_chan_disconnected_cb,
139152
.alloc_buf = alloc_buf_cb,
153+
.alloc_seg = alloc_seg_cb,
140154
.recv = recv_cb,
141155
.sent = sent_cb,
142156
};

0 commit comments

Comments
 (0)