Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_sixlowpan_frag: initial import of the VRB #11000

Merged
merged 3 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions sys/include/net/gnrc/sixlowpan/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,37 @@ extern "C" {
#define GNRC_SIXLOWPAN_ND_AR_LTIME (15U)
#endif

/**
* @brief Size of the virtual reassembly buffer
*
* @see https://tools.ietf.org/html/draft-ietf-lwig-6lowpan-virtual-reassembly-01
*
* @note Only applicable with
* [gnrc_sixlowpan_frag_vrb](@ref net_gnrc_sixlowpan_frag_vrb) module,
* but has also a direct influence on the number of available
* gnrc_sixlowpan_rbuf_int_t entries (even when
* `gnrc_sixlowpan_frag_vrb` is not compiled in).
*/
#ifndef GNRC_SIXLOWPAN_FRAG_VRB_SIZE
#if defined(MODULE_GNRC_SIXLOWPAN_FRAG_VRB) || defined(DOXYGEN)
#define GNRC_SIXLOWPAN_FRAG_VRB_SIZE (16U)
#else /* defined(MODULE_GNRC_SIXLOWPAN_FRAG_VRB) || defined(DOXYGEN) */
#define GNRC_SIXLOWPAN_FRAG_VRB_SIZE (0U)
#endif /* defined(MODULE_GNRC_SIXLOWPAN_FRAG_VRB) || defined(DOXYGEN) */
#endif /* GNRC_SIXLOWPAN_FRAG_VRB_SIZE */
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm doing this so complicated, to allow for easy fragment interval multiplicity calculation in #11068 (and coming fragment forwarding solutions):

#define RBUF_INT_SIZE (DIV_CEIL(IPV6_MIN_MTU, GNRC_SIXLOWPAN_FRAG_SIZE) * \
(RBUF_SIZE + GNRC_SIXLOWPAN_FRAG_VRB_SIZE))

If if gnrc_sixlowpan_frag_vrb is not used GNRC_SIXLOWPAN_FRAG_VRB_SIZE is 0 so I just use the fragment intervals required for the real reassembly buffer.


/**
* @brief Timeout for a VRB entry in microseconds
*
* @see https://tools.ietf.org/html/draft-ietf-lwig-6lowpan-virtual-reassembly-01
*
* @note Only applicable with
* [gnrc_sixlowpan_frag_vrb](@ref net_gnrc_sixlowpan_frag_vrb) module.
*/
#ifndef GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US
#define GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US (GNRC_SIXLOWPAN_FRAG_RBUF_TIMEOUT_US)
#endif /* GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US */

#ifdef __cplusplus
}
#endif
Expand Down
149 changes: 149 additions & 0 deletions sys/include/net/gnrc/sixlowpan/frag/vrb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* 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.
*/

/**
* @defgroup net_gnrc_sixlowpan_frag_vrb Virtual reassembly buffer
* @ingroup net_gnrc_sixlowpan_frag
* @brief Virtual reassembly buffer
* @{
*
* @file
* @brief Virtual reassembly buffer definitions
* @see https://tools.ietf.org/html/draft-ietf-lwig-6lowpan-virtual-reassembly-01
*
* @author Martine Lenders <[email protected]>
*/
#ifndef NET_GNRC_SIXLOWPAN_FRAG_VRB_H
#define NET_GNRC_SIXLOWPAN_FRAG_VRB_H

#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>

#include "net/gnrc/netif.h"
#include "net/gnrc/sixlowpan/config.h"
#include "net/gnrc/sixlowpan/frag.h"
#include "timex.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Representation of the virtual reassembly buffer entry
*/
typedef struct {
gnrc_sixlowpan_rbuf_base_t super; /**< base type */

/**
* @brief Link-layer destination address to which the fragments are
* supposed to be forwarded to
*/
uint8_t out_dst[IEEE802154_LONG_ADDRESS_LEN];
/**
* @brief Outgoing interface to gnrc_sixlowpan_frag_vrb_t::out_dst
*/
gnrc_netif_t *out_netif;
/**
* @brief Outgoing tag to gnrc_sixlowpan_frag_vrb_t::out_dst
*/
uint16_t out_tag;
/**
* @brief Length of gnrc_sixlowpan_frag_vrb_t::out_dst
*/
uint8_t out_dst_len;
} gnrc_sixlowpan_frag_vrb_t;

/**
* @brief Adds a new reassembly buffer entry
*
* @param[in] base Base data of the datagram. Must not be `NULL`.
* @param[in] out_netif Network interface that is out-going to @p out_dst.
* @param[in] out_dst Link-layer destination address to which to forward
* fragments identified by @p base. Must not be `NULL`.
* @param[in] out_dst_len Length of @p out_dst. Must be greater than 0.
*
* @pre `base != NULL`
* @pre `out_dst != NULL`
* @pre `out_dst_len > 0`
*
* @return A new VRB entry.
* @return NULL, if VRB is full.
*/
gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_add(
const gnrc_sixlowpan_rbuf_base_t *base,
gnrc_netif_t *out_netif, const uint8_t *out_dst, size_t out_dst_len);

