cooja中的RPL目标函数与仿真(DGRM模式下)

1.介绍

低功耗和有损耗网络的路由协议利用目标函数(OF)建立一个面向目标的有向无环图(DODAG)。目标函数根据某种算法或计算公式使用路由度量来形成DODAG。基本上,目标函数优化或约束用于形成路由的路由度量,从而帮助选择最佳路由。在同一个节点和网格网络上可能有许多目标函数在运行,因为不同的部署目标差异很大,单个网格网络可能需要承载具有非常不同的路径质量要求的流量。

在Contiki中实现RPL,内置有两个目标函数,但是默认情况下它使用的是最小化ETX值的那个。但是,在所有路由场景中,相同的策略不可能是最佳的路由策略。因此,需要相应地修改目标函数,以适应任何额外的约束或实现不同的目标。

2.这章节将会学到

本教程的基本假设是您了解用于低功耗和有损网络(RPL)的路由协议的工作原理。
这里使用并解释了ContikiOS 3.0 RPL的实现。
以下是本教程的解释:

  • 不同的RPL相关功能及其工作
  • 示例场景和RPL目标函数的修改
  • 基于DGRM模型的Cooja仿真

3.源代码路径

在contiki-3.0的操作系统下

~/contiki/core/net/rpl/rpl-conf.h
~/contiki/core/net/rpl/rpl-of0.c
~/contiki/core/net/rpl/rpl-mrhof.c
~/contiki/tools/cooja

4. 相关文件及功能

具有RPL要点的一些重要文件:rpl-config.h, rpl-of0.c, rpl-mhrof.c。但是这里只提到了这些文件中的一些重要函数。

rpl-conf.h

RPL_CONF_STATS

1
2
3
4
/* Set to 1 to enable RPL statistics */
#ifndef RPL_CONF_STATS
#define RPL_CONF_STATS 0
#endif /* RPL_CONF_STATS */

这里禁用了RPL配置统计信息。我们需要将它设置为1。

RPL_DAG_MC

1
2
3
4
5
6
7
8
9
10
11
12
/* 
* Select routing metric supported at runtime. This must be a valid
* DAG Metric Container Object Type (see below). Currently, we only
* support RPL_DAG_MC_ETX and RPL_DAG_MC_ENERGY.
* When MRHOF (RFC6719) is used with ETX, no metric container must
* be used; instead the rank carries ETX directly.
*/
#ifdef RPL_CONF_DAG_MC
#define RPL_DAG_MC RPL_CONF_DAG_MC
#else
#define RPL_DAG_MC RPL_DAG_MC_NONE
#endif /* RPL_CONF_DAG_MC */

选择运行时支持的路由度量。
这里支持使用ETX和ENERGY类型的RPL度量容器。(RPL_DAG_MC_ETX 和 RPL_DAG_MC_ENERGY)
如果您开发了一个目标函数和相关的度量容器,则可以支持它。

RPL_OF

1
2
3
4
5
6
7
8
9
10
11
/*
* The objective function used by RPL is configurable through the
* RPL_CONF_OF parameter. This should be defined to be the name of an
* rpl_of object linked into the system image, e.g., rpl_of0.
*/
#ifdef RPL_CONF_OF
#define RPL_OF RPL_CONF_OF
#else
/* ETX is the default objective function. */
#define RPL_OF rpl_mrhof
#endif /* RPL_CONF_OF */

RPL_OF配置了RPL的目标函数。在这里,ETX是默认的目标函数。这应该定义为链接到系统映像的rpl_of对象的名称,比如rpl_of0。在这里,您还可以将它定义为您自己开发的目标函数。

RPL_LEAF_ONLY

1
2
3
4
5
6
7
8
9
/*
* This value decides if this node must stay as a leaf or not
* as allowed by draft-ietf-roll-rpl-19#section-8.5
*/
#ifdef RPL_CONF_LEAF_ONLY
#define RPL_LEAF_ONLY RPL_CONF_LEAF_ONLY
#else
#define RPL_LEAF_ONLY 0
#endif

