net: Add nbuf buffer API

User should use the net_nbuf API that is supporting a concept
of RX, TX and DATA buffers, instead of using directly the net_buf
low level API.

Change-Id: I3b8f5f13cd37d42d2322a58b35573e117d520c54
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2016-05-09 14:12:14 +03:00
commit 69b8c675a6
11 changed files with 886 additions and 2 deletions

View file

@ -46,3 +46,35 @@ config NET_RX_STACK_SIZE
help help
Set the RX fiber stack size in bytes. The RX fiber is waiting Set the RX fiber stack size in bytes. The RX fiber is waiting
data from network. There is one RX fiber in the system. data from network. There is one RX fiber in the system.
config NET_NBUF_RX_COUNT
int "How many network receives can be pending at the same time"
default 2
help
Each RX buffer will occupy smallish amount of memory.
See include/net/nbuf.h and the sizeof(struct nbuf)
config NET_NBUF_TX_COUNT
int "How many network sends can be pending at the same time"
default 2
help
Each TX buffer will occupy smallish amount of memory.
See include/net/nbuf.h and the sizeof(struct nbuf)
config NET_NBUF_DATA_COUNT
int "How many network data buffers are allocated"
default 16
help
Each data buffer will occupy CONFIG_NBUF_DATA_SIZE + smallish
header (sizeof(struct net_buf)) amount of data.
config NET_NBUF_DATA_SIZE
int "Size of each network data fragment"
default 128
help
This value tells what is the size of the data fragment that is
received from the network.
Example: For IEEE 802.15.4, the network packet is 127 bytes long,
which leaves in worst case 81 bytes for user data (MTU).
In order to be able to receive at least full IPv6 packet which
has a size of 1280 bytes, the one should allocate 16 fragments here.

View file

@ -1,2 +1,3 @@
ccflags-y += -I${srctree}/net/ip ccflags-y += -I${srctree}/net/ip
obj-y = net_core.o net_if.o obj-y = net_core.o \
nbuf.o

621
net/yaip/nbuf.c Normal file
View file

