net: nbuf: Add function to split a data fragment
Add net_nbuf_split() function that can be used to split an existing net_buf fragment into two arbitrary length pieces, and return the two new fragments to the caller. The data from the original fragment is copied into these two new fragments. Existing fragment is not modified. Change-Id: I463e675232c6e19c2a42929f480893a6d1265873 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
909069d2c7
commit
1b2c16a498
3 changed files with 182 additions and 0 deletions
|
@ -1112,6 +1112,35 @@ static inline bool net_nbuf_insert_be32(struct net_buf *buf,
|
||||||
(uint8_t *)&value, K_FOREVER);
|
(uint8_t *)&value, K_FOREVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Split a fragment to two parts at arbitrary offset.
|
||||||
|
*
|
||||||
|
* @details This will generate two new fragments (fragA and fragB) from
|
||||||
|
* one (orig_frag). The original fragment is not modified but two new
|
||||||
|
* fragments are allocated and returned to the caller. The original fragment
|
||||||
|
* must be part of the chain pointed by the buf parameter. If the len parameter
|
||||||
|
* is larger than the amount of data in the orig fragment, then the fragA will
|
||||||
|
* contain all the data and fragB will be empty.
|
||||||
|
*
|
||||||
|
* @param buf Head of the network buffer fragment list.
|
||||||
|
* @param orig_frag Original network buffer fragment which is to be split.
|
||||||
|
* @param len Amount of data in the first returned fragment.
|
||||||
|
* @param fragA A fragment is returned. This will contain len bytes that
|
||||||
|
* are copied from start of orig_frag.
|
||||||
|
* @param fragB Another fragment is returned. This will contain remaining
|
||||||
|
* bytes (orig_frag->len - len) from the orig_frag or NULL if all the data
|
||||||
|
* was copied into fragA.
|
||||||
|
* @param timeout Affects the action taken should the net buf pool be empty.
|
||||||
|
* If K_NO_WAIT, then return immediately. If K_FOREVER, then wait as long as
|
||||||
|
* necessary. Otherwise, wait up to the specified number of milliseconds before
|
||||||
|
* timing out.
|
||||||
|
*
|
||||||
|
* @return 0 on success, <0 otherwise.
|
||||||
|
*/
|
||||||
|
int net_nbuf_split(struct net_buf *buf, struct net_buf *orig_frag,
|
||||||
|
uint16_t len, struct net_buf **fragA,
|
||||||
|
struct net_buf **fragB, int32_t timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get information about pre-defined RX, TX and DATA pools.
|
* @brief Get information about pre-defined RX, TX and DATA pools.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1516,6 +1516,59 @@ bool net_nbuf_insert(struct net_buf *buf, struct net_buf *frag,
|
||||||
return insert_data(buf, frag, temp, offset, len, data, timeout);
|
return insert_data(buf, frag, temp, offset, len, data, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int net_nbuf_split(struct net_buf *buf, struct net_buf *orig_frag,
|
||||||
|
uint16_t len, struct net_buf **fragA,
|
||||||
|
struct net_buf **fragB, int32_t timeout)
|
||||||
|
{
|
||||||
|
if (!buf || !orig_frag || is_from_data_pool(buf)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NET_ASSERT(fragA && fragB);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
*fragA = NULL;
|
||||||
|
*fragB = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > net_buf_tailroom(*fragA)) {
|
||||||
|
NET_DBG("Length %u is larger than fragment size %zd",
|
||||||
|
len, net_buf_tailroom(*fragA));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > orig_frag->len) {
|
||||||
|
*fragA = net_nbuf_get_frag(buf, timeout);
|
||||||
|
if (!*fragA) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(net_buf_add(*fragA, orig_frag->len), orig_frag->data,
|
||||||
|
orig_frag->len);
|
||||||
|
|
||||||
|
*fragB = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fragA = net_nbuf_get_frag(buf, timeout);
|
||||||
|
if (!*fragA) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fragB = net_nbuf_get_frag(buf, timeout);
|
||||||
|
if (!*fragB) {
|
||||||
|
net_nbuf_unref(*fragA);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(net_buf_add(*fragA, len), orig_frag->data, len);
|
||||||
|
memcpy(net_buf_add(*fragB, orig_frag->len - len),
|
||||||
|
orig_frag->data + len, orig_frag->len - len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void net_nbuf_get_info(struct net_buf_pool **rx,
|
void net_nbuf_get_info(struct net_buf_pool **rx,
|
||||||
struct net_buf_pool **tx,
|
struct net_buf_pool **tx,
|
||||||
struct net_buf_pool **rx_data,
|
struct net_buf_pool **rx_data,
|
||||||
|
|
|
@ -1206,6 +1206,102 @@ static int test_fragment_compact(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char frag_data[CONFIG_NET_NBUF_DATA_SIZE] = { 42 };
|
||||||
|
|
||||||
|
static int test_fragment_split(void)
|
||||||
|
{
|
||||||
|
#define TEST_FRAG_COUNT (FRAG_COUNT - 2)
|
||||||
|
#define FRAGA (FRAG_COUNT - 2)
|
||||||
|
#define FRAGB (FRAG_COUNT - 1)
|
||||||
|
struct net_buf *buf, *frags[FRAG_COUNT], *frag, *fragA, *fragB;
|
||||||
|
int i, total, splitA, splitB;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
buf = net_nbuf_get_reserve_rx(0, K_FOREVER);
|
||||||
|
frag = NULL;
|
||||||
|
|
||||||
|
for (i = 0, total = 0; i < TEST_FRAG_COUNT; i++) {
|
||||||
|
frags[i] = net_nbuf_get_reserve_rx_data(12, K_FOREVER);
|
||||||
|
|
||||||
|
if (frag) {
|
||||||
|
net_buf_frag_add(frag, frags[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
frag = frags[i];
|
||||||
|
|
||||||
|
/* Copy some test data in front of the fragment */
|
||||||
|
memcpy(net_buf_add(frags[i], sizeof(frag_data)),
|
||||||
|
frag_data, sizeof(frag_data));
|
||||||
|
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total != TEST_FRAG_COUNT) {
|
||||||
|
printk("There should be %d fragments but was %d\n",
|
||||||
|
TEST_FRAG_COUNT, total);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_frag_add(buf, frags[0]);
|
||||||
|
|
||||||
|
fragA = frags[FRAGA];
|
||||||
|
fragB = frags[FRAGB];
|
||||||
|
|
||||||
|
splitA = fragA->size * 2 / 3;
|
||||||
|
splitB = fragB->size - splitA;
|
||||||
|
|
||||||
|
/* Test some error cases first */
|
||||||
|
ret = net_nbuf_split(NULL, NULL, 1024, &fragA, &fragB, K_NO_WAIT);
|
||||||
|
if (!ret) {
|
||||||
|
printk("Invalid buf pointers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = net_nbuf_split(buf, buf->frags, 1024, &fragA, &fragB, K_NO_WAIT);
|
||||||
|
if (!ret) {
|
||||||
|
printk("Too long frag length %d\n", 1024);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = net_nbuf_split(buf, buf->frags, CONFIG_NET_NBUF_DATA_SIZE + 1,
|
||||||
|
&fragA, &fragB, K_NO_WAIT);
|
||||||
|
if (!ret) {
|
||||||
|
printk("Too long frag size %d vs %d\n",
|
||||||
|
CONFIG_NET_NBUF_DATA_SIZE,
|
||||||
|
CONFIG_NET_NBUF_DATA_SIZE + 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = net_nbuf_split(buf, buf->frags, splitA,
|
||||||
|
&fragA, &fragB, K_NO_WAIT);
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Cannot split into %d and %d parts\n", splitA, splitB);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragA->len != splitA) {
|
||||||
|
printk("Frag A len %d not %d\n", fragA->len, splitA);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragB->len != splitB) {
|
||||||
|
printk("Frag B len %d not %d\n", fragB->len, splitB);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf->frags->data, fragA->data, splitA)) {
|
||||||
|
printk("Frag A data mismatch\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf->frags->data + splitA, fragB->data, splitB)) {
|
||||||
|
printk("Frag B data mismatch\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
if (test_ipv6_multi_frags() < 0) {
|
if (test_ipv6_multi_frags() < 0) {
|
||||||
|
@ -1232,6 +1328,10 @@ void main(void)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_fragment_split() < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
printk("nbuf tests passed\n");
|
printk("nbuf tests passed\n");
|
||||||
|
|
||||||
TC_END_REPORT(TC_PASS);
|
TC_END_REPORT(TC_PASS);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue