Contiki 3.x
rpl-mrhof.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
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 /**
34  * \file
35  * The Minimum Rank with Hysteresis Objective Function (MRHOF)
36  *
37  * This implementation uses the estimated number of
38  * transmissions (ETX) as the additive routing metric,
39  * and also provides stubs for the energy metric.
40  *
41  * \author Joakim Eriksson <joakime@sics.se>, Nicolas Tsiftes <nvt@sics.se>
42  */
43 
44 /**
45  * \addtogroup uip6
46  * @{
47  */
48 
49 #include "net/rpl/rpl-private.h"
50 #include "net/nbr-table.h"
51 
52 #define DEBUG DEBUG_NONE
53 #include "net/ip/uip-debug.h"
54 
55 static void reset(rpl_dag_t *);
56 static void neighbor_link_callback(rpl_parent_t *, int, int);
57 static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
58 static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *);
59 static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
60 static void update_metric_container(rpl_instance_t *);
61 
62 rpl_of_t rpl_mrhof = {
63  reset,
64  neighbor_link_callback,
65  best_parent,
66  best_dag,
67  calculate_rank,
68  update_metric_container,
69  1
70 };
71 
72 /* Constants for the ETX moving average */
73 #define ETX_SCALE 100
74 #define ETX_ALPHA 90
75 
76 /* Reject parents that have a higher link metric than the following. */
77 #define MAX_LINK_METRIC 10
78 
79 /* Reject parents that have a higher path cost than the following. */
80 #define MAX_PATH_COST 100
81 
82 /*
83  * The rank must differ more than 1/PARENT_SWITCH_THRESHOLD_DIV in order
84  * to switch preferred parent.
85  */
86 #define PARENT_SWITCH_THRESHOLD_DIV 2
87 
88 typedef uint16_t rpl_path_metric_t;
89 
90 static rpl_path_metric_t
91 calculate_path_metric(rpl_parent_t *p)
92 {
93  if(p == NULL) {
94  return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
95  }
96 
97 #if RPL_DAG_MC == RPL_DAG_MC_NONE
98  return p->rank + (uint16_t)p->link_metric;
99 #elif RPL_DAG_MC == RPL_DAG_MC_ETX
100  return p->mc.obj.etx + (uint16_t)p->link_metric;
101 #elif RPL_DAG_MC == RPL_DAG_MC_ENERGY
102  return p->mc.obj.energy.energy_est + (uint16_t)p->link_metric;
103 #else
104 #error "Unsupported RPL_DAG_MC configured. See rpl.h."
105 #endif /* RPL_DAG_MC */
106 }
107 
108 static void
109 reset(rpl_dag_t *dag)
110 {
111  PRINTF("RPL: Reset MRHOF\n");
112 }
113 
114 static void
115 neighbor_link_callback(rpl_parent_t *p, int status, int numtx)
116 {
117  uint16_t recorded_etx = p->link_metric;
118  uint16_t packet_etx = numtx * RPL_DAG_MC_ETX_DIVISOR;
119  uint16_t new_etx;
120 
121  /* Do not penalize the ETX when collisions or transmission errors occur. */
122  if(status == MAC_TX_OK || status == MAC_TX_NOACK) {
123  if(status == MAC_TX_NOACK) {
124  packet_etx = MAX_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
125  }
126 
127  if(p->flags & RPL_PARENT_FLAG_LINK_METRIC_VALID) {
128  /* We already have a valid link metric, use weighted moving average to update it */
129  new_etx = ((uint32_t)recorded_etx * ETX_ALPHA +
130  (uint32_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE;
131  } else {
132  /* We don't have a valid link metric, set it to the current packet's ETX */
133  new_etx = packet_etx;
134  /* Set link metric as valid */
135  p->flags |= RPL_PARENT_FLAG_LINK_METRIC_VALID;
136  }
137 
138  PRINTF("RPL: ETX changed from %u to %u (packet ETX = %u)\n",
139  (unsigned)(recorded_etx / RPL_DAG_MC_ETX_DIVISOR),
140  (unsigned)(new_etx / RPL_DAG_MC_ETX_DIVISOR),
141  (unsigned)(packet_etx / RPL_DAG_MC_ETX_DIVISOR));
142  p->link_metric = new_etx;
143  }
144 }
145 
146 static rpl_rank_t
147 calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
148 {
149  rpl_rank_t new_rank;
150  rpl_rank_t rank_increase;
151 
152  if(p == NULL) {
153  if(base_rank == 0) {
154  return INFINITE_RANK;
155  }
156  rank_increase = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
157  } else {
158  rank_increase = p->link_metric;
159  if(base_rank == 0) {
160  base_rank = p->rank;
161  }
162  }
163 
164  if(INFINITE_RANK - base_rank < rank_increase) {
165  /* Reached the maximum rank. */
166  new_rank = INFINITE_RANK;
167  } else {
168  /* Calculate the rank based on the new rank information from DIO or
169  stored otherwise. */
170  new_rank = base_rank + rank_increase;
171  }
172 
173  return new_rank;
174 }
175 
176 static rpl_dag_t *
177 best_dag(rpl_dag_t *d1, rpl_dag_t *d2)
178 {
179  if(d1->grounded != d2->grounded) {
180  return d1->grounded ? d1 : d2;
181  }
182 
183  if(d1->preference != d2->preference) {
184  return d1->preference > d2->preference ? d1 : d2;
185  }
186 
187  return d1->rank < d2->rank ? d1 : d2;
188 }
189 
190 static rpl_parent_t *
191 best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
192 {
193  rpl_dag_t *dag;
194  rpl_path_metric_t min_diff;
195  rpl_path_metric_t p1_metric;
196  rpl_path_metric_t p2_metric;
197 
198  dag = p1->dag; /* Both parents are in the same DAG. */
199 
200  min_diff = RPL_DAG_MC_ETX_DIVISOR /
201  PARENT_SWITCH_THRESHOLD_DIV;
202 
203  p1_metric = calculate_path_metric(p1);
204  p2_metric = calculate_path_metric(p2);
205 
206  /* Maintain stability of the preferred parent in case of similar ranks. */
207  if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) {
208  if(p1_metric < p2_metric + min_diff &&
209  p1_metric > p2_metric - min_diff) {
210  PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n",
211  p2_metric - min_diff,
212  p1_metric,
213  p2_metric + min_diff);
214  return dag->preferred_parent;
215  }
216  }
217 
218  return p1_metric < p2_metric ? p1 : p2;
219 }
220 
221 #if RPL_DAG_MC == RPL_DAG_MC_NONE
222 static void
223 update_metric_container(rpl_instance_t *instance)
224 {
225  instance->mc.type = RPL_DAG_MC;
226 }
227 #else
228 static void
229 update_metric_container(rpl_instance_t *instance)
230 {
231  rpl_path_metric_t path_metric;
232  rpl_dag_t *dag;
233 #if RPL_DAG_MC == RPL_DAG_MC_ENERGY
234  uint8_t type;
235 #endif
236 
237  instance->mc.type = RPL_DAG_MC;
238  instance->mc.flags = RPL_DAG_MC_FLAG_P;
239  instance->mc.aggr = RPL_DAG_MC_AGGR_ADDITIVE;
240  instance->mc.prec = 0;
241 
242  dag = instance->current_dag;
243 
244  if (!dag->joined) {
245  PRINTF("RPL: Cannot update the metric container when not joined\n");
246  return;
247  }
248 
249  if(dag->rank == ROOT_RANK(instance)) {
250  path_metric = 0;
251  } else {
252  path_metric = calculate_path_metric(dag->preferred_parent);
253  }
254 
255 #if RPL_DAG_MC == RPL_DAG_MC_ETX
256  instance->mc.length = sizeof(instance->mc.obj.etx);
257  instance->mc.obj.etx = path_metric;
258 
259  PRINTF("RPL: My path ETX to the root is %u.%u\n",
260  instance->mc.obj.etx / RPL_DAG_MC_ETX_DIVISOR,
261  (instance->mc.obj.etx % RPL_DAG_MC_ETX_DIVISOR * 100) /
262  RPL_DAG_MC_ETX_DIVISOR);
263 #elif RPL_DAG_MC == RPL_DAG_MC_ENERGY
264  instance->mc.length = sizeof(instance->mc.obj.energy);
265 
266  if(dag->rank == ROOT_RANK(instance)) {
267  type = RPL_DAG_MC_ENERGY_TYPE_MAINS;
268  } else {
269  type = RPL_DAG_MC_ENERGY_TYPE_BATTERY;
270  }
271 
272  instance->mc.obj.energy.flags = type << RPL_DAG_MC_ENERGY_TYPE;
273  instance->mc.obj.energy.energy_est = path_metric;
274 #endif /* RPL_DAG_MC == RPL_DAG_MC_ETX */
275 }
276 #endif /* RPL_DAG_MC == RPL_DAG_MC_NONE */
277 
278 /** @}*/
The MAC layer deferred the transmission for a later time.
Definition: mac.h:86
#define NULL
The null pointer.
The MAC layer transmission was OK.
Definition: mac.h:79
A set of debugging macros.