@ -0,0 +1,621 @@
/** @file
@brief Network buffers for IP stack
Network data is passed between components using nbuf.
*/
/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF)
#define SYS_LOG_DOMAIN "net/nbuf"
#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
#endif
#include <nanokernel.h>
#include <toolchain.h>
#include <string.h>
#include <stdint.h>
#include <net/net_ip.h>
#include <net/buf.h>
#include <net/nbuf.h>
#include <net/net_core.h>
#if !defined(NET_DEBUG_NBUFS)
#undef NET_DBG
#define NET_DBG(...)
#endif
#include "net_private.h"
/* Available (free) buffers queue */
#if !defined(NBUF_RX_COUNT)
#if CONFIG_NET_NBUF_RX_COUNT > 0
#define NBUF_RX_COUNT CONFIG_NET_NBUF_RX_COUNT
#else
#define NBUF_RX_COUNT 1
#endif
#endif
#if !defined(NBUF_TX_COUNT)
#if CONFIG_NET_NBUF_TX_COUNT > 0
#define NBUF_TX_COUNT CONFIG_NET_NBUF_TX_COUNT
#else
#define NBUF_TX_COUNT 1
#endif
#endif
#if !defined(NBUF_DATA_COUNT)
#if CONFIG_NET_NBUF_DATA_COUNT > 0
#define NBUF_DATA_COUNT CONFIG_NET_NBUF_DATA_COUNT
#else
#define NBUF_DATA_COUNT 13
#endif
#endif
#if !defined(NBUF_DATA_LEN)
#if CONFIG_NET_NBUF_DATA_SIZE > 0
#define NBUF_DATA_LEN CONFIG_NET_NBUF_DATA_SIZE
#else
#define NBUF_DATA_LEN 128
#endif
#endif
#if defined(CONFIG_NET_TCP)
#define APP_PROTO_LEN NET_TCPH_LEN
#else
#if defined(CONFIG_NET_UDP)
#define APP_PROTO_LEN NET_UDPH_LEN
#else
#define APP_PROTO_LEN 0
#endif /* UDP */
#endif /* TCP */
#if defined(CONFIG_NET_IPV6)
#define IP_PROTO_LEN NET_IPV6H_LEN
#else
#if defined(CONFIG_NET_IPV4)
#define IP_PROTO_LEN NET_IPV4H_LEN
#endif /* IPv4 */
#endif /* IPv6 */
#define EXTRA_PROTO_LEN NET_ICMPH_LEN
/* Make sure that IP + TCP/UDP header fit into one
* fragment. This makes possible to cast a protocol header
* struct into memory area.
*/
#if NBUF_DATA_LEN < (IP_PROTO_LEN + APP_PROTO_LEN)
#if defined(STRING2)
#undef STRING2
#endif
#if defined(STRING)
#undef STRING
#endif
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#pragma message "Data len " STRING(NBUF_DATA_LEN)
#pragma message "Minimum len " STRING(IP_PROTO_LEN + APP_PROTO_LEN)
#error "Too small net_buf fragment size"
#endif
#if defined(NET_DEBUG_NBUFS)
static int num_free_rx_bufs = NBUF_RX_COUNT;
static int num_free_tx_bufs = NBUF_TX_COUNT;
static int num_free_data_bufs = NBUF_DATA_COUNT;
static inline void dec_free_rx_bufs(struct net_buf *buf)
{
if (!buf) {
return;
}
num_free_rx_bufs--;
if (num_free_rx_bufs < 0) {
NET_DBG("*** ERROR *** Invalid RX buffer count.");
num_free_rx_bufs = 0;
}
}
static inline void inc_free_rx_bufs(struct net_buf *buf)
{
if (!buf) {
return;
}
if (num_free_rx_bufs > NBUF_RX_COUNT) {
num_free_rx_bufs = NBUF_RX_COUNT;
} else {
num_free_rx_bufs++;
}
}
static inline void dec_free_tx_bufs(struct net_buf *buf)
{
if (!buf) {
return;
}
num_free_tx_bufs--;
if (num_free_tx_bufs < 0) {
NET_DBG("*** ERROR *** Invalid TX buffer count.");
num_free_tx_bufs = 0;
}
}
static inline void inc_free_tx_bufs(struct net_buf *buf)
{
if (!buf) {
return;
}
if (num_free_tx_bufs > NBUF_TX_COUNT) {
num_free_tx_bufs = NBUF_TX_COUNT;
} else {
num_free_tx_bufs++;
}
}
static inline void dec_free_data_bufs(struct net_buf *buf)
{
if (!buf) {
return;
}
num_free_data_bufs--;
if (num_free_data_bufs < 0) {
NET_DBG("*** ERROR *** Invalid data buffer count.");
num_free_data_bufs = 0;
}
}
static inline void inc_free_data_bufs(struct net_buf *buf)
{
if (!buf) {
return;
}
if (num_free_data_bufs > NBUF_DATA_COUNT) {
num_free_data_bufs = NBUF_DATA_COUNT;
} else {
num_free_data_bufs++;
}
}
static inline int get_frees(enum net_nbuf_type type)
{
switch (type) {
case NET_NBUF_RX:
return num_free_rx_bufs;
case NET_NBUF_TX:
return num_free_tx_bufs;
case NET_NBUF_DATA:
return num_free_data_bufs;
}
return 0xffffffff;
}
#define inc_free_rx_bufs_func inc_free_rx_bufs
#define inc_free_tx_bufs_func inc_free_tx_bufs
#define inc_free_data_bufs_func inc_free_data_bufs
#else /* NET_DEBUG_NBUFS */
#define dec_free_rx_bufs(...)
#define inc_free_rx_bufs(...)
#define dec_free_tx_bufs(...)
#define inc_free_tx_bufs(...)
#define dec_free_data_bufs(...)
#define inc_free_data_bufs(...)
#define inc_free_rx_bufs_func(...)
#define inc_free_tx_bufs_func(...)
#define inc_free_data_bufs_func(...)
#endif /* NET_DEBUG_NBUFS */
static struct nano_fifo free_rx_bufs;
static struct nano_fifo free_tx_bufs;
static struct nano_fifo free_data_bufs;
static inline void free_rx_bufs_func(struct net_buf *buf)
{
inc_free_rx_bufs_func(buf);
nano_fifo_put(buf->free, buf);
}
static inline void free_tx_bufs_func(struct net_buf *buf)
{
inc_free_tx_bufs_func(buf);
nano_fifo_put(buf->free, buf);
}
static inline void free_data_bufs_func(struct net_buf *buf)
{
inc_free_data_bufs_func(buf);
nano_fifo_put(buf->free, buf);
}
/* The RX and TX pools do not store any data. Only bearer / protocol
* related data is stored here.
*/
static NET_BUF_POOL(rx_buffers, NBUF_RX_COUNT, 0, \
&free_rx_bufs, free_rx_bufs_func, \
sizeof(struct net_nbuf));
static NET_BUF_POOL(tx_buffers, NBUF_TX_COUNT, 0, \
&free_tx_bufs, free_tx_bufs_func, \
sizeof(struct net_nbuf));
/* The data fragment pool is for storing network data.
* This pool does not need any user data because the rx/tx pool already
* contains all the protocol/bearer specific information.
*/
static NET_BUF_POOL(data_buffers, NBUF_DATA_COUNT, \
NBUF_DATA_LEN, &free_data_bufs, \
free_data_bufs_func, 0);
static inline const char *type2str(enum net_nbuf_type type)
{
switch (type) {
case NET_NBUF_RX:
return "RX";
case NET_NBUF_TX:
return "TX";
case NET_NBUF_DATA:
return "DATA";
}
return NULL;
}
#ifdef NET_DEBUG_NBUFS
static struct net_buf *net_nbuf_get_reserve_debug(enum net_nbuf_type type,
uint16_t reserve_head,
const char *caller,
int line)
#else
static struct net_buf *net_nbuf_get_reserve(enum net_nbuf_type type,
uint16_t reserve_head)
#endif
{
struct net_buf *buf = NULL;
/*
* The reserve_head variable in the function will tell
* the size of the link layer headers if there are any.
*/
switch (type) {
case NET_NBUF_RX:
buf = net_buf_get(&free_rx_bufs, 0);
dec_free_rx_bufs(buf);
net_nbuf_type(buf) = type;
break;
case NET_NBUF_TX:
buf = net_buf_get(&free_tx_bufs, 0);
dec_free_tx_bufs(buf);
net_nbuf_type(buf) = type;
break;
case NET_NBUF_DATA:
buf = net_buf_get(&free_data_bufs, reserve_head);
dec_free_data_bufs(buf);
break;
default:
NET_ERR("Invalid type %d for net_buf", type);
return NULL;
}
if (!buf) {
#if defined(CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF)
#define PRINT_CYCLE (30 * sys_clock_ticks_per_sec)
static uint32_t next_print;
uint32_t curr = sys_tick_get_32();
if (!next_print || (next_print < curr &&
(!((curr - next_print) > PRINT_CYCLE)))) {
uint32_t new_print;
#ifdef NET_DEBUG_NBUFS
NET_ERR("Failed to get free %s buffer (%s():%d)",
type2str(type), caller, line);
#else
NET_ERR("Failed to get free %s buffer",
type2str(type));
#endif /* NET_DEBUG_NBUFS */
new_print = curr + PRINT_CYCLE;
if (new_print > curr) {
next_print = new_print;
} else {
/* Overflow */
next_print = PRINT_CYCLE -
(0xffffffff - curr);
}
}
#endif
return NULL;
}
NET_BUF_CHECK_IF_NOT_IN_USE(buf, buf->ref + 1);
#ifdef NET_DEBUG_NBUFS
NET_DBG("%s [%d] buf %p reserve %u ref %d (%s():%d)",
type2str(type), get_frees(type),
buf, reserve_head, buf->ref, caller, line);
#else
NET_DBG("%s buf %p reserve %u ref %d",
type2str(type), buf, reserve_head, buf->ref);
#endif
return buf;
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_get_reserve_rx_debug(uint16_t reserve_head,
const char *caller, int line)
#else
struct net_buf *net_nbuf_get_reserve_rx(uint16_t reserve_head)
#endif
{
#ifdef NET_DEBUG_NBUFS
return net_nbuf_get_reserve_debug(NET_NBUF_RX, reserve_head,
caller, line);
#else
return net_nbuf_get_reserve(NET_NBUF_RX, reserve_head);
#endif
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_get_reserve_tx_debug(uint16_t reserve_head,
const char *caller, int line)
#else
struct net_buf *net_nbuf_get_reserve_tx(uint16_t reserve_head)
#endif
{
#ifdef NET_DEBUG_NBUFS
return net_nbuf_get_reserve_debug(NET_NBUF_TX, reserve_head,
caller, line);
#else
return net_nbuf_get_reserve(NET_NBUF_TX, reserve_head);
#endif
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_get_reserve_data_debug(uint16_t reserve_head,
const char *caller, int line)
#else
struct net_buf *net_nbuf_get_reserve_data(uint16_t reserve_head)
#endif
{
#ifdef NET_DEBUG_NBUFS
return net_nbuf_get_reserve_debug(NET_NBUF_DATA, reserve_head,
caller, line);
#else
return net_nbuf_get_reserve(NET_NBUF_DATA, reserve_head);
#endif
}
#ifdef NET_DEBUG_NBUFS
static struct net_buf *net_nbuf_get_debug(enum net_nbuf_type type,
struct net_context *context,
const char *caller, int line)
#else
static struct net_buf *net_nbuf_get(enum net_nbuf_type type,
struct net_context *context)
#endif
{
struct net_buf *buf;
int16_t reserve = 0;
if (type == NET_NBUF_DATA) {
reserve = NBUF_DATA_LEN -
net_if_get_mtu(net_context_get_iface(context));
if (reserve < 0) {
NET_ERR("MTU %d bigger than fragment size %d",
net_if_get_mtu(net_context_get_iface(context)),
NBUF_DATA_LEN);
return NULL;
}
}
#ifdef NET_DEBUG_NBUFS
buf = net_nbuf_get_reserve_debug(type, (uint16_t)reserve, caller, line);
#else
buf = net_nbuf_get_reserve(type, (uint16_t)reserve);
#endif
if (!buf) {
return buf;
}
if (type != NET_NBUF_DATA) {
net_nbuf_context(buf) = context;
net_nbuf_ll_reserve(buf) = (uint16_t)reserve;
}
return buf;
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_get_rx_debug(struct net_context *context,
const char *caller, int line)
#else
struct net_buf *net_nbuf_get_rx(struct net_context *context)
#endif
{
#ifdef NET_DEBUG_NBUFS
return net_nbuf_get_debug(NET_NBUF_RX, context, caller, line);
#else
return net_nbuf_get(NET_NBUF_RX, context);
#endif
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_get_tx_debug(struct net_context *context,
const char *caller, int line)
#else
struct net_buf *net_nbuf_get_tx(struct net_context *context)
#endif
{
#ifdef NET_DEBUG_NBUFS
return net_nbuf_get_debug(NET_NBUF_TX, context, caller, line);
#else
return net_nbuf_get(NET_NBUF_TX, context);
#endif
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_get_data_debug(struct net_context *context,
const char *caller, int line)
#else
struct net_buf *net_nbuf_get_data(struct net_context *context)
#endif
{
#ifdef NET_DEBUG_NBUFS
return net_nbuf_get_debug(NET_NBUF_DATA, context, caller, line);
#else
return net_nbuf_get(NET_NBUF_DATA, context);
#endif
}
#ifdef NET_DEBUG_NBUFS
void net_nbuf_unref_debug(struct net_buf *buf, const char *caller, int line)
#else
void net_nbuf_unref(struct net_buf *buf)
#endif
{
struct net_buf *frag;
if (!buf) {
#ifdef NET_DEBUG_NBUFS
NET_DBG("*** ERROR *** buf %p (%s():%d)", buf, caller, line);
#else
NET_DBG("*** ERROR *** buf %p", buf);
#endif
return;
}
if (!buf->ref) {
#ifdef NET_DEBUG_NBUFS
NET_DBG("*** ERROR *** buf %p is freed already (%s():%d)",
buf, caller, line);
#else
NET_DBG("*** ERROR *** buf %p is freed already", buf);
#endif
return;
}
if (buf->user_data_size) {
#ifdef NET_DEBUG_NBUFS
NET_DBG("%s [%d] buf %p ref %d frags %p (%s():%d)",
type2str(net_nbuf_type(buf)),
get_frees(net_nbuf_type(buf)),
buf, buf->ref - 1, buf->frags, caller, line);
#else
NET_DBG("%s buf %p ref %d frags %p",
type2str(net_nbuf_type(buf)), buf, buf->ref - 1,
buf->frags);
#endif
} else {
#ifdef NET_DEBUG_NBUFS
NET_DBG("%s buf %p ref %d frags %p (%s():%d)",
type2str(NET_NBUF_DATA),
buf, buf->ref - 1, buf->frags, caller, line);
#else
NET_DBG("%s buf %p ref %d frags %p",
type2str(NET_NBUF_DATA), buf, buf->ref - 1,
buf->frags);
#endif
}
/* Remove the fragment list elements first, otherwise we
* have a memory leak.
*/
frag = buf->frags;
while (frag) {
struct net_buf *next = frag->frags;
net_buf_frag_del(buf, frag);
#ifdef NET_DEBUG_NBUFS
NET_DBG("%s buf %p ref %d frags %p (%s():%d)",
type2str(NET_NBUF_DATA),
frag, frag->ref - 1, frag->frags, caller, line);
#else
NET_DBG("%s buf %p ref %d frags %p",
type2str(NET_NBUF_DATA), frag, frag->ref - 1,
frag->frags);
#endif
net_buf_unref(frag);
frag = next;
}
net_buf_unref(buf);
}
#ifdef NET_DEBUG_NBUFS
struct net_buf *net_nbuf_ref_debug(struct net_buf *buf, const char *caller,
int line)
#else
struct net_buf *net_nbuf_ref(struct net_buf *buf)
#endif
{
if (!buf) {
#ifdef NET_DEBUG_NBUFS
NET_DBG("*** ERROR *** buf %p (%s():%d)", buf, caller, line);
#else
NET_DBG("*** ERROR *** buf %p", buf);
#endif
return NULL;
}
if (buf->user_data_size) {
#ifdef NET_DEBUG_NBUFS
NET_DBG("%s [%d] buf %p ref %d (%s():%d)",
type2str(net_nbuf_type(buf)),
get_frees(net_nbuf_type(buf)),
buf, buf->ref + 1, caller, line);
#else
NET_DBG("%s buf %p ref %d",
type2str(net_nbuf_type(buf)), buf, buf->ref + 1);
#endif
} else {
#ifdef NET_DEBUG_NBUFS
NET_DBG("%s buf %p ref %d (%s():%d)",
type2str(NET_NBUF_DATA),
buf, buf->ref + 1, caller, line);
#else
NET_DBG("%s buf %p ref %d",
type2str(NET_NBUF_DATA), buf, buf->ref + 1);
#endif
}
return net_buf_ref(buf);
}
void net_nbuf_init(void)
{
NET_DBG("Allocating %d RX (%d bytes), %d TX (%d bytes) "
"and %d data (%d bytes) buffers",
NBUF_RX_COUNT, sizeof(rx_buffers),
NBUF_TX_COUNT, sizeof(tx_buffers),
NBUF_DATA_COUNT, sizeof(data_buffers));
net_buf_pool_init(rx_buffers);
net_buf_pool_init(tx_buffers);
net_buf_pool_init(data_buffers);
}

View file

@ -33,7 +33,10 @@
#include <errno.h> #include <errno.h>
#include <net/net_if.h> #include <net/net_if.h>
#include <net/buf.h> #include <net/nbuf.h>
#include <net/net_core.h>
#include "net_private.h"
/* Stack for the rx fiber. /* Stack for the rx fiber.
*/ */
@ -85,6 +88,8 @@ int net_init(void)
initialized = 1; initialized = 1;
net_nbuf_init();
init_rx_queue(); init_rx_queue();
return network_initialization(); return network_initialization();

25
net/yaip/net_private.h Normal file
View file

@ -0,0 +1,25 @@
/** @file
@brief Network stack private header
This is not to be included by the application.
*/
/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
extern void net_nbuf_init(void);

6
tests/net/nbuf/Makefile Normal file
View file

@ -0,0 +1,6 @@
BOARD ?= qemu_x86
MDEF_FILE = prj.mdef
KERNEL_TYPE ?= nano
CONF_FILE = prj_$(ARCH).conf
include $(ZEPHYR_BASE)/Makefile.inc

5
tests/net/nbuf/prj.mdef Normal file
View file

@ -0,0 +1,5 @@
% Application : Buffer test
% TASK NAME PRIO ENTRY STACK GROUPS
% ===================================================
TASK MAIN 7 mainloop 2048 [EXE]

View file

@ -0,0 +1,12 @@
CONFIG_NETWORKING=y
CONFIG_NET_IPV6=y
CONFIG_NET_YAIP=y
CONFIG_NET_BUF=y
CONFIG_NET_BUF_DEBUG=y
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_NET_NBUF_RX_COUNT=2
CONFIG_NET_NBUF_TX_COUNT=2
CONFIG_NET_NBUF_DATA_COUNT=5
CONFIG_NET_LOG=y
CONFIG_SYS_LOG_SHOW_COLOR=y
CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF=y

View file

@ -0,0 +1 @@
obj-y = main.o

170
tests/net/nbuf/src/main.c Normal file
View file

@ -0,0 +1,170 @@
/* main.c - Application main entry point */
/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <misc/printk.h>
#include <net/nbuf.h>
#include <net/net_ip.h>
#define LL_RESERVE 28
struct ipv6_hdr {
uint8_t vtc;
uint8_t tcflow;
uint16_t flow;
uint8_t len[2];
uint8_t nexthdr;
uint8_t hop_limit;
struct in6_addr src;
struct in6_addr dst;
} __attribute__((__packed__));
struct udp_hdr {
uint16_t src_port;
uint16_t dst_port;
uint16_t len;
uint16_t chksum;
} __attribute__((__packed__));
static const char example_data[] =
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?"
"0123456789abcdefghijklmnopqrstuvxyz!#¤%&/()=?";
static int test_ipv6_multi_frags(void)
{
struct net_buf *buf, *frag;
struct ipv6_hdr *ipv6;
struct udp_hdr *udp;
int bytes, remaining = strlen(example_data), pos = 0;
/* Example of multi fragment scenario with IPv6 */
buf = net_nbuf_get_reserve_rx(0);
frag = net_nbuf_get_reserve_data(LL_RESERVE);
/* Place the IP + UDP header in the first fragment */
if (!net_buf_tailroom(frag)) {
ipv6 = (struct ipv6_hdr *)(frag->data);
udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6));
if (net_buf_tailroom(frag) < sizeof(ipv6)) {
printk("Not enough space for IPv6 header, "
"needed %d bytes, has %d bytes\n",
sizeof(ipv6), net_buf_tailroom(frag));
return -EINVAL;
}
net_buf_add(frag, sizeof(ipv6));
if (net_buf_tailroom(frag) < sizeof(udp)) {
printk("Not enough space for UDP header, "
"needed %d bytes, has %d bytes\n",
sizeof(udp), net_buf_tailroom(frag));
return -EINVAL;
}
net_nbuf_appdata(buf) = (void *)udp + sizeof(*udp);
net_nbuf_appdatalen(buf) = 0;
}
net_buf_frag_add(buf, frag);
/* Put some data to rest of the fragments */
frag = net_nbuf_get_reserve_data(LL_RESERVE);
if (net_buf_tailroom(frag) -
(CONFIG_NET_NBUF_DATA_SIZE - LL_RESERVE)) {
printk("Invalid number of bytes available in the buf, "
"should be 0 but was %d - %d\n",
net_buf_tailroom(frag),
CONFIG_NET_NBUF_DATA_SIZE - LL_RESERVE);
return -EINVAL;
}
if (((int)net_buf_tailroom(frag) - remaining) > 0) {
printk("We should have been out of space now, "
"tailroom %d user data len %d\n",
net_buf_tailroom(frag),
strlen(example_data));
return -EINVAL;
}
while (remaining > 0) {
int copy;
bytes = net_buf_tailroom(frag);
copy = remaining > bytes ? bytes : remaining;
memcpy(net_buf_add(frag, copy), &example_data[pos], copy);
printk("Remaining %d left %d copy %d\n", remaining, bytes,
copy);
pos += bytes;
remaining -= bytes;
if (net_buf_tailroom(frag) - (bytes - copy)) {
printk("There should have not been any tailroom left, "
"tailroom %d\n",
net_buf_tailroom(frag) - (bytes - copy));
return -EINVAL;
}
net_buf_frag_add(buf, frag);
if (remaining > 0) {
frag = net_nbuf_get_reserve_data(LL_RESERVE);
}
}
bytes = net_buf_frags_len(buf->frags);
if (bytes != strlen(example_data)) {
printk("Invalid number of bytes in message, %d vs %d\n",
strlen(example_data), bytes);
return -EINVAL;
}
/* Normally one should not unref the fragment list like this
* because it will leave the buf->frags pointing to already
* freed fragment.
*/
net_nbuf_unref(buf->frags);
if (!buf->frags) {
printk("Fragment list should not be empty.\n");
return -EINVAL;
}
buf->frags = NULL; /* to prevent double free */
net_nbuf_unref(buf);
return 0;
}
#ifdef CONFIG_MICROKERNEL
void mainloop(void)
#else
void main(void)
#endif
{
if (test_ipv6_multi_frags() < 0) {
return;
}
printk("nbuf tests passed\n");
}

View file

@ -0,0 +1,6 @@
[test]
tags = nbuf
build_only = true
arch_whitelist = x86
# Doesn't work for ia32_pci
filter = CONFIG_SOC="ia32"