/**
* @brief Checks timeouts and removes entries if necessary
*/
void gnrc_sixlowpan_frag_vrb_gc(void);

/**
* @brief Gets a VRB entry
*
* @param[in] src Link-layer source address of the original fragment.
* @param[in] src_len Length of @p src.
* @param[in] dst Link-layer destination address of the original
* fragment.
* @param[in] dst_len Length of @p dst.
* @param[in] datagram_size The original fragment's datagram size.
* @param[in] src_tag Tag of the original fragment.
*
* @return The VRB entry identified by the given parameters.
* @return NULL, if there is no entry in the VRB that could be identified
* by the given parameters.
*/
gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get(
const uint8_t *src, size_t src_len,
const uint8_t *dst, size_t dst_len,
size_t datagram_size, unsigned src_tag);

/**
* @brief Removes an entry from the VRB
*
* @param[in] vrb A VRB entry
*/
static inline void gnrc_sixlowpan_frag_vrb_rm(gnrc_sixlowpan_frag_vrb_t *vrb)
{
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
gnrc_sixlowpan_frag_rbuf_base_rm(&vrb->super);
#elif defined(TEST_SUITES)
/* for testing just zero datagram_size */
vrb->super.datagram_size = 0;
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG */
}

/**
* @brief Determines if a VRB entry is empty
*
* @param[in] vrb A VRB entry
*
* @return true, if @p vrb entry is empty.
* @return false, if @p vrb entry is not empty.
*/
static inline bool gnrc_sixlowpan_frag_vrb_entry_empty(gnrc_sixlowpan_frag_vrb_t *vrb)
{
return (vrb->super.datagram_size == 0);
}

#if defined(TEST_SUITES) || defined(DOXYGEN)
/**
* @brief Resets the VRB to a clean state
*
* @note Only available when @ref TEST_SUITES is defined
*/
void gnrc_sixlowpan_frag_vrb_reset(void);
#endif

#ifdef __cplusplus
}
#endif

