Issue
A No-Path DAO is a DAO with the Transit Information Option "lifetime" field set to 0, to signal to a node that the prefix(es) given in the Target Option are no longer reachable. This triggers route suppression in dao_input (rpl-icmp6.c), by setting an expiration timeout for a particular route, which is later suppressed in rpl_purge_routes (rpl.c).
Currently, No-Path DAOs are sent in two circumstances:
- To the previous preferred parent when the preferred parent is changed.
- To the previous preferred parent in case it becomes NULL due to unacceptable rank.
I did some tests with the current implementation and this works quite well. However, No-Path DAOs are not propagated upwards towards the sink. When a router deletes route which is its last known route towards a particular prefix, it should schedule a No-Path DAO with that prefix set in the Target Option. It's mentionned as a valid event to generate a new DAO message in Section 9.2.2 of RFC6550
In Storing mode, a DAO message is "new" if
it satisfies any of these criteria for a contained Target:
- it has a newer Path Sequence number,
- it has additional Path Control bits, or
- it is a No-Path DAO message that removes the last Downward route
to a prefix.
When No-Path DAOs are not generated in the way I just described, traffic routed from the sink or outside the RPL network will not be affected, because normal DAOs sent after the parent switch occurs will successfully update the routes along the new path, including the sink. However, this affects p2p traffic originating in the sub-dodag in which the target was previously present.
Example
To illustrate, consider the scenario below where 1 is the sink:
- node 6 selects node 2 as preferred parent in the DAG formation
- after a while, node 7 appears as a potential parent for 6, and becomes the preferred parent (for whatever reason).
- 6 switches to 7, and sends a No-Path DAO to 2
- 2 suppresses its route to 6
- 6 sends a DAO to 7
- 7 adds a route for 6, and announces that prefix to its parent in a DAO
If 2 does not propagate the fact that it cannot reach 6 anymore, 5 will have an inconsistent routing table. This doesn't affect traffic coming from the sink, or from anywhere outside node 5's sub-dodag. However, if node 4 tries to reach 6, node 5 will forward traffic along 2 and a loop will appear.
Partial Solution
A partial solution in the above scenario is to generate a No-Path DAO from 2 to 5, containing node 6's prefix, and to propagate it towards the sink.
In this branch, I added dao_output_target for DAO generation to an arbitrary target and I call this to generate no-path DAOs when rpl_purge_routes detects that a deleted route entry is the last one for a given target. This is enough to delete the routes up until we reach a common ancestor. I'm not doing a pull request because it will probably evolve some more and it needs merging with dao_output. It also needs to be generalized for multi-instances/dags.
Note that this doesn't avoid the problem completely, it only lowers the chances of it occurring. If the No-Path DAO of the leaving node is not heard by the previous parent, or if it's lost somewhere along the path, there will still be an inconsistency. Making the DAOs Ackable might be an improvement, yet still limited.