1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:32:45 +01:00

gnrc_netif: add a send queue

This commit is contained in:
Martine Lenders 2019-03-25 11:15:15 +01:00 committed by Martine S. Lenders
parent 6b2cde787c
commit 7c7f667108
No known key found for this signature in database
GPG Key ID: CCD317364F63286F
11 changed files with 355 additions and 2 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

@ -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
#ifdef MODULE_GNRC_NETIF_PKTQ
#include "net/gnrc/pktqueue.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"
@ -67,6 +70,9 @@
#endif #endif
#include "rmutex.h" #include "rmutex.h"
#include "net/netif.h" #include "net/netif.h"
#ifdef MODULE_GNRC_NETIF_PKTQ
#include "xtimer.h"
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -171,6 +177,16 @@ 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 defined(MODULE_GNRC_NETIF_PKTQ) || DOXYGEN
/**
* @brief Packet queue for sending
*
* @note Only available with @ref net_gnrc_netif_pktq.
*/
gnrc_pktqueue_t *send_queue;
msg_t dequeue_msg; /**< message for gnrc_netif_t::dequeue_timer to send */
xtimer_t dequeue_timer; /**< timer to schedule next sending of queued packets */
#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,10 +35,15 @@
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"
*/ */
#define NETDEV_MSG_TYPE_EVENT (0x1234) #define NETDEV_MSG_TYPE_EVENT (0x1234)
/** /**
* @brief Acquires exclusive access to the interface * @brief Acquires exclusive access to the interface

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

@ -1161,7 +1161,7 @@ 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 defined(MODULE_NETSTATS_L2) || defined(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);
@ -1292,6 +1292,8 @@ void gnrc_netif_default_init(gnrc_netif_t *netif)
#endif #endif
} }
static void _send(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt, bool requeue);
#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
@ -1547,10 +1549,21 @@ 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;
#if defined(MODULE_NETSTATS_L2) || defined(MODULE_GNRC_NETIF_PKTQ)
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);
#ifdef MODULE_NETSTATS_L2 #ifdef MODULE_NETSTATS_L2
case NETDEV_EVENT_TX_MEDIUM_BUSY: case NETDEV_EVENT_TX_MEDIUM_BUSY:
/* we are the only ones supposed to touch this variable, /* we are the only ones supposed to touch this variable,

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;
}
/** @} */