Hi there, and welcome back to this IPv6 series. We have been looking at the neighbor discovery protocol and the various functions it performs. In the last article, we discussed the prefix discovery and redirect functions. In this article, we will be talking about neighbor unreachability detection, which allows hosts to check whether a neighbor is reachable.
A node considers its neighbor reachable if it sent packets to that neighbor and received a confirmation that the packets were received and processed by that neighbor. There are two ways a node can receive this confirmation:
It receives information from upper-layer protocols that the connection is making forward progress. For example, a host can determine that a TCP connection is making forward progress if it receives an ACK from the neighbor for a SYN in the node sent. The neighbor could only have replied with an ACK if it received the SYN (in the natural case of a TCP handshake, not when an attack is occurring).
It receives a neighbor advertisement message from the neighbor in response to a unicast neighbor solicitation message that the node sent. The only way the neighbor could have sent a neighbor advertisement message (with the solicited flag set) is if it received a neighbor solicitation message.
Note that for a neighbor to be reachable, neighbor unreachability detection requires that the forward path from a node to its neighbor be reachable from the viewpoint of the node. This means that even if a node receives an unsolicited neighbor discovery message (e.g., unsolicited neighbor solicitation, router advertisement) from its neighbor, it does not mean that the node can reach the neighbor; it only means that the path from the neighbor to the node is working.
Therefore, if HOST1 and HOST2 are communicating, HOST1 must perform its own neighbor unreachability detection and HOST2 must also perform its own. If HOST1 sends a neighbor solicitation message to HOST2 and receives a neighbor advertisement message back, HOST1 can conclude that HOST2 is reachable. However, HOST2 has no way of knowing that the neighbor advertisement message it sent to HOST1 was received, so HOST2 must perform its own neighbor unreachability detection. The diagram below explains this concept:
Neighbor Cache Entry States
Note that the states unknown and reachable as used in the diagram above are just for explanatory purposes. According to the RFC, there are actually five states in which a neighbor cache entry can be, as follows:
This means that address resolution is currently taking place on the entry. The node has sent neighbor solicitation messages on the neighbor’s solicited-mode multicast address but has not received a neighbor advertisement back from the neighbor. After sending a certain number of multicast solicitation messages without any response, that entry is deleted. If a response is received, the state of the entry changes to REACHABLE.
We will use a network scenario to see these states.
From our host I will ping an IP address that is not alive, e.g., fe80::4.
Wireshark captures reveals that the host is sending neighbor solicitation messages for that host but is not receiving neighbor advertisements back.
If we check the state of that entry in the neighbor cache while the ping is going on, it should have a state of INCOMPLETE.
The RFC specifies that, after a certain number of unacknowledged neighbor solicitation messages have been sent, the entry should be deleted from the neighbor cache. I noticed that Microsoft implementation does not delete the entry—it remains in the Incomplete state—until probably a restart or interface reset is done. However, Cisco routers eventually delete the entry. It’s not a deal breaker on Microsoft’s part though because ,if ever packets need to be sent to that address again, the host will still send neighbor solicitation messages.
This is the second state an entry can be in and it means that positive confirmation that the neighbor is reachable has been received in the last reachable time. The reachable time is how long a neighbor is considered reachable after receiving reachability confirmation. The RFC recommends a value of 30 seconds.
Let’s test this. The entry for R1 in my host’s neighbor cache is currently STALE (which is the next state we will talk about) but, if I ping that address, it will eventually change to REACHABLE.
Note: As we will soon see, it first goes to DELAY before REACHABLE.
Notice the time specified in the brackets, i.e., 21 seconds: That is how long this entry will remain in the REACHABLE state unless a new reachability confirmation is received that resets that timer. If no reachability confirmation is received before the time expires, it goes to the STALE state.
The reachable time has passed and the node has not received a positive confirmation that the neighbor is reachable. For example, after my ping session ended, and the reachable time elapsed, the entry for R1 will change to STALE on my host.
When in the state of STALE, the node does not attempt to check reachability until a packet is to be sent. Basically the node, for an entry in this state, is saying: “I have heard from this neighbor in the past but since I’m not sending it any packet, I won’t verify if it is available…waste of energy.”
When a node receives an unsolicited neighbor discovery message (e.g., a router advertisement) from a neighbor, it also adds an entry for that neighbor with a state of STALE.
When packets are first sent to an entry in the STALE state, the entry is changed to a state of DELAY and remains in this state for a certain period. This gives upper-layer protocols enough time to provide reachability confirmation before a unicast neighbor solicitation message is sent. If reachability confirmation is not received by the node after a certain period (delay time), then the state should change to PROBE and unicast neighbor solicitation messages should be sent.
Let’s do a test for this. The entry for R1 is still in the STALE state in the neighbor cache of the host. I will send one ping packet from the host to R1 and observe the neighbor cache as well as the Wireshark capture.
As you can see, the ping was successful. Immediately after the ping, I checked the neighbor cache of the host; notice that R1’s entry is now in the DELAY state.
Finally, let’s check the Wireshark capture.
The timestamps (shown in seconds) on those packets are very important for understanding what happened. Around 5 seconds after I began this capture, we see the echo request and reply messages.
The entry for R1 was in STALE state before the ping request was sent and, once I issued the ping command, the entry immediately went to the DELAY state. It was giving time for an upper-layer protocol to confirm reachability. After waiting about 5 seconds and not receiving the confirmation, the host sent a unicast neighbor solicitation message to R1 and received a unicast neighbor advertisement back.
Upon receiving the neighbor advertisement message, the host is now sure that the neighbor is reachable, and so the state has changed to REACHABLE.
R1 also needed to confirm the reachability of the host, so it sent its own unicast neighbor solicitation message, to which the host replied with a unicast neighbor advertisement message.
R1 also follows the same change trend: STALE à DELAY à REACHABLE.
This is the last state that an entry can be in. If positive confirmation of reachability for an entry in the DELAY state is not received within the delay time, then the state of the entry should be changed to PROBE and unicast neighbor solicitation messages are sent. The node will keep sending these unicast neighbor solicitations until it receives reachability confirmation or until it has sent the maximum number of unicast neighbor solicitation messages at which point it should delete the entry.
The Introduction to IPv6 whitepaper by Microsoft has a great state diagram showing the different states and events that result in state change.
TCP is one of those protocols that neighbor unreachability detection can rely on for reachability confirmation. To simulate this, I will open a telnet session to R1 from my host. This will make the state of R1’s entry in the host’s neighbor cache to be REACHABLE.
After a while of leaving the telnet session idle, the state goes back to STALE.
However, if I do anything on that telnet session, such as press ENTER, the state will change to DELAY and then REACHABLE without the host sending any neighbor solicitation message to R1. The TCP connection was able to provide it with reachability confirmation, since it received a reply for the command I entered.
Here’s the Wireshark capture. Notice that only R1 used neighbor solicitation message for neighbor unreachability detection; the host did not.
Neighbor unreachability detection improves efficiency in IPv6 neighbors by allowing nodes to quickly determine if their neighbors are reachable, and if not, to choose an alternate path in the case that the path is faulty and not the destination itself. We have discussed the five states in which an entry in the neighbor cache can be in, including INCOMPLETE, REACHABLE, STALE, DELAY, and PROBE.
One final point to note is that even if the state of a neighbor in STALE or DELAY, packets will still be sent to that neighbor while the reachability state is being verified. This is the reason we got a ping response even when the state was in DELAY. However, it seems that some implementations may queue packets although the RFC does not state that.
In the next article, we will be discussing the final function performed by the Neighbor Discovery protocol and also seeing a bit of DHCPv6. I hope you have found this article informative and I look forward to writing the next article in the series.
References and Further reading
RFC 4861: Neighbor Discovery for IP version 6 (IPv6): http://tools.ietf.org/html/rfc4861
Introduction to IPv6: http://technet.microsoft.com/library/bb726944.aspx