0

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.

5
  • 1
    The IPv6 addresses with prefix fe80::/10 are known as link-local addresses and they are never supposed to be forwarded from one interface to another. Forwarding the link-local traffic would be a violation of the IPv6 specification, so the Linux kernel won't do it. Even with another prefix, both A and B would assume they can simply communicate directly, since the source and destination are within the same IPv6 segment; to override this assumption you'd need to configure custom routes on all three.
    – telcoM
    Jul 30, 2019 at 7:45
  • 4
    This is called routing, not forwarding. Jul 30, 2019 at 7:51
  • What kind of device do you mean? A router? Then the answer is no because local link addresses are only available per local segment. A l2 switch? Then yes
    – aardbol
    Jul 30, 2019 at 8:18
  • @telcoM I think what make sense is the behavior of the device own eth0 and eth1. this topo is transparent to A or B if the device can forward packets between eth0 and eth1. Jul 30, 2019 at 10:07
  • @telcoM The essential question is : How kernel behavior if two interface's IPv6 address are the same subnet. It can bridge them ? Jul 30, 2019 at 10:11

3 Answers 3

2

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.

4
  • 1
    I never expect these packets forwards via L3 route, but If kernel make a virtual bridge when it find two or more interfaces has same prefix. then it's the perfect solution. but now kernel seems not support. The only solution now is put them in a bridge. but the usage scenario is eth0 is LAN, eth1 is WAN. IPv4 NAT is running on eth0 and eth1. the dual stack is impossible, if kernel doesn't support above IPv6 virtual bridge. and I found a solution relayd. IPv6 passthrough mode for this scenario. Jul 31, 2019 at 3:20
  • @yuanjianpeng If you bridge the two networks, you should configure both IPv4 and IPv6 on the bridge interface rather than on the individual ones. My Raspberry Pi has both IPv4 and IPv6 (it's an IPv6 router in fact) and the eth0 and wifi0 interfaces are just part of the bridge, with no configuration of their own. See my separate answer on how my config looks like. May 1, 2020 at 13:34
  • Also. If you have two interfaces with same prefix, EXCEPT the link-local prefix, you would just have two routes in-kernel with the same destination and packets will flow randomly (generally based on some "optimum" decided by the network stack) through one or the other interface. If it's the link-local prefix, all packets must mention what interface they go through SEPARATE from the IP address itself. This way you can have not only same prefix, but even same IP address belong to two devices, as long as they are on different links. May 1, 2020 at 13:41
  • Think of the link-local addresses as the 169.254.0.0/16 network, which is the same thing but for IPv4. Except in IPv6 link-local addresses are required for everything, including autoconfiguration, DHCP or finding a default gateway. The only thing in IPv6 that doesn't require a link-local address is NDP (the equivalent of ARP). That is used in configuring an IPv6 address (conflict detection) as well as just get the underlying MAC address for being able to send the packets over an L2 link. May 1, 2020 at 13:43
1

fe80::/10 are link-local addresses. Always on-link, never routed; only in scope for the local segment. They are a "next hop" address, a way in the IP protocol to discover and talk to neighbors, including routers.

You specified not bridged, so A and B are not neighbors via layer 2.


Crossing layer 2 boundaries is the job of a layer 3 router. Your example has no such route, so here is how it usually goes, per rfc4861.

Nodes A and B configure additional IP addresses, out of global unicast or unique local address space. Say 2001:db8:0:7224::a and 2001:db8:0:7224::b.

  • If A determines B to be on-link, the next hop is straight to 2001:db8:0:7224::b.
  • If not on-link a router is selected. This can be via link-local, perhaps fe80::3 on the eth0 side. The destination header is still 2001:db8:0:7224::b, as being a router it will forward packets to their final destination.

In either case, neighbor discovery determines the link-layer address to wrap the IP packet in.

1

This is not supposed to stand as an answer of its own, it's just how I can bridge wired and wireless networks just fine. For IPv4 I have a manual IP address, for IPv6 I have autoconfig enabled. The autoconfig goes through br0 just fine. If you run radvd on the pi (I do), you need to mention br0 as the interface, otherwise you need not to worry.

An L2 bridge cannot just bridge IPv4 and not bridge IPv6, because the bridge really works on the Ethernet packets, and IPv4 and IPv6 are on top of Ethernet. It's an all or nothing -- bridge both or neither.

auto eth0
iface eth0 inet manual

auto wlan0
iface wlan0 inet manual

auto br0
iface br0 inet static
»       bridge_ports eth0 wlan0
»       address 192.168.1.72
»       netmask 255.255.255.0
»       gateway 192.168.1.1
iface br0 inet6 auto
»       bridge_ports eth0 wlan0 # Configured via radvd on this same host

You said that eth0 is WAN and wlan is LAN. That complicates it, because you simply cannot bridge them correctly without serious issues. In that case you would have to forward. But then why do you want to route between LAN and WAN on IPv6? That doesn't make too much sense to me.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .