From 09d26f8060bfd2cf294f7eb066750f4e57051f92 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Wed, 3 Jul 2013 19:45:56 +0200 Subject: [PATCH] Make uip-ds6-route use neighbor table. Instead of storing a global list of routing entries that contain both the next hop and the destination, we have a separate list of reachable destination for each neighbor in the global table. --- core/net/rpl/rpl-icmp6.c | 11 ++- core/net/rpl/rpl.c | 41 ++++----- core/net/tcpip.c | 2 +- core/net/uip-ds6-route.c | 183 +++++++++++++++++++++++++++------------ core/net/uip-ds6-route.h | 15 ++-- 5 files changed, 165 insertions(+), 87 deletions(-) diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 265f7c53f90..711617ae059 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -243,6 +243,13 @@ dio_input(void) PRINTF(", "); PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); PRINTF("\n"); + } else { + PRINTF("RPL: Out of Memory, dropping DIO from "); + PRINT6ADDR(&from); + PRINTF(", "); + PRINTLLADDR((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER)); + PRINTF("\n"); + return; } } else { PRINTF("RPL: Neighbor already in neighbor cache\n"); @@ -657,11 +664,11 @@ dao_input(void) if(lifetime == RPL_ZERO_LIFETIME) { /* No-Path DAO received; invoke the route purging routine. */ - if(rep != NULL && rep->state.saved_lifetime == 0 && rep->length == prefixlen && uip_ipaddr_cmp(&rep->nexthop, &dao_sender_addr)) { + if(rep != NULL && rep->state.nopath_received == 0 && rep->length == prefixlen && uip_ipaddr_cmp(&rep->nexthop, &dao_sender_addr)) { PRINTF("RPL: Setting expiration timer for prefix "); PRINT6ADDR(&prefix); PRINTF("\n"); - rep->state.saved_lifetime = rep->state.lifetime; + rep->state.nopath_received = 1; rep->state.lifetime = DAO_EXPIRATION_TIMEOUT; } return; diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index a5cabef917e..b12c869be90 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -67,7 +67,7 @@ rpl_purge_routes(void) rpl_dag_t *dag; /* First pass, decrement lifetime */ - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); while(r != NULL) { if(r->state.lifetime >= 1) { @@ -78,11 +78,11 @@ rpl_purge_routes(void) */ r->state.lifetime--; } - r = list_item_next(r); + r = uip_ds6_route_next(r); } /* Second pass, remove dead routes */ - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); while(r != NULL) { if(r->state.lifetime < 1) { @@ -90,7 +90,7 @@ rpl_purge_routes(void) * thus we want to keep them. Hence < and not <= */ uip_ipaddr_copy(&prefix, &r->ipaddr); uip_ds6_route_rm(r); - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); PRINTF("No more routes to "); PRINT6ADDR(&prefix); dag = default_instance->current_dag; @@ -103,7 +103,7 @@ rpl_purge_routes(void) } PRINTF("\n"); } else { - r = list_item_next(r); + r = uip_ds6_route_next(r); } } } @@ -113,14 +113,14 @@ rpl_remove_routes(rpl_dag_t *dag) { uip_ds6_route_t *r; - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); while(r != NULL) { if(r->state.dag == dag) { uip_ds6_route_rm(r); - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); } else { - r = list_item_next(r); + r = uip_ds6_route_next(r); } } } @@ -130,15 +130,15 @@ rpl_remove_routes_by_nexthop(uip_ipaddr_t *nexthop, rpl_dag_t *dag) { uip_ds6_route_t *r; - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); while(r != NULL) { - if(uip_ipaddr_cmp(&r->nexthop, nexthop) && + if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), nexthop) && r->state.dag == dag) { uip_ds6_route_rm(r); - r = uip_ds6_route_list_head(); + r = uip_ds6_route_head(); } else { - r = list_item_next(r); + r = uip_ds6_route_next(r); } } ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); @@ -150,20 +150,11 @@ rpl_add_route(rpl_dag_t *dag, uip_ipaddr_t *prefix, int prefix_len, { uip_ds6_route_t *rep; - rep = uip_ds6_route_lookup(prefix); - if(rep == NULL) { - if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop, 0)) == NULL) { - PRINTF("RPL: No space for more route entries\n"); - return NULL; - } - } else { - PRINTF("RPL: Updated the next hop for prefix "); - PRINT6ADDR(prefix); - PRINTF(" to "); - PRINT6ADDR(next_hop); - PRINTF("\n"); - uip_ipaddr_copy(&rep->nexthop, next_hop); + if((rep = uip_ds6_route_add(prefix, prefix_len, next_hop)) == NULL) { + PRINTF("RPL: No space for more route entries\n"); + return NULL; } + rep->state.dag = dag; rep->state.lifetime = RPL_LIFETIME(dag->instance, dag->instance->default_lifetime); rep->state.learned_from = RPL_ROUTE_FROM_INTERNAL; diff --git a/core/net/tcpip.c b/core/net/tcpip.c index 81a2f2e609a..cf22a0556b3 100644 --- a/core/net/tcpip.c +++ b/core/net/tcpip.c @@ -587,7 +587,7 @@ tcpip_ipv6_output(void) return; } } else { - nexthop = &locrt->nexthop; + nexthop = uip_ds6_route_nexthop(locrt); } if(nexthop != NULL) { PRINTF("tcpip_ipv6_output: next hop "); diff --git a/core/net/uip-ds6-route.c b/core/net/uip-ds6-route.c index 0ba45a03e15..e5c6faaa340 100644 --- a/core/net/uip-ds6-route.c +++ b/core/net/uip-ds6-route.c @@ -34,12 +34,15 @@ #include "lib/list.h" #include "lib/memb.h" +#include "net/neighbor-table.h" #if UIP_CONF_IPV6 #include -LIST(routelist); +void uip_ds6_route_rm_routelist(list_t nbr_table_get_from_lladdr); + +NEIGHBOR_TABLE(uip_ds6_route_t *, nbr_routes); MEMB(routememb, uip_ds6_route_t, UIP_DS6_ROUTE_NB); LIST(defaultrouterlist); @@ -49,6 +52,8 @@ MEMB(defaultroutermemb, uip_ds6_defrt_t, UIP_DS6_DEFRT_NB); LIST(notificationlist); #endif +static int num_routes = 0; + #undef DEBUG #define DEBUG DEBUG_NONE #include "net/uip-debug.h" @@ -68,7 +73,7 @@ call_route_callback(int event, uip_ipaddr_t *route, event == UIP_DS6_NOTIFICATION_DEFRT_RM) { num = list_length(defaultrouterlist); } else { - num = list_length(routelist); + num = num_routes; } n->callback(event, route, nexthop, num); } @@ -95,7 +100,7 @@ void uip_ds6_route_init(void) { memb_init(&routememb); - list_init(routelist); + nbr_table_register(nbr_routes, (remove_callback_func *)uip_ds6_route_rm_routelist); memb_init(&defaultroutermemb); list_init(defaultrouterlist); @@ -105,16 +110,59 @@ uip_ds6_route_init(void) #endif } /*---------------------------------------------------------------------------*/ +static uip_lladdr_t * +uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route) +{ + if(route != NULL) { + return (uip_lladdr_t *)nbr_table_get_lladdr(nbr_routes, route->route_list); + } else { + return NULL; + } +} +/*---------------------------------------------------------------------------*/ +uip_ipaddr_t * +uip_ds6_route_nexthop(uip_ds6_route_t *route) +{ + if(route != NULL) { + return uip_ds6_nbr_ipaddr_from_lladdr(uip_ds6_route_nexthop_lladdr(route)); + } else { + return NULL; + } +} +/*---------------------------------------------------------------------------*/ uip_ds6_route_t * -uip_ds6_route_list_head(void) +uip_ds6_route_head(void) { - return list_head(routelist); + list_t nbr_route_list = nbr_table_head(nbr_routes); + if(nbr_route_list != NULL) { + return list_head((list_t)nbr_route_list); + } else { + return NULL; + } +} +/*---------------------------------------------------------------------------*/ +uip_ds6_route_t * +uip_ds6_route_next(uip_ds6_route_t *r) +{ + if(r != NULL) { + uip_ds6_route_t *n = list_item_next(r); + if(n != NULL) { + return n; + } else { + list_t nbr_route_list = nbr_table_next(nbr_routes, r->route_list); + if(nbr_route_list != NULL) { + return list_head((list_t)nbr_route_list); + } + } + } + + return NULL; } /*---------------------------------------------------------------------------*/ int uip_ds6_route_num_routes(void) { - return list_length(routelist); + return num_routes; } /*---------------------------------------------------------------------------*/ uip_ds6_route_t * @@ -131,22 +179,21 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr) found_route = NULL; longestmatch = 0; - for(r = list_head(routelist); + for(r = uip_ds6_route_head(); r != NULL; - r = list_item_next(r)) { + r = uip_ds6_route_next(r)) { if(r->length >= longestmatch && uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) { longestmatch = r->length; found_route = r; } - } if(found_route != NULL) { - PRINTF("uip-ds6-route: Found route:"); + PRINTF("uip-ds6-route: Found route: "); PRINT6ADDR(addr); PRINTF(" via "); - PRINT6ADDR(&found_route->nexthop); + PRINT6ADDR(uip_ds6_route_nexthop(found_route)); PRINTF("\n"); } else { PRINTF("uip-ds6-route: No route found\n"); @@ -157,9 +204,22 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr) /*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, - uip_ipaddr_t *nexthop, uint8_t metric) + uip_ipaddr_t *nexthop) { uip_ds6_route_t *r; + list_t nbr_route_list; + + /* Get link-layer address of next hop, make sure it is in neighbor table */ + uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop); + if(nexthop_lladdr == NULL) { + PRINTF("uip_ds6_route_add: neighbor link-local address unknown "); + PRINT6ADDR(ipaddr); + PRINTF("\n"); + return NULL; + } + + /* Get routing entry list of this neighbor */ + nbr_route_list = nbr_table_get_from_lladdr(nbr_routes, (rimeaddr_t *)nexthop_lladdr); /* First make sure that we don't add a route twice. If we find an existing route for our destination, we'll just update the old @@ -170,6 +230,18 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, PRINT6ADDR(ipaddr); PRINTF("\n"); } else { + /* If there is no routing entry, create one */ + if(nbr_route_list == NULL) { + nbr_route_list = nbr_table_add_lladdr(nbr_routes, (rimeaddr_t *)nexthop_lladdr); + if(nbr_route_list == NULL) { + PRINTF("uip_ds6_route_add: could not allocate memory (route list) for new route to "); + PRINT6ADDR(ipaddr); + PRINTF(", dropping it\n"); + return NULL; + } + list_init((list_t)nbr_route_list); + } + /* Allocate a routing entry and add the route to the list */ r = memb_alloc(&routememb); if(r == NULL) { @@ -178,15 +250,16 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, PRINTF(", dropping it\n"); return NULL; } - list_add(routelist, r); + /* Add the route to this neighbor */ + list_add((list_t)nbr_route_list, r); + num_routes++; - PRINTF("uip_ds6_route_add num %d\n", list_length(routelist)); + PRINTF("uip_ds6_route_add num %d\n", num_routes); } + r->route_list = nbr_route_list; uip_ipaddr_copy(&(r->ipaddr), ipaddr); r->length = length; - uip_ipaddr_copy(&(r->nexthop), nexthop); - r->metric = metric; #ifdef UIP_DS6_ROUTE_STATE_TYPE memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE)); @@ -210,59 +283,63 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, void uip_ds6_route_rm(uip_ds6_route_t *route) { - uip_ds6_route_t *r; - /* Make sure that the route is in the list before removing it. */ - for(r = list_head(routelist); - r != NULL; - r = list_item_next(r)) { - if(r == route) { - list_remove(routelist, route); - memb_free(&routememb, route); + if(route != NULL && route->route_list != NULL) { - PRINTF("uip_ds6_route_rm num %d\n", list_length(routelist)); + if(list_head((list_t)route->route_list) == NULL) { + /* If this was the only route using this neighbor, remove the neibhor from the table */ + nbr_table_remove(nbr_routes, route->route_list); + } + list_remove((list_t)route->route_list, route); + memb_free(&routememb, route); + + num_routes--; + + PRINTF("uip_ds6_route_rm num %d\n", num_routes); #if UIP_DS6_NOTIFICATIONS - call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM, - &route->ipaddr, &route->nexthop); + call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM, + &route->ipaddr, uip_ds6_route_nexthop(route)); #endif #if (DEBUG & DEBUG_ANNOTATE) == DEBUG_ANNOTATE - /* we need to check if this was the last route towards "nexthop" */ - /* if so - remove that link (annotation) */ - for(r = list_head(routelist); - r != NULL; - r = list_item_next(r)) { - if(uip_ipaddr_cmp(&r->nexthop, &route->nexthop)) { - /* we found another link using the specific nexthop, so keep the #L */ - return; - } + /* we need to check if this was the last route towards "nexthop" */ + /* if so - remove that link (annotation) */ + for(r = uip_ds6_route_head(); + r != NULL; + r = uip_ds6_route_next(r)) { + if(uip_ipaddr_cmp(uip_ds6_route_nexthop(r), uip_ds6_route_nexthop(route))) { + /* we found another link using the specific nexthop, so keep the #L */ + return; } - ANNOTATE("#L %u 0\n", route->nexthop.u8[sizeof(uip_ipaddr_t) - 1]); -#endif - return; } + ANNOTATE("#L %u 0\n", uip_ds6_route_nexthop(route)->u8[sizeof(uip_ipaddr_t) - 1]); +#endif } + return; } /*---------------------------------------------------------------------------*/ void -uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop) +uip_ds6_route_rm_routelist(list_t nbr_route_list) { - uip_ds6_route_t *r; - - r = list_head(routelist); - while(r != NULL) { - if(uip_ipaddr_cmp(&r->nexthop, nexthop)) { - list_remove(routelist, r); -#if UIP_DS6_NOTIFICATIONS - call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM, - &r->ipaddr, &r->nexthop); -#endif - r = list_head(routelist); - } else { - r = list_item_next(r); + if(nbr_route_list != NULL) { + uip_ds6_route_t *r; + r = list_head((list_t)nbr_route_list); + while(r != NULL) { + uip_ds6_route_rm(r); + r = list_head((list_t)nbr_route_list); } + nbr_table_remove(nbr_routes, nbr_route_list); } } /*---------------------------------------------------------------------------*/ +void +uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop) +{ + /* Get routing entry list of this neighbor */ + uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop); + list_t nbr_route_list = nbr_table_get_from_lladdr(nbr_routes, (rimeaddr_t *)nexthop_lladdr); + uip_ds6_route_rm_routelist(nbr_route_list); +} +/*---------------------------------------------------------------------------*/ uip_ds6_defrt_t * uip_ds6_defrt_add(uip_ipaddr_t *ipaddr, unsigned long interval) { diff --git a/core/net/uip-ds6-route.h b/core/net/uip-ds6-route.h index 3b8bc15b7e5..ba672adf1df 100644 --- a/core/net/uip-ds6-route.h +++ b/core/net/uip-ds6-route.h @@ -32,6 +32,8 @@ #ifndef UIP_DS6_ROUTE_H #define UIP_DS6_ROUTE_H +#include "lib/list.h" + void uip_ds6_route_init(void); #ifndef UIP_CONF_UIP_DS6_NOTIFICATIONS @@ -84,9 +86,9 @@ void uip_ds6_notification_rm(struct uip_ds6_notification *n); /* Needed for the extended route entry state when using ContikiRPL */ typedef struct rpl_route_entry { uint32_t lifetime; - uint32_t saved_lifetime; void *dag; uint8_t learned_from; + uint8_t nopath_received; } rpl_route_entry_t; #endif /* UIP_DS6_ROUTE_STATE_TYPE */ @@ -95,13 +97,12 @@ typedef struct rpl_route_entry { /** \brief An entry in the routing table */ typedef struct uip_ds6_route { struct uip_ds6_route *next; + list_t route_list; /* The list the routing entry belongs to. */ uip_ipaddr_t ipaddr; - uip_ipaddr_t nexthop; - uint8_t length; - uint8_t metric; #ifdef UIP_DS6_ROUTE_STATE_TYPE UIP_DS6_ROUTE_STATE_TYPE state; #endif + uint8_t length; } uip_ds6_route_t; @@ -130,12 +131,14 @@ void uip_ds6_defrt_periodic(void); /** @{ */ uip_ds6_route_t *uip_ds6_route_lookup(uip_ipaddr_t *destipaddr); uip_ds6_route_t *uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, - uip_ipaddr_t *next_hop, uint8_t metric); + uip_ipaddr_t *next_hop); void uip_ds6_route_rm(uip_ds6_route_t *route); void uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop); +uip_ipaddr_t *uip_ds6_route_nexthop(uip_ds6_route_t *); int uip_ds6_route_num_routes(void); -uip_ds6_route_t *uip_ds6_route_list_head(void); +uip_ds6_route_t *uip_ds6_route_head(void); +uip_ds6_route_t *uip_ds6_route_next(uip_ds6_route_t *); /** @} */