diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index 00796e7fd4424dacbb8ef156b648b40053c5de35..3a4db2763f0264d98b82da7dfa3f2d72c24b1239 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -22,6 +22,7 @@ #ifndef NET_GNRC_IPV6_NIB_H #define NET_GNRC_IPV6_NIB_H +#include "net/gnrc/ipv6/nib/abr.h" #include "net/gnrc/ipv6/nib/nc.h" #include "net/gnrc/ipv6/nib/pl.h" diff --git a/sys/include/net/gnrc/ipv6/nib/abr.h b/sys/include/net/gnrc/ipv6/nib/abr.h new file mode 100644 index 0000000000000000000000000000000000000000..effb1ebd48df5ba4126fdb5cdf1930c87e7c2b09 --- /dev/null +++ b/sys/include/net/gnrc/ipv6/nib/abr.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 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_ipv6_nib_abr Authoritative border router list + * @ingroup net_gnrc_ipv6_nib + * @brief Authoritative border router list component of neighbor + * information base + * @{ + * + * @file + * @brief Authoritative border router list definitions + * + * @author Martine Lenders <m.lenders@fu-berlin.de> + */ +#ifndef NET_GNRC_IPV6_NIB_ABR_H +#define NET_GNRC_IPV6_NIB_ABR_H + +#include "net/ipv6/addr.h" +#include "net/gnrc/ipv6/nib/conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if (GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C) || defined(DOXYGEN) +/** + * @brief Adds the address of an authoritative border router to the NIB + * + * @param[in] addr The address of an authoritative border router. + * + * @return 0 on success. + * @return -ENOMEM, if no space is left in the neighbor cache. + */ +int gnrc_ipv6_nib_abr_add(const ipv6_addr_t *addr); + +/** + * @brief Removes an authoritative border router from the NIB + * + * @param[in] addr The address of an authoritative border router. + */ +void gnrc_ipv6_nib_abr_del(const ipv6_addr_t *addr); +#endif /* (GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C) || defined(DOXYGEN) */ + +#ifdef __cplusplus +} +#endif + +#endif /* NET_GNRC_IPV6_NIB_ABR_H */ +/** @} */ diff --git a/sys/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h index adacc379080aaddc8322501721610818b2ef9056..4710ede5f5092903e92c6367afee7c49f25fab37 100644 --- a/sys/include/net/gnrc/ipv6/nib/conf.h +++ b/sys/include/net/gnrc/ipv6/nib/conf.h @@ -194,6 +194,15 @@ extern "C" { #define GNRC_IPV6_NIB_OFFL_NUMOF (8) #endif +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) +/** + * @brief Number of authoritative border router entries in NIB + */ +#ifndef GNRC_IPV6_NIB_ABR_NUMOF +#define GNRC_IPV6_NIB_ABR_NUMOF (1) +#endif +#endif + #ifdef __cplusplus } #endif diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c index 1593f940570667e1282892409fda9e226dbbac03..87049f245d65921b87aa24e083d0e116bad561f3 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c @@ -37,6 +37,10 @@ static _nib_offl_entry_t _dsts[GNRC_IPV6_NIB_OFFL_NUMOF]; static _nib_dr_entry_t _def_routers[GNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF]; static _nib_iface_t _nis[GNRC_NETIF_NUMOF]; +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +static _nib_abr_entry_t _abrs[GNRC_IPV6_NIB_ABR_NUMOF]; +#endif + #if ENABLE_DEBUG static char addr_str[IPV6_ADDR_MAX_STR_LEN]; #endif @@ -57,6 +61,9 @@ void _nib_init(void) memset(_def_routers, 0, sizeof(_def_routers)); memset(_dsts, 0, sizeof(_dsts)); memset(_nis, 0, sizeof(_nis)); +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C + memset(_abrs, 0, sizeof(_abrs)); +#endif #endif evtimer_init_msg(&_nib_evtimer); /* TODO: load ABR information from persistent memory */ @@ -450,6 +457,13 @@ static inline bool _in_dsts(const _nib_offl_entry_t *dst) return (dst < (_dsts + GNRC_IPV6_NIB_OFFL_NUMOF)); } +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +static inline bool _in_abrs(const _nib_abr_entry_t *abr) +{ + return (abr < (_abrs + GNRC_IPV6_NIB_ABR_NUMOF)); +} +#endif + void _nib_offl_clear(_nib_offl_entry_t *dst) { if (dst->next_hop != NULL) { @@ -483,6 +497,131 @@ _nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last) return NULL; } +void _nib_pl_remove(_nib_offl_entry_t *nib_offl) +{ + _nib_offl_remove(nib_offl, _PL); +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C + unsigned idx = nib_offl - _dsts; + if (idx < GNRC_IPV6_NIB_OFFL_NUMOF) { + for (_nib_abr_entry_t *abr = _abrs; _in_abrs(abr); abr++) { + if (bf_isset(abr->pfxs, idx)) { + DEBUG("nib: Removing prefix %s/%u ", + ipv6_addr_to_str(addr_str, &nib_offl->pfx, + sizeof(addr_str)), + nib_offl->pfx_len); + DEBUG("from border router %s\n", + ipv6_addr_to_str(addr_str, &abr->addr, sizeof(addr_str))); + bf_unset(abr->pfxs, idx); + } + } + } +#endif +} + +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +_nib_abr_entry_t *_nib_abr_add(const ipv6_addr_t *addr) +{ + _nib_abr_entry_t *abr = NULL; + + assert(addr != NULL); + DEBUG("nib: Allocating authoritative border router entry (addr = %s)\n", + ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); + for (unsigned i = 0; i < GNRC_IPV6_NIB_ABR_NUMOF; i++) { + _nib_abr_entry_t *tmp = &_abrs[i]; + + if (ipv6_addr_equal(addr, &tmp->addr)) { + /* exact match */ + DEBUG(" %p is an exact match\n", (void *)tmp); + return tmp; + } + if ((abr == NULL) && (ipv6_addr_is_unspecified(&tmp->addr))) { + abr = tmp; + } + } + if (abr != NULL) { + DEBUG(" using %p\n", (void *)abr); + memcpy(&abr->addr, addr, sizeof(abr->addr)); + } +#if ENABLE_DEBUG + else { + DEBUG(" NIB full\n"); + } +#endif + return abr; +} + +void _nib_abr_remove(const ipv6_addr_t *addr) +{ + assert(addr != NULL); + DEBUG("nib: Removing border router %s\n", ipv6_addr_to_str(addr_str, addr, + sizeof(addr_str))); + for (_nib_abr_entry_t *abr = _abrs; _in_abrs(abr); abr++) { + if (ipv6_addr_equal(addr, &abr->addr)) { + for (int i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) { + if (bf_isset(abr->pfxs, i)) { + _nib_pl_remove(&_dsts[i]); + } + } +#if MODULE_GNRC_SIXLOWPAN_CTX + for (int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) { + if (bf_isset(abr->ctxs, i)) { + gnrc_sixlowpan_ctx_remove(i); + } + } +#endif + memset(abr, 0, sizeof(_nib_abr_entry_t)); + } + } +} + +void _nib_abr_add_pfx(_nib_abr_entry_t *abr, const _nib_offl_entry_t *offl) +{ + assert((abr != NULL) && (offl != NULL) && (offl->mode & _PL)); + unsigned idx = (unsigned)(_dsts - offl); + + DEBUG("nib: Prefix %s/%u ", + ipv6_addr_to_str(addr_str, &offl->pfx, sizeof(addr_str)), + offl->pfx_len); + DEBUG("came from border router %s\n", ipv6_addr_to_str(addr_str, &abr->addr, + sizeof(addr_str))); + if (idx < GNRC_IPV6_NIB_OFFL_NUMOF) { + bf_set(abr->pfxs, idx); + } +} + +_nib_offl_entry_t *_nib_abr_iter_pfx(const _nib_abr_entry_t *abr, + const _nib_offl_entry_t *last) +{ + if ((last == NULL) || + (((unsigned)(_dsts - last)) < GNRC_IPV6_NIB_OFFL_NUMOF)) { + /* we don't change `ptr`, so dropping const qualifier for now is okay */ + _nib_offl_entry_t *ptr = (_nib_offl_entry_t *)last; + + while ((ptr = _nib_offl_iter(ptr))) { + /* bf_isset() discards const, but doesn't change the array, so + * discarding it on purpose */ + if ((ptr->mode & _PL) && (bf_isset((uint8_t *)abr->pfxs, ptr - _dsts))) { + return ptr; + } + } + } + return NULL; +} + +_nib_abr_entry_t *_nib_abr_iter(const _nib_abr_entry_t *last) +{ + for (const _nib_abr_entry_t *abr = (last) ? (last + 1) : _abrs; + _in_abrs(abr); abr++) { + if (!ipv6_addr_is_unspecified(&abr->addr)) { + /* const modifier provided to assure internal consistency. + * Can now be discarded. */ + return (_nib_abr_entry_t *)abr; + } + } + return NULL; +} +#endif /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */ + _nib_offl_entry_t *_nib_pl_add(unsigned iface, const ipv6_addr_t *pfx, unsigned pfx_len, diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h index 0b96040b1490d56a61e78a14a4670323bfa8101b..3dd34e6b2fee304d66e78bc4530afcefbcb3fd7f 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h @@ -23,6 +23,7 @@ #include <stdbool.h> #include <stdint.h> +#include "bitfield.h" #include "evtimer_msg.h" #include "kernel_types.h" #include "mutex.h" @@ -34,6 +35,7 @@ #include "net/gnrc/ipv6/nib/nc.h" #include "net/gnrc/ipv6/nib/conf.h" #include "net/gnrc/pktqueue.h" +#include "net/gnrc/sixlowpan/ctx.h" #include "net/ndp.h" #include "random.h" @@ -221,6 +223,27 @@ typedef struct { uint8_t na_sent; } _nib_iface_t; +/** + * @brief Internal NIB-representation of the authoritative border router + * for multihop prefix and 6LoWPAN context dissemination + */ +typedef struct { + ipv6_addr_t addr; /**< The address of the border router */ + uint32_t version; /**< last received version of the info of + * the _nib_abr_entry_t::addr */ + evtimer_msg_event_t timeout; /**< timeout of the information */ + /** + * @brief Bitfield marking the prefixes in the NIB's off-link entries + * disseminated by _nib_abr_entry_t::addr + */ + BITFIELD(pfxs, GNRC_IPV6_NIB_OFFL_NUMOF); + /** + * @brief Bitfield marking the contexts disseminated by + * _nib_abr_entry_t::addr + */ + BITFIELD(ctxs, GNRC_SIXLOWPAN_CTX_SIZE); +} _nib_abr_entry_t; + /** * @brief Mutex for locking the NIB */ @@ -598,11 +621,7 @@ _nib_offl_entry_t *_nib_pl_add(unsigned iface, * * Corresponding on-link entry is removed, too. */ -static inline void _nib_pl_remove(_nib_offl_entry_t *nib_offl) -{ - evtimer_del(&_nib_evtimer, &nib_offl->pfx_timeout.event); - _nib_offl_remove(nib_offl, _PL); -} +void _nib_pl_remove(_nib_offl_entry_t *nib_offl); #if GNRC_IPV6_NIB_CONF_ROUTER || DOXYGEN /** @@ -648,6 +667,65 @@ static inline void _nib_ft_remove(_nib_offl_entry_t *nib_offl) } #endif /* GNRC_IPV6_NIB_CONF_ROUTER */ +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) +/** + * @brief Creates or gets an existing authoritative border router. + * + * @pre `addr != NULL` + * + * @param[in] addr Address of the authoritative border router. + * + * @return An authoritative border router entry, on success. + * @return NULL, if no space is left. + */ +_nib_abr_entry_t *_nib_abr_add(const ipv6_addr_t *addr); + +/** + * @brief Removes an authoritative border router + * + * @pre `addr != NULL` + * + * @param[in] addr Address of the authoritative border router. + */ +void _nib_abr_remove(const ipv6_addr_t *addr); + +/** + * @brief Adds a prefix to the managed prefix of the authoritative border + * router + * + * @pre `(abr != NULL) && (offl != NULL) && (offl->mode & _PL)` + * + * @param[in] abr The border router. + * @param[in] offl The prefix to add. + */ +void _nib_abr_add_pfx(_nib_abr_entry_t *abr, const _nib_offl_entry_t *offl); + +/** + * @brief Iterates over an authoritative border router's prefixes + * + * @pre `(abr != NULL)` + * + * @param[in] abr The border router + * @param[in] last Last prefix (NULL to start) + * + * @return entry after @p last. + * @return NULL, if @p last is the last prefix of @p abr or if @p last + * wasn't in NIB (and != NULL). + */ +_nib_offl_entry_t *_nib_abr_iter_pfx(const _nib_abr_entry_t *abr, + const _nib_offl_entry_t *last); + +/** + * @brief Iterates over authoritative border router entries + * + * @param[in] last Last entry (NULL to start). + * + * @return entry after @p last. + * @return NULL, if @p last is the last ABR in the NIB. + */ +_nib_abr_entry_t *_nib_abr_iter(const _nib_abr_entry_t *last); +#endif + /** * @brief Gets (or creates if it not exists) interface information for * neighbor discovery diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c b/sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c new file mode 100644 index 0000000000000000000000000000000000000000..5c926b7abe74afd614a25e9277347ff06f4992d3 --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 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 <mlenders@inf.fu-berlin.de> + */ + +#include "net/gnrc/ipv6/nib/abr.h" + +#include "_nib-internal.h" + +#if GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +int gnrc_ipv6_nib_abr_add(const ipv6_addr_t *addr) +{ + _nib_abr_entry_t *abr; + _nib_offl_entry_t *offl = NULL; + + mutex_lock(&_nib_mutex); + if ((abr = _nib_abr_add(addr)) == NULL) { + mutex_unlock(&_nib_mutex); + return -ENOMEM; + } + while ((offl = _nib_offl_iter(offl))) { + if (offl->mode & _PL) { + _nib_abr_add_pfx(abr, offl); + } + } +#ifdef MODULE_GNRC_SIXLOWPAN_CTX /* included optionally for NIB testing */ + for (uint8_t id = 0; id < GNRC_SIXLOWPAN_CTX_SIZE; id++) { + if (gnrc_sixlowpan_ctx_lookup_id(id) != NULL) { + bf_set(abr->ctxs, id); + } + } +#endif + mutex_unlock(&_nib_mutex); + return 0; +} + +void gnrc_ipv6_nib_abr_del(const ipv6_addr_t *addr) +{ + mutex_lock(&_nib_mutex); + _nib_abr_remove(addr); + mutex_unlock(&_nib_mutex); +} +#else +typedef int dont_be_pedantic; +#endif + +/** @} */