mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-08-12 21:17:57 +00:00
mesh: Slab based segmentation handling
Allocates segmented message buffers as slabs in a common pool for RX and TX. This reduces memory requirements for both TX and RX, as TX messages can be stored without the network and advertising buffer overhead, and RX can use only the slabs it needs, instead of allocating a full size segmented message. This approach also removes the need for decrypting the segments for each retransmission, reducing overall processing load. Slab based segmentation for tx also introduces queuing of segmented messages, which allows the application layer to send multiple messages to the same destination without violating Bluetooth Mesh specification v1.0.1, section 3.6.4.1. This mechanism is provided through a flag that blocks segmented messages to a destination which a message is already being sent to until the previous message finishes. This changes the SDU size configuration to a symmetrical RX_SEG_MAX/TX_SEG_MAX pair of configurations, plus a new segment pool side configuration. It also removes the binding between the TX_SEG_MAX config and the advertising buffers, reducing the minimum advertising buffer count from 6 to 3. this is port of 901b5b2b2b0a33f5426f621277e7238e8b83740b and 7443c1bd3ded598b56db3c931614072098af84e1
This commit is contained in:
committed by
Łukasz Rymanowski
parent
d5e0507274
commit
6b6c67eebf
@@ -242,6 +242,10 @@ static inline void net_buf_simple_init(struct os_mbuf *buf,
|
||||
buf->om_len = 0;
|
||||
}
|
||||
|
||||
#define net_buf_simple_init_with_data(buf, data, size) \
|
||||
buf = NET_BUF_SIMPLE(size); \
|
||||
os_mbuf_copyinto(buf, 0, data, size);
|
||||
|
||||
static inline void net_buf_simple_reset(struct os_mbuf *om)
|
||||
{
|
||||
om->om_len = 0;
|
||||
@@ -413,6 +417,7 @@ static inline unsigned int find_msb_set(u32_t op)
|
||||
|
||||
#define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS)
|
||||
#define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)
|
||||
#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS )
|
||||
#define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE)
|
||||
#define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN)
|
||||
#define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT)
|
||||
@@ -427,7 +432,10 @@ static inline unsigned int find_msb_set(u32_t op)
|
||||
#define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT)
|
||||
#define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER)
|
||||
#define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME)
|
||||
#define CONFIG_BT_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX)
|
||||
#define CONFIG_BT_MESH_TX_SEG_MAX MYNEWT_VAL(BLE_MESH_TX_SEG_MAX)
|
||||
#define CONFIG_BT_MESH_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX)
|
||||
#define CONFIG_BT_MESH_RX_SEG_MSG_COUNT MYNEWT_VAL(BLE_MESH_RX_SEG_MSG_COUNT)
|
||||
#define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT)
|
||||
#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)
|
||||
#define CONFIG_BT_MESH_CDB BLE_MESH_CDB
|
||||
@@ -515,6 +523,56 @@ settings_load(void)
|
||||
|
||||
#define BUILD_ASSERT(cond) _Static_assert(cond, "")
|
||||
|
||||
|
||||
/* Memory slabs/blocks */
|
||||
|
||||
/** Memory slab structure */
|
||||
struct k_mem_slab {
|
||||
/**
|
||||
* _wait_q_t is not required now, as we don't implement zephyr timeouts -
|
||||
* if slab couldn't be allocated, we simply return error
|
||||
*/
|
||||
uint32_t num_blocks; /** number of memory blocks available for allocation */
|
||||
size_t block_size; /** size of single block */
|
||||
/**
|
||||
* buffer for blocks - must be alligned to N-byte, where N is a power of 2.
|
||||
* Minimal size of buffer is num_blocks * block_size
|
||||
*/
|
||||
char *buffer;
|
||||
char *free_list; /** list of free memory blocks */
|
||||
uint32_t num_used; /** count of used memory blocks */
|
||||
};
|
||||
|
||||
struct k_mem_block_id {
|
||||
uint32_t pool : 8;
|
||||
uint32_t level : 4;
|
||||
uint32_t block : 20;
|
||||
};
|
||||
|
||||
struct k_mem_block {
|
||||
void *data;
|
||||
struct k_mem_block_id id;
|
||||
};
|
||||
|
||||
extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem);
|
||||
extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem);
|
||||
static inline uint32_t k_mem_slab_num_free_get(struct k_mem_slab *slab)
|
||||
{
|
||||
return slab->num_blocks - slab->num_used;
|
||||
}
|
||||
|
||||
/** slab_align must be power of 2 */
|
||||
#define K_MEM_SLAB_DEFINE(name, slab_block_size, slab_num_blocks, slab_align) \
|
||||
char _k_mem_slab_buf_##name[slab_num_blocks * slab_block_size]; \
|
||||
struct k_mem_slab name = { \
|
||||
slab_num_blocks, \
|
||||
slab_block_size, \
|
||||
_k_mem_slab_buf_##name, \
|
||||
NULL, \
|
||||
0 \
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -259,7 +259,7 @@ int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
|
||||
cfm.lpn_counter = msg->lpn_counter;
|
||||
|
||||
bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR_CFM, &cfm,
|
||||
sizeof(cfm), NULL, NULL, NULL);
|
||||
sizeof(cfm), NULL, NULL);
|
||||
|
||||
friend_clear(frnd);
|
||||
|
||||
@@ -784,7 +784,7 @@ static void send_friend_clear(struct bt_mesh_friend *frnd)
|
||||
BT_DBG("");
|
||||
|
||||
bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
|
||||
sizeof(req), NULL, &clear_sent_cb, frnd);
|
||||
sizeof(req), &clear_sent_cb, frnd);
|
||||
}
|
||||
|
||||
static void clear_timeout(struct ble_npl_event *work)
|
||||
|
||||
@@ -870,6 +870,31 @@ void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
|
||||
}
|
||||
}
|
||||
|
||||
/** Memory slab methods */
|
||||
extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem)
|
||||
{
|
||||
**(char ***)mem = slab->free_list;
|
||||
slab->free_list = *(char **)mem;
|
||||
slab->num_used--;
|
||||
}
|
||||
|
||||
extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (slab->free_list != NULL) {
|
||||
/* take a free block */
|
||||
*mem = slab->free_list;
|
||||
slab->free_list = *(char **)(slab->free_list);
|
||||
slab->num_used++;
|
||||
result = 0;
|
||||
} else {
|
||||
*mem = NULL;
|
||||
result = -ENOMEM;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
|
||||
|
||||
int settings_bytes_from_str(char *val_str, void *vp, int *len)
|
||||
|
||||
@@ -190,7 +190,7 @@ static int send_friend_clear(void)
|
||||
BT_DBG("");
|
||||
|
||||
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
|
||||
sizeof(req), NULL, &clear_sent_cb, NULL);
|
||||
sizeof(req), &clear_sent_cb, NULL);
|
||||
}
|
||||
|
||||
static void clear_friendship(bool force, bool disable)
|
||||
@@ -308,7 +308,7 @@ static int send_friend_req(struct bt_mesh_lpn *lpn)
|
||||
BT_DBG("");
|
||||
|
||||
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req,
|
||||
sizeof(req), NULL, &friend_req_sent_cb, NULL);
|
||||
sizeof(req), &friend_req_sent_cb, NULL);
|
||||
}
|
||||
|
||||
static void req_sent(u16_t duration, int err, void *user_data)
|
||||
@@ -378,7 +378,7 @@ static int send_friend_poll(void)
|
||||
}
|
||||
|
||||
err = bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_POLL, &fsn, 1,
|
||||
NULL, &req_sent_cb, NULL);
|
||||
&req_sent_cb, NULL);
|
||||
if (err == 0) {
|
||||
lpn->pending_poll = 0;
|
||||
lpn->sent_req = TRANS_CTL_OP_FRIEND_POLL;
|
||||
@@ -689,8 +689,8 @@ static bool sub_update(u8_t op)
|
||||
|
||||
req.xact = lpn->xact_next++;
|
||||
|
||||
if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, NULL,
|
||||
&req_sent_cb, NULL) < 0) {
|
||||
if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2,
|
||||
&req_sent_cb, NULL) < 0) {
|
||||
group_zero(lpn->pending);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -724,62 +724,6 @@ u32_t bt_mesh_next_seq(void)
|
||||
return seq;
|
||||
}
|
||||
|
||||
int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
|
||||
bool new_key, const struct bt_mesh_send_cb *cb,
|
||||
void *cb_data)
|
||||
{
|
||||
const u8_t *enc, *priv;
|
||||
u32_t seq;
|
||||
u16_t dst;
|
||||
int err;
|
||||
|
||||
BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key,
|
||||
buf->om_len);
|
||||
|
||||
enc = sub->keys[new_key].enc;
|
||||
priv = sub->keys[new_key].privacy;
|
||||
|
||||
err = bt_mesh_net_obfuscate(buf->om_data, BT_MESH_NET_IVI_TX, priv);
|
||||
if (err) {
|
||||
BT_ERR("deobfuscate failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_mesh_net_decrypt(enc, buf, BT_MESH_NET_IVI_TX, false);
|
||||
if (err) {
|
||||
BT_ERR("decrypt failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
seq = bt_mesh_next_seq();
|
||||
sys_put_be24(seq, &buf->om_data[2]);
|
||||
|
||||
/* Get destination, in case it's a proxy client */
|
||||
dst = DST(buf->om_data);
|
||||
|
||||
err = bt_mesh_net_encrypt(enc, buf, BT_MESH_NET_IVI_TX, false);
|
||||
if (err) {
|
||||
BT_ERR("encrypt failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_mesh_net_obfuscate(buf->om_data, BT_MESH_NET_IVI_TX, priv);
|
||||
if (err) {
|
||||
BT_ERR("obfuscate failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
|
||||
bt_mesh_proxy_relay(buf, dst) &&
|
||||
BT_MESH_ADDR_IS_UNICAST(dst)) {
|
||||
send_cb_finalize(cb, cb_data);
|
||||
} else {
|
||||
bt_mesh_adv_send(buf, cb, cb_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bt_mesh_net_local(struct ble_npl_event *work)
|
||||
{
|
||||
struct os_mbuf *buf;
|
||||
|
||||
@@ -344,10 +344,6 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
|
||||
int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
|
||||
const struct bt_mesh_send_cb *cb, void *cb_data);
|
||||
|
||||
int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
|
||||
bool new_key, const struct bt_mesh_send_cb *cb,
|
||||
void *cb_data);
|
||||
|
||||
int bt_mesh_net_decode(struct os_mbuf *data, enum bt_mesh_net_if net_if,
|
||||
struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
|
||||
|
||||
|
||||
+483
-328
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,12 @@
|
||||
|
||||
#define TRANS_SEQ_AUTH_NVAL 0xffffffffffffffff
|
||||
|
||||
#define BT_MESH_TX_SDU_MAX (CONFIG_BT_MESH_TX_SEG_MAX * 12)
|
||||
#define BT_MESH_SDU_UNSEG_MAX 11
|
||||
#define BT_MESH_CTL_SEG_SDU_MAX 8
|
||||
#define BT_MESH_APP_SEG_SDU_MAX 12
|
||||
#define BT_MESH_TX_SDU_MAX (CONFIG_BT_MESH_TX_SEG_MAX * BT_MESH_APP_SEG_SDU_MAX)
|
||||
#define BT_MESH_RX_SDU_MAX (CONFIG_BT_MESH_RX_SEG_MAX * BT_MESH_APP_SEG_SDU_MAX)
|
||||
#define BT_MESH_RX_CTL_MAX (CONFIG_BT_MESH_RX_SEG_MAX * BT_MESH_CTL_SEG_SDU_MAX)
|
||||
|
||||
#define TRANS_SEQ_ZERO_MASK ((u16_t)BIT_MASK(13))
|
||||
#define TRANS_CTL_OP_MASK ((u8_t)BIT_MASK(7))
|
||||
@@ -87,8 +92,7 @@ void bt_mesh_rx_reset(void);
|
||||
void bt_mesh_tx_reset(void);
|
||||
|
||||
int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
|
||||
size_t data_len, u64_t *seq_auth,
|
||||
const struct bt_mesh_send_cb *cb, void *cb_data);
|
||||
size_t data_len, const struct bt_mesh_send_cb *cb, void *cb_data);
|
||||
|
||||
int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *msg,
|
||||
const struct bt_mesh_send_cb *cb, void *cb_data);
|
||||
|
||||
+36
-17
@@ -186,7 +186,7 @@ syscfg.defs:
|
||||
description: >
|
||||
Maximum number of simultaneous outgoing multi-segment and/or
|
||||
reliable messages.
|
||||
value: 4
|
||||
value: 1
|
||||
|
||||
BLE_MESH_RX_SEG_MSG_COUNT:
|
||||
description: >
|
||||
@@ -194,15 +194,39 @@ syscfg.defs:
|
||||
reliable messages.
|
||||
value: 2
|
||||
|
||||
BLE_MESH_RX_SDU_MAX:
|
||||
BLE_MESH_SEG_BUFS:
|
||||
description: >
|
||||
Maximum incoming Upper Transport Access PDU length. This
|
||||
determines also how many segments incoming segmented messages
|
||||
can have. Each segment can contain 12 bytes, so this value should
|
||||
be set to a multiple of 12 to avoid wasted memory. The minimum
|
||||
requirement is 2 segments (24 bytes) whereas the maximum supported
|
||||
by the Mesh specification is 32 segments (384 bytes).
|
||||
value: 72
|
||||
The incoming and outgoing segmented messages allocate their
|
||||
segments from the same pool. Each segment is a 12 byte block,
|
||||
and may only be used by one message at the time.
|
||||
|
||||
Outgoing messages will allocate their segments at the start of the
|
||||
transmission, and release them one by one as soon as they have been
|
||||
acknowledged by the receiver. Incoming messages allocate all their
|
||||
segments at the start of the transaction, and won't release them until
|
||||
the message is fully received.
|
||||
value:
|
||||
64
|
||||
|
||||
BLE_MESH_RX_SEG_MAX:
|
||||
description: >
|
||||
Maximum number of segments supported for incoming messages.
|
||||
This value should typically be fine-tuned based on what
|
||||
models the local node supports, i.e. what's the largest
|
||||
message payload that the node needs to be able to receive.
|
||||
This value affects memory and call stack consumption, which
|
||||
is why the default is lower than the maximum that the
|
||||
specification would allow (32 segments).
|
||||
|
||||
The maximum incoming SDU size is 12 times this number (out of
|
||||
which 4 or 8 bytes is used for the Transport Layer MIC). For
|
||||
example, 5 segments means the maximum SDU size is 60 bytes,
|
||||
which leaves 56 bytes for application layer data using a
|
||||
4-byte MIC and 52 bytes using an 8-byte MIC.
|
||||
value:
|
||||
3
|
||||
|
||||
|
||||
|
||||
BLE_MESH_TX_SEG_MAX:
|
||||
description: >
|
||||
@@ -210,20 +234,15 @@ syscfg.defs:
|
||||
This value should typically be fine-tuned based on what
|
||||
models the local node supports, i.e. what's the largest
|
||||
message payload that the node needs to be able to send.
|
||||
This value affects memory and call stack consumption, which
|
||||
is why the default is lower than the maximum that the
|
||||
specification would allow (32 segments).
|
||||
This value affects memory consumption, which is why the
|
||||
default is lower than the maximum that the specification
|
||||
would allow (32 segments).
|
||||
|
||||
The maximum outgoing SDU size is 12 times this number (out of
|
||||
which 4 or 8 bytes is used for the Transport Layer MIC). For
|
||||
example, 5 segments means the maximum SDU size is 60 bytes,
|
||||
which leaves 56 bytes for application layer data using a
|
||||
4-byte MIC and 52 bytes using an 8-byte MIC.
|
||||
|
||||
Be sure to specify a sufficient number of advertising buffers
|
||||
when setting this option to a higher value. There must be at
|
||||
least three more advertising buffers (BT_MESH_ADV_BUF_COUNT)
|
||||
as there are outgoing segments.
|
||||
value: 3
|
||||
|
||||
BLE_MESH_SEG_RETRANSMIT_ATTEMPTS:
|
||||
|
||||
@@ -1070,8 +1070,12 @@
|
||||
#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_MESH_RX_SDU_MAX
|
||||
#define MYNEWT_VAL_BLE_MESH_RX_SDU_MAX (72)
|
||||
#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS
|
||||
#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (72)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MAX
|
||||
#define MYNEWT_VAL_BLE_MESH_RX_SEG_MAX (3)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT
|
||||
@@ -1143,6 +1147,10 @@
|
||||
#define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT
|
||||
#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (3)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT
|
||||
#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4)
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user