Contiki-NG
uip-sr.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016, Inria.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 */
31
32/**
33 * \addtogroup uip
34 * @{
35 *
36 * \file
37 * Source routing support
38 *
39 * \author Simon Duquennoy <simon.duquennoy@inria.fr>
40 */
41
42#include "contiki.h"
43#include "net/ipv6/uip-sr.h"
44#include "net/ipv6/uiplib.h"
45#include "net/routing/routing.h"
46#include "lib/list.h"
47#include "lib/memb.h"
48
49/* Log configuration */
50#include "sys/log.h"
51#define LOG_MODULE "IPv6 SR"
52#define LOG_LEVEL LOG_LEVEL_IPV6
53
54/* Total number of nodes */
55static int num_nodes;
56
57/* Every known node in the network */
58LIST(nodelist);
59MEMB(nodememb, uip_sr_node_t, UIP_SR_LINK_NUM);
60
61/*---------------------------------------------------------------------------*/
62int
64{
65 return num_nodes;
66}
67/*---------------------------------------------------------------------------*/
68static int
69node_matches_address(const void *graph, const uip_sr_node_t *node,
70 const uip_ipaddr_t *addr)
71{
72 if(node == NULL || addr == NULL || graph != node->graph) {
73 return 0;
74 } else {
75 uip_ipaddr_t node_ipaddr;
76 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_ipaddr, node);
77 return uip_ipaddr_cmp(&node_ipaddr, addr);
78 }
79}
80/*---------------------------------------------------------------------------*/
82uip_sr_get_node(const void *graph, const uip_ipaddr_t *addr)
83{
85 for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
86 /* Compare prefix and node identifier */
87 if(node_matches_address(graph, l, addr)) {
88 return l;
89 }
90 }
91 return NULL;
92}
93/*---------------------------------------------------------------------------*/
94int
95uip_sr_is_addr_reachable(const void *graph, const uip_ipaddr_t *addr)
96{
97 int max_depth = UIP_SR_LINK_NUM;
98 uip_ipaddr_t root_ipaddr;
99 uip_sr_node_t *node;
100 uip_sr_node_t *root_node;
101
102 NETSTACK_ROUTING.get_root_ipaddr(&root_ipaddr);
103 node = uip_sr_get_node(graph, addr);
104 root_node = uip_sr_get_node(graph, &root_ipaddr);
105
106 while(node != NULL && node != root_node && max_depth > 0) {
107 node = node->parent;
108 max_depth--;
109 }
110 return node != NULL && node == root_node;
111}
112/*---------------------------------------------------------------------------*/
113void
114uip_sr_expire_parent(const void *graph, const uip_ipaddr_t *child,
115 const uip_ipaddr_t *parent)
116{
117 uip_sr_node_t *l = uip_sr_get_node(graph, child);
118 /* Check if parent matches */
119 if(l != NULL && node_matches_address(graph, l->parent, parent)) {
120 if(l->lifetime > UIP_SR_REMOVAL_DELAY) {
121 l->lifetime = UIP_SR_REMOVAL_DELAY;
122 }
123 }
124}
125/*---------------------------------------------------------------------------*/
127uip_sr_update_node(void *graph, const uip_ipaddr_t *child,
128 const uip_ipaddr_t *parent, uint32_t lifetime)
129{
130 uip_sr_node_t *child_node = uip_sr_get_node(graph, child);
131 uip_sr_node_t *parent_node = uip_sr_get_node(graph, parent);
132 uip_sr_node_t *old_parent_node;
133
134 if(parent != NULL) {
135 /* No node for the parent, add one with infinite lifetime */
136 if(parent_node == NULL) {
137 parent_node = uip_sr_update_node(graph, parent, NULL, UIP_SR_INFINITE_LIFETIME);
138 if(parent_node == NULL) {
139 LOG_ERR("NS: no space left for root node!\n");
140 return NULL;
141 }
142 }
143 }
144
145 /* No node for this child, add one */
146 if(child_node == NULL) {
147 child_node = memb_alloc(&nodememb);
148 /* No space left, abort */
149 if(child_node == NULL) {
150 LOG_ERR("NS: no space left for child ");
151 LOG_ERR_6ADDR(child);
152 LOG_ERR_("\n");
153 return NULL;
154 }
155 child_node->parent = NULL;
156 list_add(nodelist, child_node);
157 num_nodes++;
158 }
159
160 /* Initialize node */
161 child_node->graph = graph;
162 child_node->lifetime = lifetime;
163 memcpy(child_node->link_identifier, ((const unsigned char *)child) + 8, 8);
164
165 /* Is the node reachable before the update? */
166 if(uip_sr_is_addr_reachable(graph, child)) {
167 old_parent_node = child_node->parent;
168 /* Update node */
169 child_node->parent = parent_node;
170 /* Has the node become unreachable? May happen if we create a loop. */
171 if(!uip_sr_is_addr_reachable(graph, child)) {
172 /* The new parent makes the node unreachable, restore old parent.
173 * We will take the update next time, with chances we know more of
174 * the topology and the loop is gone. */
175 child_node->parent = old_parent_node;
176 }
177 } else {
178 child_node->parent = parent_node;
179 }
180
181 LOG_INFO("NS: updating link, child ");
182 LOG_INFO_6ADDR(child);
183 LOG_INFO_(", parent ");
184 LOG_INFO_6ADDR(parent);
185 LOG_INFO_(", lifetime %u, num_nodes %u\n", (unsigned)lifetime, num_nodes);
186
187 return child_node;
188}
189/*---------------------------------------------------------------------------*/
190void
192{
193 num_nodes = 0;
194 memb_init(&nodememb);
195 list_init(nodelist);
196}
197/*---------------------------------------------------------------------------*/
200{
201 return list_head(nodelist);
202}
203/*---------------------------------------------------------------------------*/
206{
207 return list_item_next(item);
208}
209/*---------------------------------------------------------------------------*/
210void
211uip_sr_periodic(unsigned seconds)
212{
213 uip_sr_node_t *l;
214 uip_sr_node_t *next;
215
216 /* First pass, for all expired nodes, deallocate them iff no child points to them */
217 for(l = list_head(nodelist); l != NULL; l = next) {
218 next = list_item_next(l);
219 if(l->lifetime == 0) {
220 uip_sr_node_t *l2;
221 int can_be_removed = 1;
222 for(l2 = list_head(nodelist); l2 != NULL; l2 = list_item_next(l2)) {
223 if(l2->parent == l) {
224 can_be_removed = 0;
225 break;
226 }
227 }
228 if(can_be_removed) {
229 /* No child found, deallocate node */
230 if(LOG_INFO_ENABLED) {
231 uip_ipaddr_t node_addr;
232 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, l);
233 LOG_INFO("NS: removing expired node ");
234 LOG_INFO_6ADDR(&node_addr);
235 LOG_INFO_("\n");
236 }
237 list_remove(nodelist, l);
238 memb_free(&nodememb, l);
239 num_nodes--;
240 }
241 } else if(l->lifetime != UIP_SR_INFINITE_LIFETIME) {
242 l->lifetime = l->lifetime > seconds ? l->lifetime - seconds : 0;
243 }
244 }
245}
246/*---------------------------------------------------------------------------*/
247void
249{
250 uip_sr_node_t *l;
251 uip_sr_node_t *next;
252 for(l = list_head(nodelist); l != NULL; l = next) {
253 next = list_item_next(l);
254 list_remove(nodelist, l);
255 memb_free(&nodememb, l);
256 num_nodes--;
257 }
258}
259/*---------------------------------------------------------------------------*/
260int
261uip_sr_link_snprint(char *buf, int buflen, const uip_sr_node_t *link)
262{
263 int index = 0;
264 uip_ipaddr_t child_ipaddr;
265 uip_ipaddr_t parent_ipaddr;
266
267 NETSTACK_ROUTING.get_sr_node_ipaddr(&child_ipaddr, link);
268 NETSTACK_ROUTING.get_sr_node_ipaddr(&parent_ipaddr, link->parent);
269
270 if(LOG_WITH_COMPACT_ADDR) {
271 index += log_6addr_compact_snprint(buf+index, buflen-index, &child_ipaddr);
272 } else {
273 index += uiplib_ipaddr_snprint(buf+index, buflen-index, &child_ipaddr);
274 }
275 if(index >= buflen) {
276 return index;
277 }
278
279 if(link->parent == NULL) {
280 index += snprintf(buf+index, buflen-index, " (DODAG root)");
281 if(index >= buflen) {
282 return index;
283 }
284 } else {
285 index += snprintf(buf+index, buflen-index, " to ");
286 if(index >= buflen) {
287 return index;
288 }
289 if(LOG_WITH_COMPACT_ADDR) {
290 index += log_6addr_compact_snprint(buf+index, buflen-index, &parent_ipaddr);
291 } else {
292 index += uiplib_ipaddr_snprint(buf+index, buflen-index, &parent_ipaddr);
293 }
294 if(index >= buflen) {
295 return index;
296 }
297 }
298 if(link->lifetime != UIP_SR_INFINITE_LIFETIME) {
299 index += snprintf(buf+index, buflen-index,
300 " (lifetime: %lu seconds)", (unsigned long)link->lifetime);
301 if(index >= buflen) {
302 return index;
303 }
304 } else {
305 index += snprintf(buf+index, buflen-index, " (lifetime: infinite)");
306 if(index >= buflen) {
307 return index;
308 }
309 }
310 return index;
311}
312/** @} */
void list_init(list_t list)
Initialize a list.
Definition: list.c:57
#define LIST(name)
Declare a linked list.
Definition: list.h:89
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:89
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition: list.c:152
void * list_item_next(const void *item)
Get the next item following this item.
Definition: list.c:203
void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition: list.c:63
int log_6addr_compact_snprint(char *buf, size_t size, const uip_ipaddr_t *ipaddr)
Write at most size - 1 characters of the IP address to the output string, in a compact representation...
Definition: log.c:97
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:91
int uiplib_ipaddr_snprint(char *buf, size_t size, const uip_ipaddr_t *addr)
Write at most size - 1 characters of the IP address to the output string.
Definition: uiplib.c:166
uip_sr_node_t * uip_sr_get_node(const void *graph, const uip_ipaddr_t *addr)
Looks up for a source routing node from its IPv6 global address.
Definition: uip-sr.c:82
void uip_sr_expire_parent(const void *graph, const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
Expires a given child-parent link.
Definition: uip-sr.c:114
void uip_sr_init(void)
Initialize this module.
Definition: uip-sr.c:191
void uip_sr_free_all(void)
Deallocate all neighbors.
Definition: uip-sr.c:248
int uip_sr_is_addr_reachable(const void *graph, const uip_ipaddr_t *addr)
Telle whether an address is reachable, i.e.
Definition: uip-sr.c:95
uip_sr_node_t * uip_sr_node_head(void)
Returns the head of the non-storing node list.
Definition: uip-sr.c:199
int uip_sr_link_snprint(char *buf, int buflen, const uip_sr_node_t *link)
Print a textual description of a source routing link.
Definition: uip-sr.c:261
void uip_sr_periodic(unsigned seconds)
A function called periodically.
Definition: uip-sr.c:211
int uip_sr_num_nodes(void)
Tells how many nodes are currently stored in the graph.
Definition: uip-sr.c:63
uip_sr_node_t * uip_sr_update_node(void *graph, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
Updates a child-parent link.
Definition: uip-sr.c:127
uip_sr_node_t * uip_sr_node_next(const uip_sr_node_t *item)
Returns the next element of the non-storing node list.
Definition: uip-sr.c:205
Linked list manipulation routines.
Header file for the logging system.
Memory block allocation routines.
Routing driver header file.
int(* get_root_ipaddr)(uip_ipaddr_t *ipaddr)
Returns the IPv6 address of the network root, if any.
Definition: routing.h:89
int(* get_sr_node_ipaddr)(uip_ipaddr_t *ipaddr, const uip_sr_node_t *node)
Returns the global IPv6 address of a source routing node.
Definition: routing.h:97
A node in a source routing graph, stored at the root and representing all child-parent relationship.
Definition: uip-sr.h:92
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
Source routing support.
Header file for the IP address manipulation library.