Merge pull request #16568 from benpicco/gnrc_ipv6_nib-rio
gnrc_ipv6_nib: handle route information option and add config to add to final RAs
This commit is contained in:
commit
8492bd7b12
@ -43,6 +43,7 @@ PSEUDOMODULES += gnrc_ipv6_nib_6lbr
|
|||||||
PSEUDOMODULES += gnrc_ipv6_nib_6ln
|
PSEUDOMODULES += gnrc_ipv6_nib_6ln
|
||||||
PSEUDOMODULES += gnrc_ipv6_nib_6lr
|
PSEUDOMODULES += gnrc_ipv6_nib_6lr
|
||||||
PSEUDOMODULES += gnrc_ipv6_nib_dns
|
PSEUDOMODULES += gnrc_ipv6_nib_dns
|
||||||
|
PSEUDOMODULES += gnrc_ipv6_nib_rio
|
||||||
PSEUDOMODULES += gnrc_ipv6_nib_router
|
PSEUDOMODULES += gnrc_ipv6_nib_router
|
||||||
PSEUDOMODULES += gnrc_netdev_default
|
PSEUDOMODULES += gnrc_netdev_default
|
||||||
PSEUDOMODULES += gnrc_neterr
|
PSEUDOMODULES += gnrc_neterr
|
||||||
|
|||||||
@ -138,6 +138,17 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Include a Route Information Option for subnets
|
||||||
|
* on other interfaces in the last Router Advertisement
|
||||||
|
* generated by @ref gnrc_ipv6_nib_change_rtr_adv_iface
|
||||||
|
*
|
||||||
|
* Requires the `gnrc_ipv6_nib_rio` module.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_GNRC_IPV6_NIB_ADD_RIO_IN_LAST_RA
|
||||||
|
#define CONFIG_GNRC_IPV6_NIB_ADD_RIO_IN_LAST_RA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief (de-)activate NDP address resolution state-machine
|
* @brief (de-)activate NDP address resolution state-machine
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -232,6 +232,35 @@ gnrc_pktsnip_t *gnrc_ndp_opt_pi_build(const ipv6_addr_t *prefix,
|
|||||||
uint8_t prefix_len,
|
uint8_t prefix_len,
|
||||||
uint32_t valid_ltime, uint32_t pref_ltime,
|
uint32_t valid_ltime, uint32_t pref_ltime,
|
||||||
uint8_t flags, gnrc_pktsnip_t *next);
|
uint8_t flags, gnrc_pktsnip_t *next);
|
||||||
|
/**
|
||||||
|
* @brief Builds the route information option.
|
||||||
|
*
|
||||||
|
* @pre `prefix != NULL`
|
||||||
|
* @pre `!ipv6_addr_is_link_local(prefix) && !ipv6_addr_is_multicast(prefix)`
|
||||||
|
* @pre `prefix_len <= 128`
|
||||||
|
*
|
||||||
|
* @see [RFC 4191, section 2.3](https://tools.ietf.org/html/rfc4191#section-2.3)
|
||||||
|
*
|
||||||
|
* @note Should only be used with router advertisemnents. This is not checked
|
||||||
|
* however, since nodes should silently ignore it in other NDP messages.
|
||||||
|
*
|
||||||
|
* @param[in] prefix An IPv6 address or a prefix of an IPv6 address.
|
||||||
|
* Must not be NULL or be a link-local or
|
||||||
|
* multicast address.
|
||||||
|
* @param[in] prefix_len The length of @p prefix in bits. Must be between
|
||||||
|
* 0 and 128.
|
||||||
|
* @param[in] route_ltime Length of time in seconds that @p prefix is valid.
|
||||||
|
* UINT32_MAX represents infinity.
|
||||||
|
* @param[in] flags Flags as defined in net/ndp.h.
|
||||||
|
* @param[in] next More options in the packet. NULL, if there are none.
|
||||||
|
*
|
||||||
|
* @return The packet snip list of options, on success
|
||||||
|
* @return NULL, if packet buffer is full
|
||||||
|
*/
|
||||||
|
gnrc_pktsnip_t *gnrc_ndp_opt_ri_build(const ipv6_addr_t *prefix,
|
||||||
|
uint8_t prefix_len,
|
||||||
|
uint32_t route_ltime,
|
||||||
|
uint8_t flags, gnrc_pktsnip_t *next);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Builds the MTU option.
|
* @brief Builds the MTU option.
|
||||||
|
|||||||
@ -88,6 +88,7 @@ extern "C" {
|
|||||||
#define NDP_OPT_PI (3) /**< prefix information option */
|
#define NDP_OPT_PI (3) /**< prefix information option */
|
||||||
#define NDP_OPT_RH (4) /**< redirected option */
|
#define NDP_OPT_RH (4) /**< redirected option */
|
||||||
#define NDP_OPT_MTU (5) /**< MTU option */
|
#define NDP_OPT_MTU (5) /**< MTU option */
|
||||||
|
#define NDP_OPT_RI (24) /**< Route Information Option */
|
||||||
#define NDP_OPT_RDNSS (25) /**< recursive DNS server option */
|
#define NDP_OPT_RDNSS (25) /**< recursive DNS server option */
|
||||||
#define NDP_OPT_AR (33) /**< address registration option */
|
#define NDP_OPT_AR (33) /**< address registration option */
|
||||||
#define NDP_OPT_6CTX (34) /**< 6LoWPAN context option */
|
#define NDP_OPT_6CTX (34) /**< 6LoWPAN context option */
|
||||||
@ -103,6 +104,17 @@ extern "C" {
|
|||||||
#define NDP_OPT_PI_FLAGS_A (0x40) /**< autonomous address configuration */
|
#define NDP_OPT_PI_FLAGS_A (0x40) /**< autonomous address configuration */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @{
|
||||||
|
* @name Flags for route information option
|
||||||
|
*/
|
||||||
|
#define NDP_OPT_RI_FLAGS_MASK (0x18)
|
||||||
|
#define NDP_OPT_RI_FLAGS_PRF_NONE (0x10) /**< ignore preference */
|
||||||
|
#define NDP_OPT_RI_FLAGS_PRF_NEG (0x18) /**< negative preference */
|
||||||
|
#define NDP_OPT_RI_FLAGS_PRF_ZERO (0x0) /**< zero preference */
|
||||||
|
#define NDP_OPT_RI_FLAGS_PRF_POS (0x8) /**< positive preference */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @{
|
* @{
|
||||||
* @name Prefix information option constants
|
* @name Prefix information option constants
|
||||||
@ -308,6 +320,21 @@ typedef struct __attribute__((packed)) {
|
|||||||
ipv6_addr_t prefix; /**< prefix */
|
ipv6_addr_t prefix; /**< prefix */
|
||||||
} ndp_opt_pi_t;
|
} ndp_opt_pi_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Route information option format
|
||||||
|
* @extends ndp_opt_t
|
||||||
|
*
|
||||||
|
* @see [RFC 4191, section 2.3](https://tools.ietf.org/html/rfc4191#section-2.3)
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
uint8_t type; /**< option type */
|
||||||
|
uint8_t len; /**< length in units of 8 octets */
|
||||||
|
uint8_t prefix_len; /**< prefix length */
|
||||||
|
uint8_t flags; /**< flags */
|
||||||
|
network_uint32_t route_ltime; /**< route lifetime */
|
||||||
|
ipv6_addr_t prefix; /**< prefix */
|
||||||
|
} ndp_opt_ri_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Redirected header option format
|
* @brief Redirected header option format
|
||||||
* @extends ndp_opt_t
|
* @extends ndp_opt_t
|
||||||
|
|||||||
@ -247,6 +247,7 @@ ifneq (,$(filter gnrc_ipv6_default,$(USEMODULE)))
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
|
ifneq (,$(filter gnrc_ipv6_router_default,$(USEMODULE)))
|
||||||
|
USEMODULE += gnrc_ipv6_nib_rio
|
||||||
USEMODULE += gnrc_ipv6_router
|
USEMODULE += gnrc_ipv6_router
|
||||||
USEMODULE += gnrc_icmpv6
|
USEMODULE += gnrc_icmpv6
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -215,6 +215,52 @@ static gnrc_pktsnip_t *_build_ext_opts(gnrc_netif_t *netif,
|
|||||||
return ext_opts;
|
return ext_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sending a RA with ltime = 0 causes the router to be removed from the
|
||||||
|
* default router list, but options are still parsed.
|
||||||
|
* This allows us to add downstream subnets that should be routed through
|
||||||
|
* this router, but the router is not an upstream / default router for
|
||||||
|
* this link. */
|
||||||
|
static gnrc_pktsnip_t *_build_final_ext_opts(gnrc_netif_t *netif)
|
||||||
|
{
|
||||||
|
gnrc_pktsnip_t *ext_opts = NULL;
|
||||||
|
_nib_offl_entry_t *entry = NULL;
|
||||||
|
|
||||||
|
if (!IS_USED(MODULE_GNRC_IPV6_NIB_RIO) ||
|
||||||
|
!IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_ADD_RIO_IN_LAST_RA)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("nib: sending final RA on interface %u\n", netif->pid);
|
||||||
|
|
||||||
|
uint32_t now = evtimer_now_msec();
|
||||||
|
while ((entry = _nib_offl_iter(entry))) {
|
||||||
|
|
||||||
|
unsigned id = netif->pid;
|
||||||
|
if (_nib_onl_get_if(entry->next_hop) == id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((entry->mode & _PL) && (entry->flags & _PFX_ON_LINK)) {
|
||||||
|
DEBUG("nib: adding downstream subnet to RA\n");
|
||||||
|
uint32_t valid_ltime = (entry->valid_until == UINT32_MAX) ? UINT32_MAX :
|
||||||
|
((entry->valid_until - now) / MS_PER_SEC);
|
||||||
|
gnrc_pktsnip_t *snip = gnrc_ndp_opt_ri_build(&entry->pfx,
|
||||||
|
entry->pfx_len,
|
||||||
|
valid_ltime,
|
||||||
|
NDP_OPT_RI_FLAGS_PRF_NONE,
|
||||||
|
ext_opts);
|
||||||
|
if (snip != NULL) {
|
||||||
|
ext_opts = snip;
|
||||||
|
} else {
|
||||||
|
DEBUG_PUTS("nib: can't add RIO to RA - out of memory");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ext_opts;
|
||||||
|
}
|
||||||
|
|
||||||
void _set_rtr_adv(gnrc_netif_t *netif)
|
void _set_rtr_adv(gnrc_netif_t *netif)
|
||||||
{
|
{
|
||||||
DEBUG("nib: set RTR_ADV flag for interface %i\n", netif->pid);
|
DEBUG("nib: set RTR_ADV flag for interface %i\n", netif->pid);
|
||||||
@ -228,7 +274,9 @@ static void _snd_ra(gnrc_netif_t *netif, const ipv6_addr_t *dst,
|
|||||||
{
|
{
|
||||||
gnrc_pktsnip_t *ext_opts = NULL;
|
gnrc_pktsnip_t *ext_opts = NULL;
|
||||||
|
|
||||||
if (!final) {
|
if (final) {
|
||||||
|
ext_opts = _build_final_ext_opts(netif);
|
||||||
|
} else {
|
||||||
ext_opts = _build_ext_opts(netif, abr);
|
ext_opts = _build_ext_opts(netif, abr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -461,6 +461,8 @@ static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6,
|
|||||||
static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6,
|
static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6,
|
||||||
const ndp_opt_pi_t *pio);
|
const ndp_opt_pi_t *pio);
|
||||||
#endif /* CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C */
|
#endif /* CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C */
|
||||||
|
static uint32_t _handle_rio(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
|
||||||
|
const ndp_opt_ri_t *pio);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/* Iterator for NDP options in a packet */
|
/* Iterator for NDP options in a packet */
|
||||||
@ -738,6 +740,9 @@ static void _handle_rtr_adv(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
|
|||||||
_handle_mtuo(netif, (const icmpv6_hdr_t *)rtr_adv,
|
_handle_mtuo(netif, (const icmpv6_hdr_t *)rtr_adv,
|
||||||
(ndp_opt_mtu_t *)opt);
|
(ndp_opt_mtu_t *)opt);
|
||||||
break;
|
break;
|
||||||
|
case NDP_OPT_RI:
|
||||||
|
_handle_rio(netif, ipv6, (ndp_opt_ri_t *)opt);
|
||||||
|
break;
|
||||||
case NDP_OPT_PI: {
|
case NDP_OPT_PI: {
|
||||||
uint32_t min_pfx_timeout;
|
uint32_t min_pfx_timeout;
|
||||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C)
|
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_MULTIHOP_P6C)
|
||||||
@ -1584,4 +1589,55 @@ static uint32_t _handle_pio(gnrc_netif_t *netif, const icmpv6_hdr_t *icmpv6,
|
|||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *_prio_string(uint8_t prio)
|
||||||
|
{
|
||||||
|
switch (prio & NDP_OPT_RI_FLAGS_MASK) {
|
||||||
|
case NDP_OPT_RI_FLAGS_PRF_NONE:
|
||||||
|
return "none";
|
||||||
|
case NDP_OPT_RI_FLAGS_PRF_NEG:
|
||||||
|
return "-1";
|
||||||
|
case NDP_OPT_RI_FLAGS_PRF_ZERO:
|
||||||
|
return "0";
|
||||||
|
case NDP_OPT_RI_FLAGS_PRF_POS:
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t _handle_rio(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6,
|
||||||
|
const ndp_opt_ri_t *rio)
|
||||||
|
{
|
||||||
|
if (!IS_USED(MODULE_GNRC_IPV6_NIB_RIO)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t route_ltime = byteorder_ntohl(rio->route_ltime);
|
||||||
|
|
||||||
|
if (ipv6_addr_is_link_local(&rio->prefix)) {
|
||||||
|
DEBUG("nib: ignoring RIO with invalid data\n");
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
DEBUG("nib: received valid Route Information option:\n");
|
||||||
|
DEBUG(" - Prefix: %s/%u\n",
|
||||||
|
ipv6_addr_to_str(addr_str, &rio->prefix, sizeof(addr_str)),
|
||||||
|
rio->prefix_len);
|
||||||
|
DEBUG(" - Priority: %s\n", _prio_string(rio->flags));
|
||||||
|
DEBUG(" - Route lifetime: %" PRIu32 "\n",
|
||||||
|
byteorder_ntohl(rio->route_ltime));
|
||||||
|
|
||||||
|
if (route_ltime < UINT32_MAX) { /* UINT32_MAX means infinite lifetime */
|
||||||
|
/* the valid lifetime is given in seconds, but our timers work in
|
||||||
|
* microseconds, so we have to scale down to the smallest possible
|
||||||
|
* value (UINT32_MAX - 1). This is however alright since we ask for
|
||||||
|
* a new router advertisement before this timeout expires */
|
||||||
|
route_ltime = (route_ltime > (UINT32_MAX / MS_PER_SEC)) ?
|
||||||
|
(UINT32_MAX - 1) : route_ltime * MS_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnrc_ipv6_nib_ft_add(&rio->prefix, rio->prefix_len, &ipv6->src,
|
||||||
|
netif->pid, route_ltime);
|
||||||
|
|
||||||
|
return route_ltime;
|
||||||
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|||||||
@ -201,6 +201,30 @@ gnrc_pktsnip_t *gnrc_ndp_opt_pi_build(const ipv6_addr_t *prefix,
|
|||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gnrc_pktsnip_t *gnrc_ndp_opt_ri_build(const ipv6_addr_t *prefix,
|
||||||
|
uint8_t prefix_len,
|
||||||
|
uint32_t route_ltime,
|
||||||
|
uint8_t flags, gnrc_pktsnip_t *next)
|
||||||
|
{
|
||||||
|
assert(prefix != NULL);
|
||||||
|
assert(!ipv6_addr_is_link_local(prefix) && !ipv6_addr_is_multicast(prefix));
|
||||||
|
assert(prefix_len <= 128);
|
||||||
|
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_RI, sizeof(ndp_opt_ri_t),
|
||||||
|
next);
|
||||||
|
|
||||||
|
if (pkt != NULL) {
|
||||||
|
ndp_opt_ri_t *ri_opt = pkt->data;
|
||||||
|
|
||||||
|
ri_opt->prefix_len = prefix_len;
|
||||||
|
ri_opt->flags = (flags & NDP_OPT_PI_FLAGS_MASK);
|
||||||
|
ri_opt->route_ltime = byteorder_htonl(route_ltime);
|
||||||
|
/* Bits beyond prefix_len MUST be 0 */
|
||||||
|
ipv6_addr_set_unspecified(&ri_opt->prefix);
|
||||||
|
ipv6_addr_init_prefix(&ri_opt->prefix, prefix, prefix_len);
|
||||||
|
}
|
||||||
|
return pkt;
|
||||||
|
}
|
||||||
|
|
||||||
gnrc_pktsnip_t *gnrc_ndp_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next)
|
gnrc_pktsnip_t *gnrc_ndp_opt_mtu_build(uint32_t mtu, gnrc_pktsnip_t *next)
|
||||||
{
|
{
|
||||||
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_MTU,
|
gnrc_pktsnip_t *pkt = gnrc_ndp_opt_build(NDP_OPT_MTU,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user