Bridge and ipv6 autoconfiguration

“There’s no sound”, said my missus.

Few minutes before, as usual, I picked up my 17-inch laptop and placed it on the second desk, where it can face the room. I don’t really like dragging the armchair every time I want to watch a video together, but the flat isn’t big enough to arrange a place with a permanent setup. (I also don’t own a TV and I’m proud of it.)

This time there was indeed no sound.

“Wait a minute”, I said and opened Gnome Terminal. At my place, there is only one set of speakers connected to one computer, and shared over the local area network. After a while I figured out that mplayer had trouble contacting PulseAudio server. The server wouldn’t respond.

I tried playing sound from a different machine – it worked. So it’s not the server. Next test:

maciej@quince ~ $ ping -c 1 leon
PING ( 56(84) bytes of data.
64 bytes from ( icmp_seq=1 ttl=64 time=0.165 ms

— ping statistics —
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.165/0.165/0.165/0.000 ms

Next test…

maciej@quince ~ $ telnet leon 4713
Trying 2001:

Timeout. And… ah. I forgot I was running native IPv6 in my LAN. I tried connecting over IPv4, it worked. I’ve set ${PULSE_SERVER} to the IPv4 address of the PulseAudio server and happily watched the movie together with my missus.

But… what’s going on? Running ping6 gives good results – there are answers. But when I ran ping6 leon, I got no answer. How can ping work for an external host but not for a host in my LAN?

After more poking at the machine, I’ve found out that the response packets (ACK) over IPv6 are in fact coming to the slave eth0 interface, but never to the bridge interface, br0.

Then I’ve noticed that IPv6 routing is wrong! There are two routes:

2001:660:952::/64 dev eth0
2001:660:952::/64 dev br0

Packets should leave through br0, not eth0. First idea, restart the bridge. However, the wrong route stayed there even after interface restart. It made me think what happens when I stop the bridge.

Well, eth0 goes back from slave state into a normal state, and then… it’s autoconfigured. That means, it gets a route assigned to it. When the bridge is being started, eth0 becomes a slave of br0, but there probably is no mechanism to remove the route which was assigned during eth0’s autoconfiguration.

A quick ad-hoc fix is:

ip -6 route del 2001:660:952::/64 dev eth0

A permanent solution would be better, but I happen to be lazy.

UPDATE 2009-02-01: Jeroen Massar from SixXS offered a better workaround:
put in /etc/sysctl.conf:
net.ipv6.conf.eth0.accept_ra = 0

When talking about this problem, the conversation usually goes like this:
– I have this problem with IPv6 autoconfiguration… (yada yada)
– What distribution are you using?
– Gentoo.
– (laughter)

Well, turns out, they were right. I tried this config on Ubuntu:

maciej@ubuntu-vbox:~$ cat /etc/network/interfaces
auto lo
iface lo inet loopback
iface br0 inet dhcp
bridge_ports eth0
auto eth0
auto br0

After “/etc/init.d/network restart”, the surplus route was there. But after a reboot, it wasn’t there any more. Ubuntu/Debian somehow handles this case.