From 8e899294502f4a138014b4759a58944a94e5b159 Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 7 Jul 2025 16:23:20 +0200 Subject: [PATCH 1/2] gnrc/rpl: extract `gnrc_rpl_dodag_root_init` --- sys/include/net/gnrc/rpl/dodag.h | 7 ++++++ sys/net/gnrc/routing/rpl/gnrc_rpl.c | 27 ++--------------------- sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c | 24 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/sys/include/net/gnrc/rpl/dodag.h b/sys/include/net/gnrc/rpl/dodag.h index 680b14787b65..1e78779c4fd3 100644 --- a/sys/include/net/gnrc/rpl/dodag.h +++ b/sys/include/net/gnrc/rpl/dodag.h @@ -100,6 +100,13 @@ void gnrc_rpl_instance_remove(gnrc_rpl_instance_t *inst); */ gnrc_rpl_instance_t *gnrc_rpl_instance_get(uint8_t instance_id); +/** + * @brief Setup self as root for the @p dodag. + * + * @param[in] dodag Pointer to the dodag. + */ +void gnrc_rpl_dodag_root_init(gnrc_rpl_dodag_t *dodag); + /** * @brief Initialize a new RPL DODAG with the id @p dodag_id for the instance @p instance. * diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl.c b/sys/net/gnrc/routing/rpl/gnrc_rpl.c index a0ef1a215198..cefbb0958751 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl.c @@ -155,37 +155,14 @@ gnrc_rpl_instance_t *gnrc_rpl_root_init(uint8_t instance_id, const ipv6_addr_t * instance_id = gnrc_rpl_gen_instance_id(local_inst_id); } - gnrc_rpl_dodag_t *dodag = NULL; gnrc_rpl_instance_t *inst = gnrc_rpl_root_instance_init(instance_id, dodag_id, GNRC_RPL_DEFAULT_MOP); if (!inst) { return NULL; } - - dodag = &inst->dodag; - - dodag->dtsn = 1; - dodag->prf = 0; - dodag->dio_interval_doubl = CONFIG_GNRC_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS; - dodag->dio_min = CONFIG_GNRC_RPL_DEFAULT_DIO_INTERVAL_MIN; - dodag->dio_redun = CONFIG_GNRC_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT; - dodag->default_lifetime = CONFIG_GNRC_RPL_DEFAULT_LIFETIME; - dodag->lifetime_unit = CONFIG_GNRC_RPL_LIFETIME_UNIT; - dodag->version = GNRC_RPL_COUNTER_INIT; - dodag->grounded = GNRC_RPL_GROUNDED; - dodag->node_status = GNRC_RPL_ROOT_NODE; - dodag->my_rank = GNRC_RPL_ROOT_RANK; - dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; - - if (!IS_ACTIVE(CONFIG_GNRC_RPL_WITHOUT_PIO)) { - dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; - } - - trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_MSG, - (1 << dodag->dio_min), dodag->dio_interval_doubl, - dodag->dio_redun); - gnrc_rpl_rpble_update(dodag); + gnrc_rpl_dodag_root_init(&inst->dodag); + gnrc_rpl_rpble_update(&inst->dodag); return inst; } diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c index aaa3dca3636a..aaf2c205bad2 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c @@ -150,6 +150,30 @@ gnrc_rpl_instance_t *gnrc_rpl_instance_get(uint8_t instance_id) return NULL; } +void gnrc_rpl_dodag_root_init(gnrc_rpl_dodag_t *dodag) +{ + dodag->dtsn = 1; + dodag->prf = 0; + dodag->dio_interval_doubl = CONFIG_GNRC_RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS; + dodag->dio_min = CONFIG_GNRC_RPL_DEFAULT_DIO_INTERVAL_MIN; + dodag->dio_redun = CONFIG_GNRC_RPL_DEFAULT_DIO_REDUNDANCY_CONSTANT; + dodag->default_lifetime = CONFIG_GNRC_RPL_DEFAULT_LIFETIME; + dodag->lifetime_unit = CONFIG_GNRC_RPL_LIFETIME_UNIT; + dodag->version = GNRC_RPL_COUNTER_INIT; + dodag->grounded = GNRC_RPL_GROUNDED; + dodag->node_status = GNRC_RPL_ROOT_NODE; + dodag->my_rank = GNRC_RPL_ROOT_RANK; + dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; + + if (!IS_ACTIVE(CONFIG_GNRC_RPL_WITHOUT_PIO)) { + dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; + } + + trickle_start(gnrc_rpl_pid, &dodag->trickle, GNRC_RPL_MSG_TYPE_TRICKLE_MSG, + (1 << dodag->dio_min), dodag->dio_interval_doubl, + dodag->dio_redun); +} + bool gnrc_rpl_dodag_init(gnrc_rpl_instance_t *instance, const ipv6_addr_t *dodag_id, kernel_pid_t iface) { From cd963e2bdb1a5d0689fc97b763561f086a9d57ab Mon Sep 17 00:00:00 2001 From: Elena Frank Date: Mon, 7 Jul 2025 16:34:57 +0200 Subject: [PATCH 2/2] gnrc/rpl: float DODAG during local repair If the parent set of a router is empty and a local repair initiated, don't immediately poison all routes. Instead configure node as root of a new floating DODAG to maintain connectivity in the sub-tree. Once a different, grounded DODAG is found the node will join the new DODAG. If no other DODAG is found the floating DODAG will timeout after `CONFIG_GNRC_RPL_DODAG_FLOAT_TIMEOUT` and cleaned up.. --- sys/include/net/gnrc/rpl.h | 14 ++++ sys/include/net/gnrc/rpl/dodag.h | 9 +++ sys/include/net/gnrc/rpl/structs.h | 4 ++ sys/net/gnrc/routing/rpl/gnrc_rpl.c | 18 +++++ sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c | 68 +++++++++++++++++-- .../routing/rpl/gnrc_rpl_internal/globals.h | 4 ++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/sys/include/net/gnrc/rpl.h b/sys/include/net/gnrc/rpl.h index dbdc2b1c52d6..0c22793bd4e7 100644 --- a/sys/include/net/gnrc/rpl.h +++ b/sys/include/net/gnrc/rpl.h @@ -151,6 +151,7 @@ #include "net/gnrc/rpl/dodag.h" #include "net/gnrc/rpl/of_manager.h" #include "net/fib.h" +#include "time_units.h" #include "trickle.h" #ifdef MODULE_NETSTATS_RPL @@ -627,6 +628,19 @@ extern netstats_rpl_t gnrc_rpl_netstats; #define CONFIG_GNRC_RPL_PARENT_TIMEOUT_DIS_RETRIES (3) #endif +/** + * @brief Timeout for floating DODAGs in milliseconds. + * + * @details While a DODOAG is floating, it has no uplink but maintains + * connectivity in the subtree. After the timeout, the DODAG will be + * deconstructed and cleared. + * Nodes will always switch to grounded (i.e., non-floating) DODAGs if + * one becomes available in the meantime. + */ +#ifndef CONFIG_GNRC_RPL_DODAG_FLOAT_TIMEOUT +# define CONFIG_GNRC_RPL_DODAG_FLOAT_TIMEOUT (15 * MS_PER_SEC * SEC_PER_MIN) +#endif + /** * @brief Default network interface for GNRC RPL */ diff --git a/sys/include/net/gnrc/rpl/dodag.h b/sys/include/net/gnrc/rpl/dodag.h index 1e78779c4fd3..edf943c94749 100644 --- a/sys/include/net/gnrc/rpl/dodag.h +++ b/sys/include/net/gnrc/rpl/dodag.h @@ -178,6 +178,15 @@ void gnrc_rpl_parent_update(gnrc_rpl_dodag_t *dodag, gnrc_rpl_parent_t *parent); */ void gnrc_rpl_cleanup_start(gnrc_rpl_dodag_t *dodag); +/** + * @brief Poison all routes of @p dodag by setting an infinite rank, and schedule + * a cleanup for the @p dodag. + * + * @param[in] dodag Pointer to the DODAG + * + */ +void gnrc_rpl_poison_routes(gnrc_rpl_dodag_t *dodag); + /** * @brief Start a local repair. * diff --git a/sys/include/net/gnrc/rpl/structs.h b/sys/include/net/gnrc/rpl/structs.h index fc80056834eb..054d9155005d 100644 --- a/sys/include/net/gnrc/rpl/structs.h +++ b/sys/include/net/gnrc/rpl/structs.h @@ -330,6 +330,10 @@ struct gnrc_rpl_dodag { uint8_t dio_opts; /**< options in the next DIO (see @ref GNRC_RPL_REQ_DIO_OPTS "DIO Options") */ evtimer_msg_event_t dao_event; /**< DAO TX events (see @ref GNRC_RPL_MSG_TYPE_DODAG_DAO_TX) */ + /** + * floating dodag timeout events (see @ref GNRC_RPL_MSG_TYPE_DODAG_FLOAT_TIMEOUT) + */ + evtimer_msg_event_t float_timeout_event; trickle_t trickle; /**< trickle representation */ }; diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl.c b/sys/net/gnrc/routing/rpl/gnrc_rpl.c index cefbb0958751..ede274f39eec 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl.c @@ -326,6 +326,19 @@ static inline void _netapi_notify_event(gnrc_netapi_notify_t *notify) } } +/** + * @brief Handles the timeout for floating DODAG by poisoning all routes. + * + * @param[in] dodag Pointer to the dodag. + */ +static void _dodag_float_timeout(gnrc_rpl_dodag_t *dodag) +{ + if (dodag->grounded != GNRC_RPL_GROUNDED) { + gnrc_rpl_poison_routes(dodag); + } + evtimer_del(&gnrc_rpl_evtimer, (evtimer_event_t *)&dodag->float_timeout_event); +} + static void *_event_loop(void *args) { msg_t msg, reply; @@ -376,6 +389,11 @@ static void *_event_loop(void *args) gnrc_rpl_instance_remove(instance); } break; + case GNRC_RPL_MSG_TYPE_DODAG_FLOAT_TIMEOUT: + DEBUG("RPL: GNRC_RPL_MSG_TYPE_DODAG_FLOAT_TIMEOUT received\n"); + instance = msg.content.ptr; + _dodag_float_timeout(&instance->dodag); + break; case GNRC_RPL_MSG_TYPE_TRICKLE_MSG: DEBUG("RPL: GNRC_RPL_MSG_TYPE_TRICKLE_MSG received\n"); trickle = msg.content.ptr; diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c index aaf2c205bad2..60b4c6407e91 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_dodag.c @@ -77,6 +77,18 @@ static uint16_t _dflt_route_lifetime_sec(gnrc_rpl_dodag_t *dodag) (GNRC_RPL_PARENT_PROBE_INTERVAL / MS_PER_SEC)); } +void gnrc_rpl_poison_routes(gnrc_rpl_dodag_t *dodag) +{ + if (dodag->my_rank != GNRC_RPL_INFINITE_RANK) { + DEBUG("RPL: Poison all children routes in DODAG.\n"); + + /* Poison routes by advertising infinity rank */ + dodag->my_rank = GNRC_RPL_INFINITE_RANK; + trickle_reset_timer(&dodag->trickle); + gnrc_rpl_cleanup_start(dodag); + } +} + bool gnrc_rpl_instance_add(uint8_t instance_id, gnrc_rpl_instance_t **inst) { *inst = NULL; @@ -130,8 +142,9 @@ void gnrc_rpl_dodag_remove(gnrc_rpl_dodag_t *dodag) gnrc_rpl_dodag_remove_all_parents(dodag); trickle_stop(&dodag->trickle); evtimer_del(&gnrc_rpl_evtimer, (evtimer_event_t *)&dodag->dao_event); + evtimer_del(&gnrc_rpl_evtimer, (evtimer_event_t *)&dodag->float_timeout_event); evtimer_del(&gnrc_rpl_evtimer, (evtimer_event_t *)&dodag->instance->cleanup_event); - + memset(dodag, 0, sizeof(gnrc_rpl_dodag_t)); } void gnrc_rpl_instance_remove(gnrc_rpl_instance_t *inst) @@ -164,6 +177,7 @@ void gnrc_rpl_dodag_root_init(gnrc_rpl_dodag_t *dodag) dodag->node_status = GNRC_RPL_ROOT_NODE; dodag->my_rank = GNRC_RPL_ROOT_RANK; dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_DODAG_CONF; + dodag->parents = NULL; if (!IS_ACTIVE(CONFIG_GNRC_RPL_WITHOUT_PIO)) { dodag->dio_opts |= GNRC_RPL_REQ_DIO_OPT_PREFIX_INFO; @@ -200,6 +214,8 @@ bool gnrc_rpl_dodag_init(gnrc_rpl_instance_t *instance, const ipv6_addr_t *dodag dodag->iface = iface; dodag->dao_event.msg.content.ptr = instance; dodag->dao_event.msg.type = GNRC_RPL_MSG_TYPE_DODAG_DAO_TX; + dodag->float_timeout_event.msg.content.ptr = instance; + dodag->float_timeout_event.msg.type = GNRC_RPL_MSG_TYPE_DODAG_FLOAT_TIMEOUT; if ((netif != NULL) && !(netif->flags & GNRC_NETIF_FLAGS_IPV6_FORWARDING)) { gnrc_rpl_leaf_operation(dodag); @@ -215,6 +231,50 @@ bool gnrc_rpl_dodag_init(gnrc_rpl_instance_t *instance, const ipv6_addr_t *dodag return true; } +/** + * @brief Configures the local node as root for a new floating DODAG. + * The DODAG retains the prefix of the @p dodag old ID. + * + * @param[in, out] dodag Pointer to the new dodag. + * + * @retval True on success. + * @retval False if no address was found that can be used as ID for the new + * DODAG. + * @retval If @p dodag is null. + */ +static bool _float_dodag(gnrc_rpl_dodag_t *dodag) +{ + evtimer_event_t *float_event; + + if (!dodag) { + return false; + } + + DEBUG("RPL: Set local node as root for floating DODAG.\n"); + + float_event = (evtimer_event_t *)&dodag->float_timeout_event; + evtimer_del(&gnrc_rpl_evtimer, float_event); + + /* Find address on interface that matches the prefix of the old dodag. */ + gnrc_netif_t *netif = gnrc_netif_get_by_pid(dodag->iface); + int idx = gnrc_netif_ipv6_addr_match(netif, &dodag->dodag_id); + if (idx < 0) { + DEBUG("RPL: could not find address to use as DODAGID."); + return false; + } + + /* Configure node as root. */ + gnrc_rpl_dodag_root_init(dodag); + dodag->dodag_id = netif->ipv6.addrs[idx]; + dodag->grounded &= !GNRC_RPL_GROUNDED; + + /* Floating dodag should timeout eventually if no new grounded dodag is found. */ + float_event->offset = CONFIG_GNRC_RPL_DODAG_FLOAT_TIMEOUT; + evtimer_add_msg(&gnrc_rpl_evtimer, &dodag->float_timeout_event, gnrc_rpl_pid); + + return true; +} + void gnrc_rpl_dodag_remove_all_parents(gnrc_rpl_dodag_t *dodag) { gnrc_rpl_parent_t *elt = NULL; @@ -313,10 +373,8 @@ void gnrc_rpl_local_repair(gnrc_rpl_dodag_t *dodag) dodag->dtsn++; - if (dodag->my_rank != GNRC_RPL_INFINITE_RANK) { - dodag->my_rank = GNRC_RPL_INFINITE_RANK; - trickle_reset_timer(&dodag->trickle); - gnrc_rpl_cleanup_start(dodag); + if ((CONFIG_GNRC_RPL_DODAG_FLOAT_TIMEOUT <= 0) || !_float_dodag(dodag)) { + gnrc_rpl_poison_routes(dodag); } if (dodag->parents) { diff --git a/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h b/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h index a9c6c8188926..1e74d33db2a0 100644 --- a/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h +++ b/sys/net/gnrc/routing/rpl/gnrc_rpl_internal/globals.h @@ -45,6 +45,10 @@ extern evtimer_msg_t gnrc_rpl_evtimer; * @brief Message type for DAO transmissions. */ #define GNRC_RPL_MSG_TYPE_DODAG_DAO_TX (0x0906) +/** + * @brief Message type for floating DODAG timeouts. + */ +#define GNRC_RPL_MSG_TYPE_DODAG_FLOAT_TIMEOUT (0x0907) /** @} */ /**