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:
parent
81298abfb4
commit
69b8c675a6
11 changed files with 886 additions and 2 deletions
|
@ -46,3 +46,35 @@ config NET_RX_STACK_SIZE
|
|||
help
|
||||
Set the RX fiber stack size in bytes. The RX fiber is waiting
|
||||
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.
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
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
621
net/yaip/nbuf.c
Normal 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);
|
||||
}
|
|
@ -33,7 +33,10 @@
|
|||
#include <errno.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.
|
||||
*/
|
||||
|
@ -85,6 +88,8 @@ int net_init(void)
|
|||
|
||||
initialized = 1;
|
||||
|
||||
net_nbuf_init();
|
||||
|
||||
init_rx_queue();
|
||||
|
||||
return network_initialization();
|
||||
|
|
25
net/yaip/net_private.h
Normal file
25
net/yaip/net_private.h
Normal 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
6
tests/net/nbuf/Makefile
Normal 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
5
tests/net/nbuf/prj.mdef
Normal file
|
@ -0,0 +1,5 @@
|
|||
% Application : Buffer test
|
||||
|
||||
% TASK NAME PRIO ENTRY STACK GROUPS
|
||||
% ===================================================
|
||||
TASK MAIN 7 mainloop 2048 [EXE]
|
12
tests/net/nbuf/prj_x86.conf
Normal file
12
tests/net/nbuf/prj_x86.conf
Normal 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
|
1
tests/net/nbuf/src/Makefile
Normal file
1
tests/net/nbuf/src/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-y = main.o
|
170
tests/net/nbuf/src/main.c
Normal file
170
tests/net/nbuf/src/main.c
Normal 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");
|
||||
}
|
6
tests/net/nbuf/testcase.ini
Normal file
6
tests/net/nbuf/testcase.ini
Normal file
|
@ -0,0 +1,6 @@
|
|||
[test]
|
||||
tags = nbuf
|
||||
build_only = true
|
||||
arch_whitelist = x86
|
||||
# Doesn't work for ia32_pci
|
||||
filter = CONFIG_SOC="ia32"
|
Loading…
Add table
Add a link
Reference in a new issue