gnrc_ipv6_nib: add prefix list component
This commit is contained in:
parent
c3d3e7d024
commit
3685fa02ae
@ -23,6 +23,7 @@
|
||||
#define NET_GNRC_IPV6_NIB_H
|
||||
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
#include "net/gnrc/ipv6/nib/pl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
137
sys/include/net/gnrc/ipv6/nib/pl.h
Normal file
137
sys/include/net/gnrc/ipv6/nib/pl.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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_pl Prefix list
|
||||
* @ingroup net_gnrc_ipv6_nib
|
||||
* @brief Prefix list component of neighbor information base
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Prefix list defintions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef NET_GNRC_IPV6_NIB_PL_H
|
||||
#define NET_GNRC_IPV6_NIB_PL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "net/ipv6/addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Prefix list entry view on NIB
|
||||
*/
|
||||
typedef struct {
|
||||
ipv6_addr_t pfx; /**< prefix */
|
||||
uint8_t pfx_len; /**< length of gnrc_ipv6_nib_pl_t::pfx in bits */
|
||||
uint16_t iface; /**< interface gnrc_ipv6_nib_pl_t::pfx is assigned
|
||||
* to */
|
||||
uint32_t valid_until; /**< timestamp (in ms) until which the prefix is
|
||||
valid */
|
||||
uint32_t pref_until; /**< timestamp (in ms) until which the prefix is
|
||||
preferred */
|
||||
} gnrc_ipv6_nib_pl_t;
|
||||
|
||||
/**
|
||||
* @brief Adds (or updates) prefix to NIB
|
||||
*
|
||||
* @pre `(pfx != NULL)`
|
||||
*
|
||||
* @param[in] iface Interface @p pfx is valid on.
|
||||
* @param[in] pfx The prefix. May not be a link-local prefix or a
|
||||
* multicast address and its first @p pfx_len bits
|
||||
* may not be 0.
|
||||
* @param[in] pfx_len Length of @p pfx in bits.
|
||||
* Condition @p pfx_len > 0 must hold.
|
||||
* @param[in] valid_ltime Lifetime (in ms) until prefix expires from now.
|
||||
* UINT32_MAX for infinite lifetime. Addresses with
|
||||
* expired prefixes are removed from @p iface.
|
||||
* @param[in] pref_ltime Lifetime (in ms) until prefix deprecates from now.
|
||||
* UINT32_MAX for infinite lifetime. Addresses with
|
||||
* deprecated prefixes should not be used for new
|
||||
* communication. Only applications with difficulty
|
||||
* changing to another address without service
|
||||
* disruption should use deprecated addresses. May not
|
||||
* be greater then @p valid_ltime.
|
||||
*
|
||||
* @return 0, on success.
|
||||
* @return -EINVAL, if @p pfx was fe80::` or multicast,
|
||||
* @p pfx_len was == 0, the first @p pfx_len bits of @ pfx were 0,
|
||||
* or if pref_ltime > valid_ltime.
|
||||
* @return -ENOMEM, if no space was left in the prefix list.
|
||||
*/
|
||||
int gnrc_ipv6_nib_pl_set(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len,
|
||||
uint32_t valid_ltime, uint32_t pref_ltime);
|
||||
|
||||
/**
|
||||
* @brief Deletes prefix from NIB
|
||||
*
|
||||
* @pre `pfx != NULL`
|
||||
*
|
||||
* @param[in] iface The interface @p pfx is expected to be on (0 for any).
|
||||
* @param[in] pfx The prefix to be removed.
|
||||
* @param[in] pfx_len Length of @p pfx in bits.
|
||||
*/
|
||||
void gnrc_ipv6_nib_pl_del(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len);
|
||||
|
||||
/**
|
||||
* @brief Iterates over all prefix list entries in the NIB.
|
||||
*
|
||||
* @pre `(state != NULL) && (ple != NULL)`
|
||||
*
|
||||
* @param[in] iface Restrict iteration to entries on this interface.
|
||||
* 0 for any interface.
|
||||
* @param[in,out] state Iteration state of the prefix list. Must point to NULL
|
||||
* pointer to start iteration
|
||||
* @param[out] ple The next prefix list entry.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
|
||||
* #include "net/gnrc/ipv6/nib/pl.h"
|
||||
*
|
||||
* int main(void) {
|
||||
* void *state = NULL;
|
||||
* gnrc_ipv6_nib_pl_t ple;
|
||||
*
|
||||
* puts("My prefixes:");
|
||||
* while (gnrc_ipv6_nib_pl_iter(0, &state, &ple)) {
|
||||
* gnrc_ipv6_nib_pl_print(&ple);
|
||||
* }
|
||||
* return 0;
|
||||
* }
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* @return true, if iteration can be continued.
|
||||
* @return false, if @p ple is the last prefix list ple in the NIB.
|
||||
*/
|
||||
bool gnrc_ipv6_nib_pl_iter(unsigned iface, void **state,
|
||||
gnrc_ipv6_nib_pl_t *ple);
|
||||
|
||||
/**
|
||||
* @brief Prints a prefix list entry
|
||||
*
|
||||
* @pre `ple != NULL`
|
||||
*
|
||||
* @param[in] ple A prefix list entry
|
||||
*/
|
||||
void gnrc_ipv6_nib_pl_print(gnrc_ipv6_nib_pl_t *ple);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_GNRC_IPV6_NIB_PL_H */
|
||||
/** @} */
|
||||
@ -483,6 +483,41 @@ _nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
const ipv6_addr_t *pfx,
|
||||
unsigned pfx_len,
|
||||
uint32_t valid_ltime,
|
||||
uint32_t pref_ltime)
|
||||
{
|
||||
_nib_offl_entry_t *dst = _nib_offl_add(NULL, iface, pfx, pfx_len, _PL);
|
||||
|
||||
if (dst == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
assert(valid_ltime >= pref_ltime);
|
||||
if ((valid_ltime != UINT32_MAX) || (pref_ltime != UINT32_MAX)) {
|
||||
uint32_t now = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX;
|
||||
if (pref_ltime != UINT32_MAX) {
|
||||
_evtimer_add(dst, GNRC_IPV6_NIB_PFX_TIMEOUT, &dst->pfx_timeout,
|
||||
pref_ltime);
|
||||
if (((pref_ltime + now) == UINT32_MAX) && (now != 0)) {
|
||||
pref_ltime++;
|
||||
}
|
||||
pref_ltime += now;
|
||||
}
|
||||
if (valid_ltime != UINT32_MAX) {
|
||||
/* prevent valid_ltime from becoming UINT32_MAX */
|
||||
if ((valid_ltime + now) == UINT32_MAX) {
|
||||
valid_ltime++;
|
||||
}
|
||||
valid_ltime += now;
|
||||
}
|
||||
}
|
||||
dst->valid_until = valid_ltime;
|
||||
dst->pref_until = pref_ltime;
|
||||
return dst;
|
||||
}
|
||||
|
||||
_nib_iface_t *_nib_iface_get(unsigned iface)
|
||||
{
|
||||
_nib_iface_t *ni = NULL;
|
||||
|
||||
@ -165,8 +165,16 @@ typedef struct {
|
||||
ipv6_addr_t pfx; /**< prefix to the destination */
|
||||
unsigned pfx_len; /**< prefix-length in bits of
|
||||
* _nib_onl_entry_t::pfx */
|
||||
/**
|
||||
* @brief Event for @ref GNRC_IPV6_NIB_PFX_TIMEOUT
|
||||
*/
|
||||
evtimer_msg_event_t pfx_timeout;
|
||||
uint8_t mode; /**< [mode](@ref net_gnrc_ipv6_nib_mode) of the
|
||||
* off-link entry */
|
||||
uint32_t valid_until; /**< timestamp (in ms) until which the prefix
|
||||
valid (UINT32_MAX means forever) */
|
||||
uint32_t pref_until; /**< timestamp (in ms) until which the prefix
|
||||
preferred (UINT32_MAX means forever) */
|
||||
} _nib_offl_entry_t;
|
||||
|
||||
/**
|
||||
@ -565,6 +573,7 @@ static inline void _nib_dc_remove(_nib_offl_entry_t *nib_offl)
|
||||
*
|
||||
* @pre `(next_hop != NULL)`
|
||||
* @pre `(pfx != NULL) && (pfx != "::") && (pfx_len != 0) && (pfx_len <= 128)`
|
||||
* @pre `(pref_ltime <= valid_ltime)`
|
||||
*
|
||||
* @param[in] iface The interface to the prefix is added to.
|
||||
* @param[in] pfx The IPv6 prefix or address of the destination.
|
||||
@ -576,12 +585,11 @@ static inline void _nib_dc_remove(_nib_offl_entry_t *nib_offl)
|
||||
* @p pfx.
|
||||
* @return NULL, if no space is left.
|
||||
*/
|
||||
static inline _nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
const ipv6_addr_t *pfx,
|
||||
unsigned pfx_len)
|
||||
{
|
||||
return _nib_offl_add(NULL, iface, pfx, pfx_len, _PL);
|
||||
}
|
||||
_nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
const ipv6_addr_t *pfx,
|
||||
unsigned pfx_len,
|
||||
uint32_t valid_ltime,
|
||||
uint32_t pref_ltime);
|
||||
|
||||
/**
|
||||
* @brief Removes a prefix list entry
|
||||
@ -592,6 +600,7 @@ static inline _nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
120
sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
Normal file
120
sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "net/gnrc/ipv6/nib/pl.h"
|
||||
#include "timex.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "_nib-internal.h"
|
||||
|
||||
int gnrc_ipv6_nib_pl_set(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len,
|
||||
uint32_t valid_ltime, uint32_t pref_ltime)
|
||||
{
|
||||
int res = 0;
|
||||
_nib_offl_entry_t *dst;
|
||||
ipv6_addr_t tmp = IPV6_ADDR_UNSPECIFIED;
|
||||
|
||||
assert((pfx != NULL));
|
||||
if (pfx_len > IPV6_ADDR_BIT_LEN) {
|
||||
pfx_len = IPV6_ADDR_BIT_LEN;
|
||||
}
|
||||
ipv6_addr_init_prefix(&tmp, pfx, pfx_len);
|
||||
/* pfx_len == 0 implicitly checked, since this leaves tmp unspecified */
|
||||
if (ipv6_addr_is_unspecified(&tmp) || ipv6_addr_is_link_local(pfx) ||
|
||||
ipv6_addr_is_multicast(pfx) || (pref_ltime > valid_ltime)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&_nib_mutex);
|
||||
dst = _nib_pl_add(iface, pfx, pfx_len, valid_ltime,
|
||||
pref_ltime);
|
||||
if (dst == NULL) {
|
||||
res = -ENOMEM;
|
||||
}
|
||||
mutex_unlock(&_nib_mutex);
|
||||
/* TODO: send RA with PIO, if iface is allowed to send RAs */
|
||||
return res;
|
||||
}
|
||||
|
||||
void gnrc_ipv6_nib_pl_del(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len)
|
||||
{
|
||||
_nib_offl_entry_t *dst = NULL;
|
||||
|
||||
assert(pfx != NULL);
|
||||
mutex_lock(&_nib_mutex);
|
||||
while ((dst = _nib_offl_iter(dst)) != NULL) {
|
||||
assert(dst->next_hop != NULL);
|
||||
if ((pfx_len == dst->pfx_len) &&
|
||||
((iface == 0) || (iface == _nib_onl_get_if(dst->next_hop))) &&
|
||||
(ipv6_addr_match_prefix(pfx, &dst->pfx) >= pfx_len)) {
|
||||
_nib_pl_remove(dst);
|
||||
mutex_unlock(&_nib_mutex);
|
||||
/* TODO: send RA with PIO, if iface is allowed to send RAs */
|
||||
return;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_nib_mutex);
|
||||
}
|
||||
|
||||
bool gnrc_ipv6_nib_pl_iter(unsigned iface, void **state,
|
||||
gnrc_ipv6_nib_pl_t *entry)
|
||||
{
|
||||
_nib_offl_entry_t *dst = *state;
|
||||
|
||||
mutex_lock(&_nib_mutex);
|
||||
while ((dst = _nib_offl_iter(dst)) != NULL) {
|
||||
const _nib_onl_entry_t *node = dst->next_hop;
|
||||
assert(node != NULL);
|
||||
if ((dst->mode & _PL) &&
|
||||
((iface == 0) || (_nib_onl_get_if(node) == iface))) {
|
||||
entry->pfx_len = dst->pfx_len;
|
||||
ipv6_addr_set_unspecified(&entry->pfx);
|
||||
ipv6_addr_init_prefix(&entry->pfx, &dst->pfx, dst->pfx_len);
|
||||
entry->iface = _nib_onl_get_if(node);
|
||||
entry->valid_until = dst->valid_until;
|
||||
entry->pref_until = dst->pref_until;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_nib_mutex);
|
||||
*state = dst;
|
||||
return (*state != NULL);
|
||||
}
|
||||
|
||||
void gnrc_ipv6_nib_pl_print(gnrc_ipv6_nib_pl_t *entry)
|
||||
{
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
ipv6_addr_t pfx = IPV6_ADDR_UNSPECIFIED;
|
||||
uint32_t now = ((xtimer_now_usec64() / US_PER_MS)) & UINT32_MAX;
|
||||
|
||||
ipv6_addr_init_prefix(&pfx, &entry->pfx, entry->pfx_len);
|
||||
printf("%s/%u ", ipv6_addr_to_str(addr_str, &pfx, sizeof(addr_str)),
|
||||
entry->pfx_len);
|
||||
printf("dev #%u ", entry->iface);
|
||||
if (entry->valid_until < UINT32_MAX) {
|
||||
printf(" expires %" PRIu32 "sec", (entry->valid_until - now) / MS_PER_SEC);
|
||||
}
|
||||
if (entry->pref_until < UINT32_MAX) {
|
||||
printf(" deprecates %" PRIu32 "sec", (entry->pref_until - now) / MS_PER_SEC);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
/** @} */
|
||||
Loading…
x
Reference in New Issue
Block a user