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
|
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.
|
||||||
|
|
|
@ -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
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 <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
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