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 */
55 static int num_nodes;
56 
57 /* Every known node in the network */
58 LIST(nodelist);
59 MEMB(nodememb, uip_sr_node_t, UIP_SR_LINK_NUM);
60 
61 /*---------------------------------------------------------------------------*/
62 int
64 {
65  return num_nodes;
66 }
67 /*---------------------------------------------------------------------------*/
68 static int
69 node_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 /*---------------------------------------------------------------------------*/
82 uip_sr_get_node(const void *graph, const uip_ipaddr_t *addr)
83 {
84  uip_sr_node_t *l;
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 /*---------------------------------------------------------------------------*/
94 int
95 uip_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 /*---------------------------------------------------------------------------*/
113 void
114 uip_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 /*---------------------------------------------------------------------------*/
127 uip_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 /*---------------------------------------------------------------------------*/
190 void
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 /*---------------------------------------------------------------------------*/
210 void
211 uip_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 /*---------------------------------------------------------------------------*/
247 void
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 /*---------------------------------------------------------------------------*/
260 int
261 uip_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 /** @} */
int uip_sr_num_nodes(void)
Tells how many nodes are currently stored in the graph.
Definition: uip-sr.c:63
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
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
void uip_sr_free_all(void)
Deallocate all neighbors.
Definition: uip-sr.c:248
void uip_sr_init(void)
Initialize this module.
Definition: uip-sr.c:191
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
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
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
Source routing support.
Header file for the IP address manipulation library.
void uip_sr_periodic(unsigned seconds)
A function called periodically.
Definition: uip-sr.c:211
Linked list manipulation routines.
void * list_head(const list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition: list.c:237
uip_sr_node_t * uip_sr_node_head(void)
Returns the head of the non-storing node list.
Definition: uip-sr.c:199
Routing driver header file
Memory block allocation routines.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
void list_init(list_t list)
Initialize a list.
Definition: list.c:65
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
#define LIST(name)
Declare a linked list.
Definition: list.h:89
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
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
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(* get_sr_node_ipaddr)(uip_ipaddr_t *addr, const uip_sr_node_t *node)
Returns the global IPv6 address of a source routing node.
Definition: routing.h:97
int(* get_root_ipaddr)(uip_ipaddr_t *ipaddr)
Returns the IPv6 address of the network root, if any.
Definition: routing.h:89
void * list_item_next(const void *item)
Get the next item following this item.
Definition: list.c:322
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
Header file for the logging system
A node in a source routing graph, stored at the root and representing all child-parent relationship...
Definition: uip-sr.h:92
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90
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