#endif /* NET_GNRC_SIXLOWPAN_FRAG_VRB_H */
/** @} */
3 changes: 3 additions & 0 deletions sys/net/gnrc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ endif
ifneq (,$(filter gnrc_sixlowpan_frag,$(USEMODULE)))
DIRS += network_layer/sixlowpan/frag
endif
ifneq (,$(filter gnrc_sixlowpan_frag_vrb,$(USEMODULE)))
DIRS += network_layer/sixlowpan/frag/vrb
endif
ifneq (,$(filter gnrc_sixlowpan_iphc,$(USEMODULE)))
DIRS += network_layer/sixlowpan/iphc
endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ void gnrc_sixlowpan_frag_rbuf_dispatch_when_complete(gnrc_sixlowpan_rbuf_t *rbuf
{
assert(rbuf);
assert(netif_hdr);
if (rbuf->super.current_size == rbuf->pkt->size) {
if (rbuf->super.current_size == rbuf->super.datagram_size) {
gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(rbuf->super.src,
rbuf->super.src_len,
rbuf->super.dst,
Expand Down
8 changes: 7 additions & 1 deletion sys/net/gnrc/network_layer/sixlowpan/frag/rbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include "net/gnrc.h"
#include "net/gnrc/sixlowpan.h"
#include "net/gnrc/sixlowpan/frag.h"
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
#include "net/gnrc/sixlowpan/frag/vrb.h"
#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */
#include "net/sixlowpan.h"
#include "thread.h"
#include "xtimer.h"
Expand Down Expand Up @@ -264,7 +267,7 @@ void rbuf_gc(void)

for (i = 0; i < RBUF_SIZE; i++) {
/* since pkt occupies pktbuf, aggressivly collect garbage */
if ((rbuf[i].pkt != NULL) &&
if (!rbuf_entry_empty(&rbuf[i]) &&
((now_usec - rbuf[i].super.arrival) > RBUF_TIMEOUT)) {
DEBUG("6lo rfrag: entry (%s, ",
gnrc_netif_addr_to_str(rbuf[i].super.src,
Expand All @@ -280,6 +283,9 @@ void rbuf_gc(void)
rbuf_rm(&(rbuf[i]));
}
}
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB
gnrc_sixlowpan_frag_vrb_gc();
#endif
}

static inline void _set_rbuf_timeout(void)
Expand Down
3 changes: 3 additions & 0 deletions sys/net/gnrc/network_layer/sixlowpan/frag/vrb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE := gnrc_sixlowpan_frag_vrb

include $(RIOTBASE)/Makefile.base
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* 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 <[email protected]>
*/

#include "net/ieee802154.h"
#include "xtimer.h"

#include "net/gnrc/sixlowpan/frag/vrb.h"

#define ENABLE_DEBUG (0)
#include "debug.h"

static gnrc_sixlowpan_frag_vrb_t _vrb[GNRC_SIXLOWPAN_FRAG_VRB_SIZE];
static char l2addr_str[3 * IEEE802154_LONG_ADDRESS_LEN];
miri64 marked this conversation as resolved.
Show resolved Hide resolved

#if !defined(MODULE_GNRC_SIXLOWPAN_FRAG) && defined(TEST_SUITES)
/* mock for e.g. testing */
uint16_t tag = 0;

uint16_t gnrc_sixlowpan_frag_next_tag(void)
{
return tag++;
}
#endif /* !defined(MODULE_GNRC_SIXLOWPAN_FRAG) && defined(TEST_SUITES) */

gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_add(
const gnrc_sixlowpan_rbuf_base_t *base,
gnrc_netif_t *out_netif, const uint8_t *out_dst, size_t out_dst_len)
{
gnrc_sixlowpan_frag_vrb_t *vrbe = NULL;

assert(base != NULL);
assert(out_netif != NULL);
assert(out_dst != NULL);
assert(out_dst_len > 0);
for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) {
gnrc_sixlowpan_frag_vrb_t *ptr = &_vrb[i];

if (gnrc_sixlowpan_frag_vrb_entry_empty(ptr) ||
(memcmp(&ptr->super, base, sizeof(ptr->super)) == 0)) {
vrbe = ptr;
if (gnrc_sixlowpan_frag_vrb_entry_empty(vrbe)) {
vrbe->super = *base;
vrbe->out_netif = out_netif;
memcpy(vrbe->out_dst, out_dst, out_dst_len);
vrbe->out_tag = gnrc_sixlowpan_frag_next_tag();
vrbe->out_dst_len = out_dst_len;
DEBUG("6lo vrb: creating entry (%s, ",
gnrc_netif_addr_to_str(vrbe->super.src,
vrbe->super.src_len,
l2addr_str));
DEBUG("%s, %u, %u) => ",
gnrc_netif_addr_to_str(vrbe->super.dst,
vrbe->super.dst_len,
l2addr_str),
(unsigned)vrbe->super.datagram_size, vrbe->super.tag);
DEBUG("(%s, %u)\n",
gnrc_netif_addr_to_str(vrbe->out_dst,
vrbe->out_dst_len,
l2addr_str), vrbe->out_tag);
}
break;
}
}
return vrbe;
}

gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get(
const uint8_t *src, size_t src_len,
const uint8_t *dst, size_t dst_len,
size_t datagram_size, unsigned src_tag)
{
DEBUG("6lo vrb: trying to get entry for (%s, ",
gnrc_netif_addr_to_str(src, src_len, l2addr_str));
DEBUG("%s, %u, %u)\n",
gnrc_netif_addr_to_str(dst, dst_len, l2addr_str),
(unsigned)datagram_size, src_tag);
for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) {
gnrc_sixlowpan_frag_vrb_t *vrbe = &_vrb[i];

if ((vrbe->super.datagram_size == datagram_size) &&
(vrbe->super.tag == src_tag) &&
(vrbe->super.src_len == src_len) &&
(vrbe->super.dst_len == dst_len) &&
(memcmp(vrbe->super.src, src, src_len) == 0) &&
(memcmp(vrbe->super.dst, dst, dst_len) == 0)) {
DEBUG("6lo vrb: got VRB to (%s, %u)\n",
gnrc_netif_addr_to_str(vrbe->out_dst,
vrbe->out_dst_len,
l2addr_str), vrbe->out_tag);
return vrbe;
}
}
DEBUG("6lo vrb: no entry found\n");
return NULL;
}

void gnrc_sixlowpan_frag_vrb_gc(void)
{
uint32_t now_usec = xtimer_now_usec();

for (unsigned i = 0; i < GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) {
if (!gnrc_sixlowpan_frag_vrb_entry_empty(&_vrb[i]) &&
(now_usec - _vrb[i].super.arrival) > GNRC_SIXLOWPAN_FRAG_VRB_TIMEOUT_US) {
DEBUG("6lo vrb: entry (%s, ",
gnrc_netif_addr_to_str(_vrb[i].super.src,
_vrb[i].super.src_len,
l2addr_str));
DEBUG("%s, %u, %u) timed out\n",
gnrc_netif_addr_to_str(_vrb[i].super.dst,
_vrb[i].super.dst_len,
l2addr_str),
(unsigned)_vrb[i].super.datagram_size, _vrb[i].super.tag);
gnrc_sixlowpan_frag_vrb_rm(&_vrb[i]);
}
}
}

#ifdef TEST_SUITES
void gnrc_sixlowpan_frag_vrb_reset(void)
{
memset(_vrb, 0, sizeof(_vrb));
}
#endif

/** @} */
1 change: 1 addition & 0 deletions tests/unittests/tests-gnrc_sixlowpan_frag_vrb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
USEMODULE += gnrc_sixlowpan_frag_vrb
USEMODULE += xtimer
Loading