节点是否应该作为叶节点由这个值决定。
(如draft-ietf-roll-rpl-19#section-8.5中所述)

RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
* RPL Default route lifetime
* The RPL route lifetime is used for the downward routes and for the default
* route. In a high density network with DIO suppression activated it may happen
* that a node will never send a DIO once the DIO interval becomes high as it
* has heard DIO from many neighbors already. As the default route to the
* preferred parent has a lifetime reset by receiving DIO from the parent, it
* means that the default route can be destroyed after a while. Setting the
* default route with infinite lifetime secures the upstream route.
*/
#ifdef RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME
#define RPL_DEFAULT_ROUTE_INFINITE_LIFETIME RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME
#else
#define RPL_DEFAULT_ROUTE_INFINITE_LIFETIME 0
#endif /* RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME */

RPL路由生存期用于向下路由和默认路由的构建。在高密度网络且DIO不活跃时(组网稳定后),可能会发生这种情况:一个节点永远不会发送DIO报文了,一旦发送DIO的时间间隔变得很高则已经收到很多邻居的来信了。默认路径通过接收来自父节点的DIO信号来重置首选父节点的生存期,它表示默认路由可以在一段时间后销毁。
设置具有无限生存期的默认路由保护上行路由。

RPL_DIO_INTERVAL_MIN

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* The DIO interval (n) represents 2^n ms.
*
* According to the specification, the default value is 3 which
* means 8 milliseconds. That is far too low when using duty cycling
* with wake-up intervals that are typically hundreds of milliseconds.
* ContikiRPL thus sets the default to 2^12 ms = 4.096 s.
*/
#ifdef RPL_CONF_DIO_INTERVAL_MIN
#define RPL_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN
#else
#define RPL_DIO_INTERVAL_MIN 12
#endif

DIO以2^n ms的时间间隔对外发送。
根据说明,默认的值为3(即2^3=8 ms)。当使用任务循环时,这个值太低了唤醒间隔通常为数百毫秒。
ContikiRPL因此设置默认值为2^12 ms = 4.096 s.

RPL_INIT_LINK_METRIC

1
2
3
4
5
6
7
8
/*
* Initial metric attributed to a link when the ETX is unknown
*/
#ifndef RPL_CONF_INIT_LINK_METRIC
#define RPL_INIT_LINK_METRIC 2
#else
#define RPL_INIT_LINK_METRIC RPL_CONF_INIT_LINK_METRIC
#endif

当ETX的值位置是,初始化这个度量值为2

of0.c

这个文件中描述了RPL中of0目标函数的定义。

calculate_rank(rpl_parent_t * p, rpl_rank_t base_rank)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static rpl_rank_t
calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
{
rpl_rank_t increment;
if(base_rank == 0) {
if(p == NULL) {
return INFINITE_RANK;
}
base_rank = p->rank;
}

increment = p != NULL ?
p->dag->instance->min_hoprankinc :
DEFAULT_RANK_INCREMENT;

if((rpl_rank_t)(base_rank + increment) < base_rank) {
PRINTF("RPL: OF0 rank %d incremented to infinite rank due to wrapping\n",
base_rank);
return INFINITE_RANK;
}
return base_rank + increment;

}

这里计算节点的秩。节点的秩基于它的父级秩(parents rank)和基级秩(base rank)。

  • 如果基秩为0,而节点没有父结点,则节点的秩为无穷大。
  • 如果基秩为0并且父秩存在,那么基秩就等于父秩。
  • 如果基秩不为零,那么根据父级是否存在,增量(increment)将成为DAG instance中父节点的min_hoprankinc或DEFAULT_RANK_INCREMENT。

简而言之,如果没有父节点,那么base_rank将增加为一个默认的增量,否则它将使用有关父级的信息来增加base_rank。

在最后一部分中,如果计算出的新秩(new rank)小于基秩(bese rank),则新秩(new rank)由于环路loop而变得无穷大。

新计算的秩(the new caculate_rank) = 基秩(base_rank) + 增量(increment)。

best_dag(rpl_dag_t * d1, rpl_dag_t * d2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
static rpl_dag_t *
best_dag(rpl_dag_t *d1, rpl_dag_t *d2)
{
if(d1->grounded) {
if (!d2->grounded) {
return d1;
}
} else if(d2->grounded) {
return d2;
}

if(d1->preference < d2->preference) {
return d2;
} else {
if(d1->preference > d2->preference) {
return d1;
}
}

if(d2->rank < d1->rank) {
return d2;
} else {
return d1;
}
}

该函数比较两个dag,并根据目标函数返回两个dag中最好的一个(作为输入d1和d2传递)。
这里有3个标准来找到最佳的DAG。

  • 第一个是检查DAG是否接地(if the DAG is grounded)。
  • 其次是每个DAG的偏好度量(the preference metric of each DAG)。
  • 第三个是每个DAG的秩(the rank of each DAG)。

best_parent(rpl_parent_t * p1, rpl_parent_t * p2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
static rpl_parent_t *
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
{
rpl_rank_t r1, r2;
rpl_dag_t *dag;
uip_ds6_nbr_t *nbr1, *nbr2;
nbr1 = rpl_get_nbr(p1);
nbr2 = rpl_get_nbr(p2);

dag = (rpl_dag_t *)p1->dag; /* Both parents must be in the same DAG. */

if(nbr1 == NULL || nbr2 == NULL) {
return dag->preferred_parent;
}

PRINTF("RPL: Comparing parent ");
PRINT6ADDR(rpl_get_parent_ipaddr(p1));
PRINTF(" (confidence %d, rank %d) with parent ",
nbr1->link_metric, p1->rank);
PRINT6ADDR(rpl_get_parent_ipaddr(p2));
PRINTF(" (confidence %d, rank %d)\n",
nbr2->link_metric, p2->rank);


r1 = DAG_RANK(p1->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC +
nbr1->link_metric;
r2 = DAG_RANK(p2->rank, p1->dag->instance) * RPL_MIN_HOPRANKINC +
nbr2->link_metric;
/* Compare two parents by looking both and their rank and at the ETX
for that parent. We choose the parent that has the most
favourable combination. */

if(r1 < r2 + MIN_DIFFERENCE &&
r1 > r2 - MIN_DIFFERENCE) {
return dag->preferred_parent;
} else if(r1 < r2) {
return p1;
} else {
return p2;
}
}

该函数比较父节点并根据目标函数返回最佳父节点。
这里根据候选父节点的rank值和ETX值对候选父节点进行比较。
这是一个重要的功能,因为路线的形成是在此基础上选择最佳的DAG。

rpl-mhrof.c

该文件实现了带有滞后目标函数(MRHOF)的最小秩。目标函数使用ETX作为路由度量,它还有能量度量的存根。

calculate_path_metric(rpl_parent_t * p)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static rpl_path_metric_t
calculate_path_metric(rpl_parent_t *p)
{
uip_ds6_nbr_t *nbr;
if(p == NULL) {
return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
}
nbr = rpl_get_nbr(p);
if(nbr == NULL) {
return MAX_PATH_COST * RPL_DAG_MC_ETX_DIVISOR;
}
#if RPL_DAG_MC == RPL_DAG_MC_NONE
{
return p->rank + (uint16_t)nbr->link_metric;
}
#elif RPL_DAG_MC == RPL_DAG_MC_ETX
return p->mc.obj.etx + (uint16_t)nbr->link_metric;
#elif RPL_DAG_MC == RPL_DAG_MC_ENERGY
return p->mc.obj.energy.energy_est + (uint16_t)nbr->link_metric;
#else
#error "Unsupported RPL_DAG_MC configured. See rpl.h."
#endif /* RPL_DAG_MC */
}

这里路径度量的计算根据的是OF。
如果没有父节点,则使用基于最大路径成本(maximum path cost)计算的默认度量。
如果没有提到OF,那么路径度量就是秩的和。
(因为OF基于ETX,它是被测量的ETX (p->mc.obj.etx)和链接度量的总和。)
类似地,如果OF基于能量,则将能量值(p->mc.obj.energy.energy_est)添加到链接度量(link metric)中。
此函数由best_parent()调用,用于比较两个父节点的路径度量。

neighbor_link_callback(rpl_parent_t * p, int status, int numtx)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
static void
neighbor_link_callback(rpl_parent_t *p, int status, int numtx)
{
uint16_t recorded_etx = 0;
uint16_t packet_etx = numtx * RPL_DAG_MC_ETX_DIVISOR;
uint16_t new_etx;
uip_ds6_nbr_t *nbr = NULL;

nbr = rpl_get_nbr(p);
if(nbr == NULL) {
/* No neighbor for this parent - something bad has occurred */
return;
}

recorded_etx = nbr->link_metric;

/* Do not penalize the ETX when collisions or transmission errors occur. */
if(status == MAC_TX_OK || status == MAC_TX_NOACK) {
if(status == MAC_TX_NOACK) {
packet_etx = MAX_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
}

if(p->flags & RPL_PARENT_FLAG_LINK_METRIC_VALID) {
/* We already have a valid link metric, use weighted moving average to update it */
new_etx = ((uint32_t)recorded_etx * ETX_ALPHA +
(uint32_t)packet_etx * (ETX_SCALE - ETX_ALPHA)) / ETX_SCALE;
} else {
/* We don't have a valid link metric, set it to the current packet's ETX */
new_etx = packet_etx;
/* Set link metric as valid */
p->flags |= RPL_PARENT_FLAG_LINK_METRIC_VALID;
}

PRINTF("RPL: ETX changed from %u to %u (packet ETX = %u)\n",
(unsigned)(recorded_etx / RPL_DAG_MC_ETX_DIVISOR),
(unsigned)(new_etx / RPL_DAG_MC_ETX_DIVISOR),
(unsigned)(packet_etx / RPL_DAG_MC_ETX_DIVISOR));
/* update the link metric for this nbr */
nbr->link_metric = new_etx;
}
}

此函数接收链路层邻居信息。
参数状态设置为0或1。
numetx参数表示当前邻居节点的ETX(estimated transmission)。
recorded_etx 是 link_metric,packet_etx是传递给函数的numetx参数。
new_etx是根据公式使用recorded and packet ETX计算的。
link_metric用新的ETX值更新。

calculate_rank(rpl_parent_t * p, rpl_rank_t base_rank)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static rpl_rank_t
calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
{
rpl_rank_t new_rank;
rpl_rank_t rank_increase;
uip_ds6_nbr_t *nbr;

if(p == NULL || (nbr = rpl_get_nbr(p)) == NULL) {
if(base_rank == 0) {
return INFINITE_RANK;
}
rank_increase = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR;
} else {
rank_increase = nbr->link_metric;
if(base_rank == 0) {
base_rank = p->rank;
}
}

if(INFINITE_RANK - base_rank < rank_increase) {
/* Reached the maximum rank. */
new_rank = INFINITE_RANK;
} else {
/* Calculate the rank based on the new rank information from DIO or
stored otherwise. */
new_rank = base_rank + rank_increase;
}

return new_rank;
}

这类似于前面介绍的calculate_rank()函数,但有一点不同。
在这个函数中,如果parent = NULL,rank_increase是一个等于RPL_INIT_LINK_METRIC的增量。否则它等于link_metric。
new_rank = the increment + base rank

est_parent(rpl_parent_t * p1, rpl_parent_t * p2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static rpl_parent_t *
best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
{
rpl_dag_t *dag;
rpl_path_metric_t min_diff;
rpl_path_metric_t p1_metric;
rpl_path_metric_t p2_metric;

dag = p1->dag; /* Both parents are in the same DAG. */

min_diff = RPL_DAG_MC_ETX_DIVISOR /
PARENT_SWITCH_THRESHOLD_DIV;

p1_metric = calculate_path_metric(p1);
p2_metric = calculate_path_metric(p2);

/* Maintain stability of the preferred parent in case of similar ranks. */
if(p1 == dag->preferred_parent || p2 == dag->preferred_parent) {
if(p1_metric < p2_metric + min_diff &&
p1_metric > p2_metric - min_diff) {
PRINTF("RPL: MRHOF hysteresis: %u <= %u <= %u\n",
p2_metric - min_diff,
p1_metric,
p2_metric + min_diff);
return dag->preferred_parent;
}
}

return p1_metric < p2_metric ? p1 : p2;
}

这类似于前面的best_parent()函数,该函数比较两个父类并返回最佳的一个。
这里,为每个父节点计算的路径度量(path metric)是比较的基础。
首先检查在DAG中是否有一个父节点被设置为首选父对象,如果是,则选择它作为最佳父对象(基于MRHOF滞后现象 RFC 6719)。
否则,将比较计算的两个度量,选择具有较低度量的节点为最好的父节点。
在这个函数下,只有当它比当前路径少于一个给定阈值时,才切换到最小秩路径。
第二种机制称为“滞后现象”(RFC 6719)。这里,PARENT_SWITCH_THRESHOLD_DIV被定义为2。

这种父选择发生在以下情况中:

  • 在网络的初始形成过程中
  • 当邻近节点的路径代价发生变化时
  • 一个新节点出现在该节点的邻域中

5.目标函数的修改

l2jDWd.png
上图显示了一个可以使用的拓扑示例。
一个目标函数基本上使用一个链路度量(link metric),并有一个约束的函数试图为路由选择最佳路径。
要定义一个全新的目标函数文件(不修改现有文件),必须在其中定义以下函数。
还应该相应地修改makefile,并注意新文件不应出现编译和链接错误。
一些RPL OF 的API如下所示:

  • reset(dag):重置特定DAG的目标函数状态。在对DAG执行全局修复时调用此函数。
  • neighbor_link_callback(parent, status, etx): 接收链路层邻居信息。
  • best_parent(parent1, parent2):根据OF,比较两个父节点并返回最好的一个。
  • best_dag(dag1, dag2):根据OF,比较两个dag并返回最好的一个。
  • calculate_rank(parent, base_rank): 使用父秩和基秩计算秩值。
  • update_metric_container(dag): 在某个DAG中更新传出DIOs的度量容器。如果DAG的目标函数不使用度量容器,则该函数应该将对象类型设置为RPL_DAG_MC_NONE。

修改目标函数的一个例子可以是Load Balancing application
新的目标函数应该选择一条最小化ETX的路由,如果有多条路由具有相同的ETX,或者ETX在预定义的范围内,那么它应该减小这些路由中任意一条转发包的最大数量。
这意味着任何一个节点都不承担转发包的负载,而其他节点则处于未被利用的状态。

解决这个问题的一种方法是定义一个如前所述的全新的目标函数。
另一种方法是修改现有的rpl-mhrof.c文件。因为它已经使用了问题的最小ETX部分,我们只需要实现负载平衡部分。
当一个子节点有多条路由时,负载平衡就出现了,比如父节点们。因此,the best parent function应该做相应的修改。

另一个例子是选择shortest path with nodes using minimum energy
这里的目标函数应该是这样的:
它首先使用最小能量或在一个范围内识别节点;
然后使用最小跳数通过这些节点到达目的地。
这可以应用于这样一种情况:一个节点必须快速发送数据,而不会给一个能量不足的节点带来负担。
在这个场景中,使用能量度量的目标函数在当前的rpl-mhrof.c中的当前实现中已经存在,并且目标函数可以与附加逻辑一起用于在选择父节点时选择最小跳数。
其他需要新的或修改的目标函数的场景可以基于不同的链接度量,如吞吐量(throughput)、链接质量级别(link quelity level)、延迟(latency)等。

6.Cooja仿真(在DGRM模式下)

使用DGRM模型是因为它更容易改变链路接收速率。
此外,在两个需要的节点之间形成链接也更容易,其他节点除外。以下是形成一个新的模拟的步骤:

注意:您可以参考Cooja Simulater来了解Cooja.

  • 运行cooja

打开你的contiki文件夹,在路径“contiki-3.0/tools/cooja”下,进入终端,敲下面命令,打开GUI界面

1
sudo ant run

l2zBYF.png

  • 开始一个新的仿真

file下拉菜单中选择New Simulation
l2zjk8.png

会弹出下面的界面:
lRSQn1.png

simulation name栏中,填写你的仿真名称;
radio medium下拉选项中,选择directed graph radio medium(DGRM)
点击creat按钮,创建仿真工程。
lRpP8e.png

创建的new simulation将打开多个窗口,如下所示。
lRpn58.png

  • 添加sink mote

添加类型为Sink的mote。
lRp0xJ.png

这里使用了来自rpl-collect示例(/examples/ipv6/rpl-collect/)的udp-sink.c代码。
但是,您可以根据应用程序上传任何想要实现的代码。
单击Compile按钮。
lRpHdP.png

在成功编译时,将出现一个创建按钮,该按钮可根据需要在网络中添加更多的mote。这里只添加1个sink节点。
lR9PoV.png

  • 添加其他sender motes
    添加其他类型的mote。
    这里使用的是来自rpl-collect示例(/examples/ipv6/rpl-collect/)的udp-sender.c代码。
    但是,您可以根据应用程序上传任何想要实现的代码。
    lR9vtK.png
    编译代码并根据拓扑结构创建许多这种类型的motes。
    lRiKwn.png
    lRi3WT.png

注意:mote的位置在这里并不重要。你可以把你的motes放在图表的任何地方。由于这与距离模型不同,我们在motes之间建立了明确的通信联系,因此它们之间的距离没有区别。

  • 添加communication links

在每组节点之间添加两个通信链路,使通信可以是双向的。

选择tools->DGRM Links...这将打开一个DGRM配置器对话框。
lRFm9K.png

单击Add.选择sourcedestination,然后再次单击Add。这将添加一个从源节点到目标节点的单向链接。对于双向链接,您需要添加一个带有交换的源节点和目标节点的链接。您可以通过这种方式添加多个链接。添加链接后关闭对话框。
lRFcCV.png
您可以根据您的应用程序更改链接的其他参数,如RX radio、RSSI、LQI和delay。这些参数会影响单个链接的质量。RX radio影响ETX值。
因此,要在各种链接质量条件下测试应用程序时,可以更改这些参数。

您还可以使用remove选项删除一个现有的。
Import选项有助于导入已经在其中指定了这些链接连接和参数的任何数据文件。

  • 运行仿真

使用simulation control窗口中的Start选项运行仿真。
这将启动mote,并且分配给所有的mote一个新的rime地址和其他初始化过程。
lRkzyF.png

  • Watch Output
  1. motes输出和调试消息可以在Motes Output窗口中看到。
  2. 可以根据节点ID:node_id对输出进行筛选,以监视特定的节点。
  3. 还可以通过过滤来查看特定的调试消息。
  4. Motes output中其他有用功能是file,edit和view。
    File选项有助于将输出保存到文件中。
    Edit具有复制输出的选项 — 完整的或特定选定的消息。
  5. 您还可以使用Clear all messages选项来清除消息。
  6. 使用这些保存在文件中的信息,根据您的实验目标进行观察并绘制图形。

7.温馨提醒

在运行cooja时,一定要以sudo ant的方式运行,因为只运行ant可能会抛出一些错误,因为它可能无法访问某些文件。
如果网络很大或ETX值很大,则来自叶节点的数据包可能需要一段时间才能到达根节点。
因此,您可能需要长时间地运行模拟。

参考文献

  1. RFC 6550 RPL: IPv6 Routing Protocol for Low-Power and Lossy Networks
  2. RFC 6552 Objective Function Zero for the Routing Protocol for Low-Power and Lossy Networks (RPL)
  3. RFC 6719 MRHOF: The Minimum Rank with Hysteresis Objective Function
  4. ContikiRPL and TinyRPL: Happy Together
  5. Documentation: RPL
  6. Tutorial: RPL

此文翻译的是链接 https://blog.csdn.net/frank_jb/article/details/50912306 的内容