Linux – Can linux kernel forward IPv6 packets between 2 interfaces with the same prefix

ipv6linux

Assume a topology

A <=> eth0 eth1 <=> B

eth0 & eth1 are on the same device with IPv6 forward enabled but these two interfaces are not put in a bridge.

In case A, B, eth0 and eth1 have the same address prefix, e.g. their IPv6 addresses are

  • fe80::2
  • fe80::3
  • fe80::4
  • fe80::5

, will A and B be able to communicate with each other ?

How about if the addresses are global unicast address.

Best Answer

The Layer-2 solution: bridging

If the eth0 and eth1 are not configured to act as parts of a bridge as originally assumed in the question, then the middle system will not be transparent to traffic from A to B. But if those interfaces are configured as two parts of a bridge, then traffic can pass through from A to B and vice versa without any changes to the configurations of A or B.

The trickier Layer-3 alternative: forwarding

Using forwarding to make traffic between A and B pass through the middle device will be more difficult, because under the conditions specified in the question, forwarding is not the right tool for this job.

First, since fe80:: is the link-local prefix, any traffic with that prefix will not be forwarded from one link (e.g. A <=> eth0) to another (eth1 <=> B); that's just how "link-local" is defined. But, let's assume that you use some other prefix but keep the set-up exactly the same otherwise.

The kernel on the middle device must first receive the traffic packet in order to forward it. And if you don't use bridging, then Layer-2 will stop you here: unless you specifically tell device A that it must use eth0 to reach device B (= set up a host route on device A for device B, using eth0 as the gateway), device A will see that the IPv6 address of device B has the same prefix as device A itself has.

Normally, that means device B should be directly reachable on the same network segment, so device A will just send a ICMPv6 Neighbor Discovery (NDP) packet (also known as Neighbor Solicitation) on the A <=> eth0 link, asking for the MAC address of device B.

The destination address of the neighbor solicitation packet will be the "solicited-node" multicast address, which will be within the FF02:0:0:0:0:1:FF00::/104 prefix. The initial FF02 indicates it's a link-local multicast, so it won't be forwarded by the middle device. So device B will never receive it, and cannot answer it.

After a few retries, device A will conclude that there is no response to its neighbor solicitation, and that it means the device B is unreachable. The middle device never gets a chance to forward anything, because it never receives anything that would be allowable to forward.

Even if device A will already know the MAC address of device B, the MAC filter (often in the hardware of the network interface) on eth0 will not pass the packet to the kernel of the middle device. Basically: "It's not my address and not a multicast/broadcast address I need to care about; I don't have to look at it any further."

But if you add an entry to device A's routing table that has higher priority than the default entry for the local network segment (i.e. a tighter prefix), that says "to reach device B, you must use eth0 as your gateway", then device A will first use NDP to get the MAC address of eth0, and will send the packet to device B with a Layer-3 IPv6 address of device B, but with the Layer-2 MAC address of eth0.

Now the traffic reaches eth0 of the middle device, gets past the Layer-2 MAC filter, and the kernel gets to forward it. "That's my MAC address, but not my IPv6 address, so it's something that should be forwarded." But how will the kernel decide which interface it uses to forward the packet? Well, it uses its routing table!

Under the default routing rules (also known as the Weak Host Model), the kernel will just pick the first line on the routing table whose prefix matches the destination address, and use it to forward the traffic. But you'll have two interfaces with the exact same prefix and probably also the same metric value, so it will have a 50% chance to use eth1, usually based on which interface was configured last.

Let's assume that you're lucky, and the routing table has eth1 as the top-most route for your prefix. The packet will go to the outgoing queue for eth1, and the kernel will first send out a NDP query for the MAC address of device B on eth1. Device B will answer it, and then the packet will go out eth1 with a destination IPv6 address of device B, and also with the Layer-2 MAC address of device B. And finally, device B gets to receive it.

But wait, that's just the first half of the problem! The answer must also be able to go from B through the middle device to A. So it will have all the same challenges: first device B must know that "to reach device A, the packet must be sent to eth1 rather than directly to device A's MAC address."

And there is one more challenge. Remember that eth1 was the top-most choice for outgoing traffic for your network prefix on the middle device? Now that the answer is going the opposite way, that is going to send the answer back out through eth1, which is the wrong way for it.

To fix that, you would need either a host route on the middle device, or more universally, a separate routing table for any traffic that came in through eth1. That would require advanced routing rules. (Effectively, you would be implementing an alternative routing strategy, known as the Strong Host Model.)

So, you can do it also with forwarding, but it requires so much additional configuration to make it work, it's usually not worth the effort.

This is actually why good network design and planning are important: if you structure your network prefixes so that they'll match the actual topology of your network, getting the packets to go to their destinations will be much easier.