diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index 961f26abd9820..ab073db0367a5 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -39,6 +39,10 @@ #include #endif +#if defined(CONFIG_NET_RPL) +#include "rpl.h" +#endif + #include "net_shell.h" #include "net_stats.h" @@ -265,17 +269,12 @@ static void route_cb(struct net_route_entry *entry, void *user_data) return; } - printk("IPv6 Route %p for interface %p\n", entry, iface); - printk("==============================================\n"); - printk("IPv6 prefix : %s/%d\n", net_sprint_ipv6_addr(&entry->addr), entry->prefix_len); count = 0; - printk("Next hops :\n"); - SYS_SLIST_FOR_EACH_CONTAINER(&entry->nexthop, nexthop_route, node) { struct net_linkaddr_storage *lladdr; @@ -307,6 +306,9 @@ static void iface_per_route_cb(struct net_if *iface, void *user_data) { ARG_UNUSED(user_data); + printk("IPv6 routes for interface %p\n", iface); + printk("====================================\n"); + net_route_foreach(route_cb, iface); } #endif /* CONFIG_NET_ROUTE */ @@ -1391,8 +1393,14 @@ static void nbr_cb(struct net_nbr *nbr, void *user_data) int *count = user_data; if (*count == 0) { + char *padding = ""; + + if (net_nbr_get_lladdr(nbr->idx)->len == 8) { + padding = " "; + } + printk(" Neighbor Flags Interface State\t" - "Remain\tLink Address\n"); + "Remain\tLink %sAddress\n", padding); } (*count)++; @@ -1648,6 +1656,184 @@ int net_shell_cmd_route(int argc, char *argv[]) return 0; } +#if defined(CONFIG_NET_RPL) +static int power(int base, unsigned int exp) +{ + int i, result = 1; + + for (i = 0; i < exp; i++) { + result *= base; + } + + return result; +} + +static void rpl_parent(struct net_rpl_parent *parent, void *user_data) +{ + int *count = user_data; + + if (*count == 0) { + printk(" Parent Last TX Rank DTSN Flags\tAddress\n"); + } + + (*count)++; + + if (parent->dag) { + printk("[%2d] %p %10d %2d %d 0x%08x %s\n", + *count, parent, parent->last_tx_time, parent->rank, + parent->dtsn, parent->flags, + net_sprint_ipv6_addr(&parent->dag->dag_id)); + } +} + +#endif /* CONFIG_NET_RPL */ + +int net_shell_cmd_rpl(int argc, char *argv[]) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#if defined(CONFIG_NET_RPL) + struct net_rpl_instance *instance; + enum net_rpl_mode mode; + int i, count; + + mode = net_rpl_get_mode(); + printk("RPL Configuration\n"); + printk("=================\n"); + printk("RPL mode : %s\n", + mode == NET_RPL_MODE_MESH ? "mesh" : + (mode == NET_RPL_MODE_FEATHER ? "feather" : + (mode == NET_RPL_MODE_LEAF ? "leaf" : ""))); + printk("Used objective function : %s\n", + IS_ENABLED(CONFIG_NET_RPL_MRHOF) ? "MRHOF" : + (IS_ENABLED(CONFIG_NET_RPL_OF0) ? "OF0" : "")); + printk("Used routing metric : %s\n", + IS_ENABLED(CONFIG_NET_RPL_MC_NONE) ? "none" : + (IS_ENABLED(CONFIG_NET_RPL_MC_ETX) ? "estimated num of TX" : + (IS_ENABLED(CONFIG_NET_RPL_MC_ENERGY) ? "energy based" : + ""))); + printk("Mode of operation (MOP) : %s\n", + IS_ENABLED(CONFIG_NET_RPL_MOP2) ? "Storing, no mcast (MOP2)" : + (IS_ENABLED(CONFIG_NET_RPL_MOP3) ? "Storing (MOP3)" : + "")); + printk("Send probes to nodes : %s\n", + IS_ENABLED(CONFIG_NET_RPL_PROBING) ? "enabled" : "disabled"); + printk("Max instances : %d\n", + CONFIG_NET_RPL_MAX_INSTANCES); + printk("Max DAG / instance : %d\n", + CONFIG_NET_RPL_MAX_DAG_PER_INSTANCE); + + printk("Min hop rank increment : %d\n", + CONFIG_NET_RPL_MIN_HOP_RANK_INC); + printk("Initial link metric : %d\n", + CONFIG_NET_RPL_INIT_LINK_METRIC); + printk("RPL preference value : %d\n", + CONFIG_NET_RPL_PREFERENCE); + printk("DAG grounded by default : %s\n", + IS_ENABLED(CONFIG_NET_RPL_GROUNDED) ? "yes" : "no"); + printk("Default instance id : %d (0x%02x)\n", + CONFIG_NET_RPL_DEFAULT_INSTANCE, + CONFIG_NET_RPL_DEFAULT_INSTANCE); + printk("Insert Hop-by-hop option : %s\n", + IS_ENABLED(CONFIG_NET_RPL_INSERT_HBH_OPTION) ? "yes" : "no"); + + printk("Specify DAG when sending DAO : %s\n", + IS_ENABLED(CONFIG_NET_RPL_DAO_SPECIFY_DAG) ? "yes" : "no"); + printk("DIO min interval : %d (%d ms)\n", + CONFIG_NET_RPL_DIO_INTERVAL_MIN, + power(2, CONFIG_NET_RPL_DIO_INTERVAL_MIN)); + printk("DIO doublings interval : %d\n", + CONFIG_NET_RPL_DIO_INTERVAL_DOUBLINGS); + printk("DIO redundancy value : %d\n", + CONFIG_NET_RPL_DIO_REDUNDANCY); + + printk("DAO sending timer value : %d sec\n", + CONFIG_NET_RPL_DAO_TIMER); + printk("DAO max retransmissions : %d\n", + CONFIG_NET_RPL_DAO_MAX_RETRANSMISSIONS); + printk("Node expecting DAO ack : %s\n", + IS_ENABLED(CONFIG_NET_RPL_DAO_ACK) ? "yes" : "no"); + + printk("Send DIS periodically : %s\n", + IS_ENABLED(CONFIG_NET_RPL_DIS_SEND) ? "yes" : "no"); +#if defined(CONFIG_NET_RPL_DIS_SEND) + printk("DIS interval : %d sec\n", + CONFIG_NET_RPL_DIS_INTERVAL); +#endif + + printk("Default route lifetime unit : %d sec\n", + CONFIG_NET_RPL_DEFAULT_LIFETIME_UNIT); + printk("Default route lifetime : %d\n", + CONFIG_NET_RPL_DEFAULT_LIFETIME); +#if defined(CONFIG_NET_RPL_MOP3) + printk("Multicast route lifetime : %d\n", + CONFIG_NET_RPL_MCAST_LIFETIME); +#endif + printk("\nRuntime status\n"); + printk("==============\n"); + + instance = net_rpl_get_default_instance(); + if (!instance) { + printk("No default RPL instance found.\n"); + return 0; + } + + printk("Default instance (id %d) : %p (%s)\n", instance->instance_id, + instance, instance->is_used ? "active" : "disabled"); + + if (instance->default_route) { + printk("Default route : %s\n", + net_sprint_ipv6_addr( + &instance->default_route->address.in6_addr)); + } + +#if defined(CONFIG_NET_STATISTICS_RPL) + printk("DIO statistics : intervals %d sent %d recv %d\n", + instance->dio_intervals, instance->dio_send_pkt, + instance->dio_recv_pkt); +#endif /* CONFIG_NET_STATISTICS_RPL */ + + printk("Instance DAGs :\n"); + for (i = 0, count = 0; i < CONFIG_NET_RPL_MAX_DAG_PER_INSTANCE; i++) { + char prefix[NET_IPV6_ADDR_LEN]; + + if (!instance->dags[i].is_used) { + continue; + } + + snprintk(prefix, sizeof(prefix), "%s", + net_sprint_ipv6_addr( + &instance->dags[i].prefix_info.prefix)); + + printk("[%2d]%s %s prefix %s/%d rank %d/%d ver %d flags %c%c " + "parent %p\n", + ++count, + &instance->dags[i] == instance->current_dag ? "*" : " ", + net_sprint_ipv6_addr(&instance->dags[i].dag_id), + prefix, instance->dags[i].prefix_info.length, + instance->dags[i].rank, instance->dags[i].min_rank, + instance->dags[i].version, + instance->dags[i].is_grounded ? 'G' : 'g', + instance->dags[i].is_joined ? 'J' : 'j', + instance->dags[i].preferred_parent); + } + printk("\n"); + + count = 0; + i = net_rpl_foreach_parent(rpl_parent, &count); + if (i == 0) { + printk("No parents found.\n"); + } + + printk("\n"); +#else + printk("RPL not enabled, set CONFIG_NET_RPL to enable it.\n"); +#endif + + return 0; +} + #if defined(CONFIG_INIT_STACKS) extern K_THREAD_STACK_DEFINE(_main_stack, CONFIG_MAIN_STACK_SIZE); extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE); @@ -2018,6 +2204,7 @@ static struct shell_cmd net_commands[] = { "nbr rm \n\tRemove neighbor from cache" }, { "ping", net_shell_cmd_ping, "\n\tPing a network host" }, { "route", net_shell_cmd_route, "\n\tShow network route" }, + { "rpl", net_shell_cmd_rpl, "\n\tShow RPL mesh routing status" }, { "stacks", net_shell_cmd_stacks, "\n\tShow network stacks information" }, { "stats", net_shell_cmd_stats, "\n\tShow network statistics" }, diff --git a/subsys/net/ip/route.c b/subsys/net/ip/route.c index 48807359dc6e9..b5c82f9405da4 100644 --- a/subsys/net/ip/route.c +++ b/subsys/net/ip/route.c @@ -554,7 +554,9 @@ struct in6_addr *net_route_get_nexthop(struct net_route_entry *route) struct net_route_nexthop *nexthop_route; struct net_ipv6_nbr_data *ipv6_nbr_data; - NET_ASSERT(route); + if (!route) { + return NULL; + } SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route, node) { struct in6_addr *addr; diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index c5b630775319b..d5d942d2ef1df 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -345,7 +345,26 @@ struct in6_addr *net_rpl_get_parent_addr(struct net_if *iface, return net_ipv6_nbr_lookup_by_index(iface, nbr->idx); } -#if defined(CONFIG_NET_DEBUG_RPL) +int net_rpl_foreach_parent(net_rpl_parent_cb_t cb, void *user_data) +{ + int i, ret = 0; + + for (i = 0; i < CONFIG_NET_IPV6_MAX_NEIGHBORS; i++) { + struct net_nbr *nbr = get_nbr(i); + + if (!nbr->ref) { + continue; + } + + cb(nbr_data(nbr), user_data); + + ret++; + } + + return ret; +} + +#if defined(CONFIG_NET_DEBUG_RPL) && (CONFIG_SYS_LOG_NET_LEVEL > 3) static void net_rpl_print_neighbors(void) { if (rpl_default_instance && rpl_default_instance->current_dag) { @@ -1285,7 +1304,6 @@ static void net_rpl_reset_dio_timer(struct net_rpl_instance *instance) net_stats_update_rpl_resets(); } -static struct net_rpl_dag *net_rpl_set_root_with_version(struct net_if *iface, u8_t instance_id, struct in6_addr *dag_id, @@ -1460,7 +1478,7 @@ static void net_rpl_nullify_parent(struct net_if *iface, struct net_rpl_parent *parent) { struct net_rpl_dag *dag = parent->dag; -#if defined(CONFIG_NET_DEBUG_RPL) +#if defined(CONFIG_NET_DEBUG_RPL) && (CONFIG_SYS_LOG_NET_LEVEL > 3) struct in6_addr *addr = net_rpl_get_parent_addr(iface, parent); #endif @@ -2044,7 +2062,7 @@ static bool net_rpl_process_parent_event(struct net_if *iface, return ret; } -static bool net_rpl_repair_root(u8_t instance_id) +bool net_rpl_repair_root(u8_t instance_id) { struct net_rpl_instance *instance; @@ -3287,13 +3305,30 @@ static int forwarding_dao(struct net_rpl_instance *instance, return r; } +static bool is_root(struct net_rpl_instance *instance) +{ + if (!(instance && instance->current_dag)) { + return false; + } + + if (instance->current_dag->preferred_parent) { + return false; + } + + if (instance->current_dag->rank != NET_RPL_ROOT_RANK(instance)) { + return false; + } + + return true; +} + static enum net_verdict handle_dao(struct net_pkt *pkt) { struct in6_addr *dao_sender = &NET_IPV6_HDR(pkt)->src; + struct net_rpl_route_entry *extra = NULL; struct net_rpl_parent *parent = NULL; enum net_rpl_route_source learned_from; struct net_rpl_instance *instance; - struct net_rpl_route_entry *extra; struct net_route_entry *route; struct net_rpl_dag *dag; struct net_buf *frag; @@ -3458,25 +3493,17 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) } #endif - route = net_route_lookup(net_pkt_iface(pkt), &addr); - if (!route) { - NET_DBG("No route to %s for iface %p", - net_sprint_ipv6_addr(&addr), net_pkt_iface(pkt)); - return NET_DROP; - } - - nbr = net_route_get_nbr(route); - if (!nbr) { - return NET_DROP; - } - - extra = net_nbr_extra_data(nbr); - if (lifetime == NET_RPL_ZERO_LIFETIME) { struct in6_addr *nexthop; NET_DBG("No-Path DAO received"); + route = net_route_lookup(net_pkt_iface(pkt), &addr); + nbr = net_route_get_nbr(route); + if (nbr) { + extra = net_nbr_extra_data(nbr); + } + nexthop = net_route_get_nexthop(route); /* No-Path DAO received; invoke the route purging routine. */ @@ -3551,6 +3578,7 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) return NET_DROP; } + extra = net_nbr_extra_data(nbr); if (extra) { extra->lifetime = net_rpl_lifetime(instance, lifetime); extra->route_source = learned_from; @@ -3575,6 +3603,22 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) net_pkt_unref(pkt); return NET_OK; } + } else { + if (IS_ENABLED(CONFIG_NET_RPL_DAO_ACK) && + (flags & NET_RPL_DAO_K_FLAG) && + is_root(instance)) { + r = dao_ack_send(&NET_IPV6_HDR(pkt)->dst, + &NET_IPV6_HDR(pkt)->src, + net_pkt_iface(pkt), + instance, sequence, 0); + if (r >= 0) { + NET_DBG("Sending DAO-ACK to %s", + net_sprint_ipv6_addr( + &NET_IPV6_HDR(pkt)->src)); + net_pkt_unref(pkt); + return NET_OK; + } + } } } diff --git a/subsys/net/ip/rpl.h b/subsys/net/ip/rpl.h index cae99881fcbe3..5e7652e8dab6d 100644 --- a/subsys/net/ip/rpl.h +++ b/subsys/net/ip/rpl.h @@ -887,6 +887,21 @@ struct net_rpl_dag *net_rpl_set_root(struct net_if *iface, u8_t instance_id, struct in6_addr *dag_id); +/** + * @brief Set the root DAG with version. + * + * @param iface Network interface to use. + * @param instance Pointer to instance object. + * @param dag_id IPv6 address of the DAG. + * @param version Version number to use. + * + * @return DAG object or NULL if creation failed. + */ +struct net_rpl_dag *net_rpl_set_root_with_version(struct net_if *iface, + u8_t instance_id, + struct in6_addr *dag_id, + u8_t version); + /** * @brief Get first available DAG. * @@ -916,6 +931,13 @@ bool net_rpl_set_prefix(struct net_if *iface, */ void net_rpl_global_repair(struct net_route_entry *route); +/** + * @brief Do global repair for this instance. + * + * @param instance RPL instance id. + */ +bool net_rpl_repair_root(u8_t instance_id); + /** * @brief Update RPL headers in IPv6 packet. * @@ -973,6 +995,20 @@ int net_rpl_revert_header(struct net_pkt *pkt, u16_t offset, u16_t *pos); struct in6_addr *net_rpl_get_parent_addr(struct net_if *iface, struct net_rpl_parent *parent); +typedef void (*net_rpl_parent_cb_t)(struct net_rpl_parent *parent, + void *user_data); + +/** + * @brief Go through all the parents entries and call callback + * for each entry that is in use. + * + * @param cb User supplied callback function to call. + * @param user_data User specified data. + * + * @return Total number of parents found. + */ +int net_rpl_foreach_parent(net_rpl_parent_cb_t cb, void *user_data); + /** * @brief Set the RPL mode (mesh or leaf) of this node. *