Merge pull request #11263 from miri64/gnrc_netif/new/pktq

gnrc_netif: add packet to queue when device is busy
This commit is contained in:
benpicco 2020-09-07 13:59:58 +02:00 committed by GitHub
commit a336fdc918
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 637 additions and 25 deletions

View File

@ -673,6 +673,10 @@ ifneq (,$(filter gnrc_netif_%,$(USEMODULE)))
USEMODULE += gnrc_netif USEMODULE += gnrc_netif
endif endif
ifneq (,$(filter gnrc_netif_pktq,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter netstats_%, $(USEMODULE))) ifneq (,$(filter netstats_%, $(USEMODULE)))
USEMODULE += netstats USEMODULE += netstats
endif endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 Freie Universität Berlin * Copyright (C) 2017-20 Freie Universität Berlin
* *
* This file is subject to the terms and conditions of the GNU Lesser * This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level * General Public License v2.1. See the file LICENSE in the top level
@ -59,6 +59,9 @@
#if IS_USED(MODULE_GNRC_NETIF_MAC) #if IS_USED(MODULE_GNRC_NETIF_MAC)
#include "net/gnrc/netif/mac.h" #include "net/gnrc/netif/mac.h"
#endif #endif
#if IS_USED(MODULE_GNRC_NETIF_PKTQ)
#include "net/gnrc/netif/pktq/type.h"
#endif
#include "net/ndp.h" #include "net/ndp.h"
#include "net/netdev.h" #include "net/netdev.h"
#include "net/netopt.h" #include "net/netopt.h"
@ -171,6 +174,14 @@ typedef struct {
#endif #endif
#if IS_USED(MODULE_GNRC_NETIF_6LO) || defined(DOXYGEN) #if IS_USED(MODULE_GNRC_NETIF_6LO) || defined(DOXYGEN)
gnrc_netif_6lo_t sixlo; /**< 6Lo component */ gnrc_netif_6lo_t sixlo; /**< 6Lo component */
#endif
#if IS_USED(MODULE_GNRC_NETIF_PKTQ) || defined(DOXYGEN)
/**
* @brief Packet queue for sending
*
* @note Only available with @ref net_gnrc_netif_pktq.
*/
gnrc_netif_pktq_t send_queue;
#endif #endif
uint8_t cur_hl; /**< Current hop-limit for out-going packets */ uint8_t cur_hl; /**< Current hop-limit for out-going packets */
uint8_t device_type; /**< Device type */ uint8_t device_type; /**< Device type */

View File

@ -54,6 +54,30 @@ extern "C" {
#define CONFIG_GNRC_NETIF_MSG_QUEUE_SIZE_EXP (4U) #define CONFIG_GNRC_NETIF_MSG_QUEUE_SIZE_EXP (4U)
#endif #endif
/**
* @brief Packet queue pool size for all network interfaces
*
* @note With @ref net_gnrc_sixlowpan_frag the queue should fit at least
* all fragments of the minimum MTU.
* @see net_gnrc_netif_pktq
*/
#ifndef CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE
#define CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE (16U)
#endif
/**
* @brief Time in microseconds for when to try send a queued packet at the
* latest
*
* Set to -1 to deactivate dequeing by timer. For this it has to be ensured that
* none of the notifications by the driver are missed!
*
* @see net_gnrc_netif_pktq
*/
#ifndef CONFIG_GNRC_NETIF_PKTQ_TIMER_US
#define CONFIG_GNRC_NETIF_PKTQ_TIMER_US (5000U)
#endif
/** /**
* @brief Number of multicast addresses needed for @ref net_gnrc_rpl "RPL". * @brief Number of multicast addresses needed for @ref net_gnrc_rpl "RPL".
* *

View File

@ -35,6 +35,11 @@
extern "C" { extern "C" {
#endif #endif
/**
* @brief Message type to send from @ref net_gnrc_netif_pktq
*/
#define GNRC_NETIF_PKTQ_DEQUEUE_MSG (0x1233)
/** /**
* @brief Message type for @ref netdev_event_t "netdev events" * @brief Message type for @ref netdev_event_t "netdev events"
*/ */

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2019-20 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_gnrc_netif_pktq Send queue for @ref net_gnrc_netif
* @ingroup net_gnrc_netif
* @brief
* @{
*
* @file
* @brief @ref net_gnrc_netif_pktq definitions
*
* @author Martine S. Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NET_GNRC_NETIF_PKTQ_H
#define NET_GNRC_NETIF_PKTQ_H
#include <assert.h>
#include <stdbool.h>
#include "net/gnrc/netif.h"
#include "net/gnrc/netif/pktq/type.h"
#include "net/gnrc/pkt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Puts a packet into the packet send queue of a network interface
*
* @pre `netif != NULL`
* @pre `pkt != NULL`
*
* @param[in] netif A network interface. May not be NULL.
* @param[in] pkt A packet. May not be NULL.
*
* @return 0 on success
* @return -1 when the pool of available gnrc_pktqueue_t entries (of size
* @ref CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE) is depleted
*/
int gnrc_netif_pktq_put(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
/**
* @brief Gets a packet from the packet send queue of a network interface
*
* @pre `netif != NULL`
*
* @param[in] netif A network interface. May not be NULL.
*
* @return A packet on success
* @return NULL when the queue is empty
*/
static inline gnrc_pktsnip_t *gnrc_netif_pktq_get(gnrc_netif_t *netif)
{
#if IS_USED(MODULE_GNRC_NETIF_PKTQ)
assert(netif != NULL);
gnrc_pktsnip_t *pkt = NULL;
gnrc_pktqueue_t *entry = gnrc_pktqueue_remove_head(
&netif->send_queue.queue
);
if (entry != NULL) {
pkt = entry->pkt;
entry->pkt = NULL;
}
return pkt;
#else /* IS_USED(MODULE_GNRC_NETIF_PKTQ) */
(void)netif;
return NULL;
#endif /* IS_USED(MODULE_GNRC_NETIF_PKTQ) */
}
/**
* @brief Schedule a dequeue notification to network interface
*
* The notification will be scheduled in @ref CONFIG_GNRC_NETIF_PKTQ_TIMER_US
* microseconds.
*
* @pre `netif != NULL`
*
* The signaling message can be used to send the next message in
* gnrc_netif_pktq_t::queue.
*
* @param[in] netif A network interface. May not be NULL.
*/
void gnrc_netif_pktq_sched_get(gnrc_netif_t *netif);
/**
* @brief Pushes a packet back to the head of the packet send queue of a
* network interface
*
* @pre `netif != NULL`
* @pre `pkt != NULL`
*
* @param[in] netif A network interface. May not be NULL.
* @param[in] pkt A packet. May not be NULL.
*
* @return 0 on success
* @return -1 when the pool of available gnrc_pktqueue_t entries (of size
* @ref CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE) is depleted
*/
int gnrc_netif_pktq_push_back(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt);
/**
* @brief Check if a network interface's packet send queue is empty
*
* @pre `netif != NULL`
*
* @param[in] netif A network interface. May not be NULL.
*
* @return true, when the packet send queue of @p netif is empty
* @return false, otherwise
*/
static inline bool gnrc_netif_pktq_empty(gnrc_netif_t *netif)
{
#if IS_USED(MODULE_GNRC_NETIF_PKTQ)
assert(netif != NULL);
return (netif->send_queue.queue == NULL);
#else /* IS_USED(MODULE_GNRC_NETIF_PKTQ) */
(void)netif;
return false;
#endif /* IS_USED(MODULE_GNRC_NETIF_PKTQ) */
}
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NETIF_PKTQ_H */
/** @} */

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2019-20 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup net_gnrc_netif_pktq
* @brief
* @{
*
* @file
* @brief @ref net_gnrc_netif_pktq type definitions
*
* Contained in its own file, so the type can be included in
* @ref gnrc_netif_t while the functions in net/gnrc/netif/pktq.h can use
* @ref gnrc_netif_t as operating type.
*
* @author Martine S. Lenders <m.lenders@fu-berlin.de>
*/
#ifndef NET_GNRC_NETIF_PKTQ_TYPE_H
#define NET_GNRC_NETIF_PKTQ_TYPE_H
#include "net/gnrc/pktqueue.h"
#include "xtimer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief A packet queue for @ref net_gnrc_netif with a de-queue timer
*/
typedef struct {
gnrc_pktqueue_t *queue; /**< the actual packet queue class */
#if CONFIG_GNRC_NETIF_PKTQ_TIMER_US >= 0
msg_t dequeue_msg; /**< message for gnrc_netif_pktq_t::dequeue_timer to send */
xtimer_t dequeue_timer; /**< timer to schedule next sending of
* queued packets */
#endif
} gnrc_netif_pktq_t;
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NETIF_PKTQ_TYPE_H */
/** @} */

View File

@ -48,4 +48,17 @@ config GNRC_NETIF_NONSTANDARD_6LO_MTU
This is non compliant with RFC 4944 and might not be supported by other This is non compliant with RFC 4944 and might not be supported by other
implementations. implementations.
config GNRC_NETIF_PKTQ_POOL_SIZE
int "Packet queue pool size for all network interfaces"
depends on USEMODULE_GNRC_NETIF_PKTQ
default 16
config GNRC_NETIF_PKTQ_TIMER_US
int "Time in microseconds for when to try to send a queued packet at the latest"
depends on USEMODULE_GNRC_NETIF_PKTQ
default 5000
help
Set to -1 to deactivate dequeing by timer. For this it has to be ensured
that none of the notifications by the driver are missed!
endif # KCONFIG_USEMODULE_GNRC_NETIF endif # KCONFIG_USEMODULE_GNRC_NETIF

View File

@ -9,6 +9,9 @@ endif
ifneq (,$(filter gnrc_netif_init_devs,$(USEMODULE))) ifneq (,$(filter gnrc_netif_init_devs,$(USEMODULE)))
DIRS += init_devs DIRS += init_devs
endif endif
ifneq (,$(filter gnrc_netif_pktq,$(USEMODULE)))
DIRS += pktq
endif
ifneq (,$(filter gnrc_netif_hdr,$(USEMODULE))) ifneq (,$(filter gnrc_netif_hdr,$(USEMODULE)))
DIRS += hdr DIRS += hdr
endif endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2014-2017 Freie Universität Berlin * Copyright (C) 2014-20 Freie Universität Berlin
* *
* This file is subject to the terms and conditions of the GNU Lesser * This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level * General Public License v2.1. See the file LICENSE in the top level
@ -27,6 +27,7 @@
#include "net/gnrc/ipv6/nib.h" #include "net/gnrc/ipv6/nib.h"
#include "net/gnrc/ipv6.h" #include "net/gnrc/ipv6.h"
#endif /* MODULE_GNRC_IPV6_NIB */ #endif /* MODULE_GNRC_IPV6_NIB */
#include "net/gnrc/netif/pktq.h"
#ifdef MODULE_NETSTATS #ifdef MODULE_NETSTATS
#include "net/netstats.h" #include "net/netstats.h"
#endif #endif
@ -1161,12 +1162,12 @@ static void _configure_netdev(netdev_t *dev)
if (res < 0) { if (res < 0) {
DEBUG("gnrc_netif: enable NETOPT_RX_END_IRQ failed: %d\n", res); DEBUG("gnrc_netif: enable NETOPT_RX_END_IRQ failed: %d\n", res);
} }
#ifdef MODULE_NETSTATS_L2 if (IS_USED(MODULE_NETSTATS_L2) || IS_USED(MODULE_GNRC_NETIF_PKTQ)) {
res = dev->driver->set(dev, NETOPT_TX_END_IRQ, &enable, sizeof(enable)); res = dev->driver->set(dev, NETOPT_TX_END_IRQ, &enable, sizeof(enable));
if (res < 0) { if (res < 0) {
DEBUG("gnrc_netif: enable NETOPT_TX_END_IRQ failed: %d\n", res); DEBUG("gnrc_netif: enable NETOPT_TX_END_IRQ failed: %d\n", res);
} }
#endif }
} }
#ifdef DEVELHELP #ifdef DEVELHELP
@ -1292,6 +1293,8 @@ void gnrc_netif_default_init(gnrc_netif_t *netif)
#endif #endif
} }
static void _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt, bool push_back);
#if IS_USED(MODULE_GNRC_NETIF_EVENTS) #if IS_USED(MODULE_GNRC_NETIF_EVENTS)
/** /**
* @brief Call the ISR handler from an event * @brief Call the ISR handler from an event
@ -1379,6 +1382,83 @@ static void _process_events_await_msg(gnrc_netif_t *netif, msg_t *msg)
} }
} }
static void _send_queued_pkt(gnrc_netif_t *netif)
{
if (IS_USED(MODULE_GNRC_NETIF_PKTQ)) {
gnrc_pktsnip_t *pkt;
if ((pkt = gnrc_netif_pktq_get(netif)) != NULL) {
_send(netif, pkt, true);
gnrc_netif_pktq_sched_get(netif);
}
}
}
static void _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt, bool push_back)
{
int res;
if (IS_USED(MODULE_GNRC_NETIF_PKTQ)) {
/* send queued packets first to keep order */
if (!push_back && !gnrc_netif_pktq_empty(netif)) {
int put_res;
put_res = gnrc_netif_pktq_put(netif, pkt);
if (put_res == 0) {
DEBUG("gnrc_netif: (re-)queued pkt %p\n", (void *)pkt);
_send_queued_pkt(netif);
return;
}
else {
LOG_WARNING("gnrc_netif: can't queue packet for sending\n");
/* try to send anyway */
}
}
/* hold in case device was busy to not having to rewrite *all* the link
* layer implementations in case `gnrc_netif_pktq` is included */
gnrc_pktbuf_hold(pkt, 1);
}
res = netif->ops->send(netif, pkt);
if (IS_USED(MODULE_GNRC_NETIF_PKTQ) && (res == -EBUSY)) {
int put_res;
/* Lower layer was busy.
* Since "busy" could also mean that the lower layer is currently
* receiving, trying to wait for the device not being busy any more
* could run into the risk of overriding the received packet on send
* Rather, queue the packet within the netif now and try to send them
* again after the device completed its busy state. */
if (push_back) {
put_res = gnrc_netif_pktq_push_back(netif, pkt);
}
else {
put_res = gnrc_netif_pktq_put(netif, pkt);
gnrc_netif_pktq_sched_get(netif);
}
if (put_res == 0) {
DEBUG("gnrc_netif: (re-)queued pkt %p\n", (void *)pkt);
return; /* early return to not release */
}
else {
LOG_ERROR("gnrc_netif: can't queue packet for sending\n");
}
return;
}
else if (IS_USED(MODULE_GNRC_NETIF_PKTQ)) {
/* remove previously held packet */
gnrc_pktbuf_release(pkt);
}
if (res < 0) {
DEBUG("gnrc_netif: error sending packet %p (code: %i)\n",
(void *)pkt, res);
}
#ifdef MODULE_NETSTATS_L2
else {
netif->stats.tx_bytes += res;
}
#endif
}
static void *_gnrc_netif_thread(void *args) static void *_gnrc_netif_thread(void *args)
{ {
gnrc_netapi_opt_t *opt; gnrc_netapi_opt_t *opt;
@ -1440,22 +1520,19 @@ static void *_gnrc_netif_thread(void *args)
/* dispatch netdev, MAC and gnrc_netapi messages */ /* dispatch netdev, MAC and gnrc_netapi messages */
DEBUG("gnrc_netif: message %u\n", (unsigned)msg.type); DEBUG("gnrc_netif: message %u\n", (unsigned)msg.type);
switch (msg.type) { switch (msg.type) {
#if IS_USED(MODULE_GNRC_NETIF_PKTQ)
case GNRC_NETIF_PKTQ_DEQUEUE_MSG:
DEBUG("gnrc_netif: send from packet send queue\n");
_send_queued_pkt(netif);
break;
#endif /* IS_USED(MODULE_GNRC_NETIF_PKTQ) */
case NETDEV_MSG_TYPE_EVENT: case NETDEV_MSG_TYPE_EVENT:
DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_EVENT received\n"); DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_EVENT received\n");
dev->driver->isr(dev); dev->driver->isr(dev);
break; break;
case GNRC_NETAPI_MSG_TYPE_SND: case GNRC_NETAPI_MSG_TYPE_SND:
DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_SND received\n"); DEBUG("gnrc_netif: GNRC_NETDEV_MSG_TYPE_SND received\n");
res = netif->ops->send(netif, msg.content.ptr); _send(netif, msg.content.ptr, false);
if (res < 0) {
DEBUG("gnrc_netif: error sending packet %p (code: %i)\n",
msg.content.ptr, res);
}
#ifdef MODULE_NETSTATS_L2
else {
netif->stats.tx_bytes += res;
}
#endif
#if (CONFIG_GNRC_NETIF_MIN_WAIT_AFTER_SEND_US > 0U) #if (CONFIG_GNRC_NETIF_MIN_WAIT_AFTER_SEND_US > 0U)
xtimer_periodic_wakeup( xtimer_periodic_wakeup(
&last_wakeup, &last_wakeup,
@ -1547,22 +1624,42 @@ static void _event_cb(netdev_t *dev, netdev_event_t event)
switch (event) { switch (event) {
case NETDEV_EVENT_RX_COMPLETE: case NETDEV_EVENT_RX_COMPLETE:
pkt = netif->ops->recv(netif); pkt = netif->ops->recv(netif);
/* send packet previously queued within netif due to the lower
* layer being busy.
* Further packets will be sent on later TX_COMPLETE */
_send_queued_pkt(netif);
if (pkt) { if (pkt) {
_pass_on_packet(pkt); _pass_on_packet(pkt);
} }
break; break;
#ifdef MODULE_NETSTATS_L2 #if IS_USED(MODULE_NETSTATS_L2) || IS_USED(MODULE_GNRC_NETIF_PKTQ)
case NETDEV_EVENT_TX_MEDIUM_BUSY:
/* we are the only ones supposed to touch this variable,
* so no acquire necessary */
netif->stats.tx_failed++;
break;
case NETDEV_EVENT_TX_COMPLETE: case NETDEV_EVENT_TX_COMPLETE:
/* send packet previously queued within netif due to the lower
* layer being busy.
* Further packets will be sent on later TX_COMPLETE or
* TX_MEDIUM_BUSY */
_send_queued_pkt(netif);
#if IS_USED(MODULE_NETSTATS_L2)
/* we are the only ones supposed to touch this variable, /* we are the only ones supposed to touch this variable,
* so no acquire necessary */ * so no acquire necessary */
netif->stats.tx_success++; netif->stats.tx_success++;
#endif /* IS_USED(MODULE_NETSTATS_L2) */
break; break;
#endif #endif /* IS_USED(MODULE_NETSTATS_L2) || IS_USED(MODULE_GNRC_NETIF_PKTQ) */
#if IS_USED(MODULE_NETSTATS_L2) || IS_USED(MODULE_GNRC_NETIF_PKTQ)
case NETDEV_EVENT_TX_MEDIUM_BUSY:
/* send packet previously queued within netif due to the lower
* layer being busy.
* Further packets will be sent on later TX_COMPLETE or
* TX_MEDIUM_BUSY */
_send_queued_pkt(netif);
#if IS_USED(MODULE_NETSTATS_L2)
/* we are the only ones supposed to touch this variable,
* so no acquire necessary */
netif->stats.tx_failed++;
#endif /* IS_USED(MODULE_NETSTATS_L2) */
break;
#endif /* IS_USED(MODULE_NETSTATS_L2) || IS_USED(MODULE_GNRC_NETIF_PKTQ) */
default: default:
DEBUG("gnrc_netif: warning: unhandled event %u.\n", event); DEBUG("gnrc_netif: warning: unhandled event %u.\n", event);
} }

View File

@ -0,0 +1,3 @@
MODULE := gnrc_netif_pktq
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#include "net/gnrc/pktqueue.h"
#include "net/gnrc/netif/conf.h"
#include "net/gnrc/netif/internal.h"
#include "net/gnrc/netif/pktq.h"
static gnrc_pktqueue_t _pool[CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE];
static gnrc_pktqueue_t *_get_free_entry(void)
{
for (unsigned i = 0; i < CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE; i++) {
if (_pool[i].pkt == NULL) {
return &_pool[i];
}
}
return NULL;
}
int gnrc_netif_pktq_put(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
assert(netif != NULL);
assert(pkt != NULL);
gnrc_pktqueue_t *entry = _get_free_entry();
if (entry == NULL) {
return -1;
}
entry->pkt = pkt;
gnrc_pktqueue_add(&netif->send_queue.queue, entry);
return 0;
}
void gnrc_netif_pktq_sched_get(gnrc_netif_t *netif)
{
#if CONFIG_GNRC_NETIF_PKTQ_TIMER_US >= 0
assert(netif != NULL);
netif->send_queue.dequeue_msg.type = GNRC_NETIF_PKTQ_DEQUEUE_MSG;
/* Prevent timer from firing while we add this.
* Otherwise the system might crash: The timer handler sets
* netif->send_queue.dequeue_msg.sender_pid to KERNEL_PID_ISR while
* the message is added to the timer, causing the next round of the timer
* handler to try to send the message to IPC, leaving the system in an
* invalid state. */
unsigned state = irq_disable();
xtimer_set_msg(&netif->send_queue.dequeue_timer,
CONFIG_GNRC_NETIF_PKTQ_TIMER_US,
&netif->send_queue.dequeue_msg, netif->pid);
irq_restore(state);
#else /* CONFIG_GNRC_NETIF_PKTQ_TIMER_US >= 0 */
(void)netif;
#endif /* CONFIG_GNRC_NETIF_PKTQ_TIMER_US >= 0 */
}
int gnrc_netif_pktq_push_back(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
{
assert(netif != NULL);
assert(pkt != NULL);
gnrc_pktqueue_t *entry = _get_free_entry();
if (entry == NULL) {
return -1;
}
entry->pkt = pkt;
LL_PREPEND(netif->send_queue.queue, entry);
return 0;
}
/** @} */

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,3 @@
USEMODULE += gnrc_netif_pktq
CFLAGS += -DCONFIG_GNRC_NETIF_PKTQ_POOL_SIZE=4

View File

@ -0,0 +1,141 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#include "embUnit.h"
#include "net/gnrc/netif/conf.h"
#include "net/gnrc/netif/pktq.h"
#include "tests-gnrc_netif_pktq.h"
gnrc_netif_t _netif;
static void set_up(void)
{
while (gnrc_netif_pktq_get(&_netif)) { }
}
static void test_pktq_get__empty(void)
{
TEST_ASSERT_NULL(gnrc_netif_pktq_get(&_netif));
}
static void test_pktq_put__full(void)
{
gnrc_pktsnip_t pkt;
for (unsigned i = 0; i < CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE; i++) {
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_put(&_netif, &pkt));
}
TEST_ASSERT_EQUAL_INT(-1, gnrc_netif_pktq_put(&_netif, &pkt));
}
static void test_pktq_put_get1(void)
{
gnrc_pktsnip_t pkt_in, *pkt_out;
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_put(&_netif, &pkt_in));
TEST_ASSERT_NOT_NULL((pkt_out = gnrc_netif_pktq_get(&_netif)));
TEST_ASSERT(&pkt_in == pkt_out);
}
static void test_pktq_put_get3(void)
{
gnrc_pktsnip_t pkt_in[3];
for (unsigned i = 0; i < 3; i++) {
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_put(&_netif, &pkt_in[i]));
}
for (unsigned i = 0; i < 3; i++) {
gnrc_pktsnip_t *pkt_out;
TEST_ASSERT_NOT_NULL((pkt_out = gnrc_netif_pktq_get(&_netif)));
TEST_ASSERT(&pkt_in[i] == pkt_out);
}
}
static void test_pktq_push_back__full(void)
{
gnrc_pktsnip_t pkt;
for (unsigned i = 0; i < CONFIG_GNRC_NETIF_PKTQ_POOL_SIZE; i++) {
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_put(&_netif, &pkt));
}
TEST_ASSERT_EQUAL_INT(-1, gnrc_netif_pktq_push_back(&_netif, &pkt));
}
static void test_pktq_push_back_get1(void)
{
gnrc_pktsnip_t pkt_in, *pkt_out;
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_push_back(&_netif, &pkt_in));
TEST_ASSERT_NOT_NULL((pkt_out = gnrc_netif_pktq_get(&_netif)));
TEST_ASSERT(&pkt_in == pkt_out);
}
static void test_pktq_push_back_get3(void)
{
gnrc_pktsnip_t pkt_in[3];
for (unsigned i = 0; i < 3; i++) {
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_push_back(&_netif, &pkt_in[i]));
}
for (unsigned i = 0; i < 3; i++) {
gnrc_pktsnip_t *pkt_out;
TEST_ASSERT_NOT_NULL((pkt_out = gnrc_netif_pktq_get(&_netif)));
TEST_ASSERT(&pkt_in[3 - i - 1] == pkt_out);
}
}
static void test_pktq_empty(void)
{
gnrc_pktsnip_t pkt_in;
TEST_ASSERT(gnrc_netif_pktq_empty(&_netif));
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_put(&_netif, &pkt_in));
TEST_ASSERT(!gnrc_netif_pktq_empty(&_netif));
TEST_ASSERT_NOT_NULL(gnrc_netif_pktq_get(&_netif));
TEST_ASSERT(gnrc_netif_pktq_empty(&_netif));
TEST_ASSERT_EQUAL_INT(0, gnrc_netif_pktq_push_back(&_netif, &pkt_in));
TEST_ASSERT(!gnrc_netif_pktq_empty(&_netif));
TEST_ASSERT_NOT_NULL(gnrc_netif_pktq_get(&_netif));
TEST_ASSERT(gnrc_netif_pktq_empty(&_netif));
}
static Test *test_gnrc_netif_pktq(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_pktq_get__empty),
new_TestFixture(test_pktq_put__full),
new_TestFixture(test_pktq_put_get1),
new_TestFixture(test_pktq_put_get3),
new_TestFixture(test_pktq_push_back__full),
new_TestFixture(test_pktq_push_back_get1),
new_TestFixture(test_pktq_push_back_get3),
new_TestFixture(test_pktq_empty),
};
EMB_UNIT_TESTCALLER(pktq_tests, set_up, NULL, fixtures);
return (Test *)&pktq_tests;
}
void tests_gnrc_netif_pktq(void)
{
TESTS_RUN(test_gnrc_netif_pktq());
}
/** @} */

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup unittests
* @{
*
* @file
* @brief unittests for the `gnrc_netif_pktq` module
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef TESTS_GNRC_NETIF_PKTQ_H
#define TESTS_GNRC_NETIF_PKTQ_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The entry point of this test suite.
*/
void tests_pktqueue(void);
#ifdef __cplusplus
}
#endif
#endif /* TESTS_GNRC_NETIF_PKTQ_H */
/** @} */