QEMU/KVM IPv6 Support
This article describes IPv6 support in QEMU/KVM.
You have rented a whole server in a data center somewhere and are running a few Kernel Virtual Machines (KVMs). Your provider gives you a single IPv4 address and a IPv6 /64 subnet. Its a nuisance to use IPv4 with non standard ports on the KVMs and you are too parsimonious to invest in more IPv4 addresses, its a hobby server after all. You get a single IPv4 address and a whole IPv6 /64 subnet, since your provider cannot give you any less.
Lets put the KVMs onto IPv6 so that they have global scope IPv6 addresses.
This guide is written around the use of libvirtd
- A working Gentoo host with IPv6 support.
- One or more Gentoo KVM Guests with IPv6 support.
- A IPv6 /64 prefix, like 2001:db8:dead:beef::/64
- IPv6 working on the host.
IPv6 support means
USE="ipv6" in /etc/portage/make.conf, kernel IPv6 support and packages like sys-apps/iproute2 installed.
Other than iproute2, this is the Gentoo default.
On the hosts and KVM:
emerge --ask sys-apps/iproute2
Do check that it is built with
USE=ipv6. If emerge shows that its a rebuild it can be skipped...there is nothing new to compile.
The host setup
Your KVM setup will have created an interface called virbr0.
The settings for this are stored in /etc/libvirt/qemu/networks/default.xml. You might want to backup this file before you start.
Stop the network, so you can edit the settings file. Don't even think of using $EDITOR.
virsh net-destroy default
virsh net-edit default
Add the following two lines above the existing closing
Use your own /64 and make up your own prefix extension.
<ip family='ipv6' address='2001:db8:dead:beef:fe::2' prefix='96'> </ip>
virsh net-edit will syntax check your edit and complain loudly if you mess up. This adds an IPv6 address to virbr0.
If you want to use DHCP for IPv6 in your KVMs, you probably don't, you can add a range statement here too. The range must be part of the prefix being assigned to virbr0
<ip family='ipv6' address='2001:db8:dead:beef:fe::2' prefix='96'> <dhcp> <range start='2001:db8:dead:beef:fe::1000' end='2001:db8:dead:beef:fe::2000' /> </dhcp> </ip>
Restart the network:
virsh net-start default
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255 inet6 2001:db8:dead:beef:fe::2 prefixlen 96 scopeid 0x0<global> inet6 fe80::wwww:xxxx:yyyy:zzzz prefixlen 64 scopeid 0x20<link> ...
Notice that the interface virbr0 has aquired a /96 from your /64. That's as many IP addresses as there is in the entire IPv4 address space.
You also have a self assigned link local IP, where wwww:xxxx:yyyy:zzzz is related to the virbr0 MAC addr.
It's a really good idea not to use addresses from 2001:db8:dead:beef:fe::/96 outside of virbr0
IPv6 address and default route
The KVM IPv6 setup is static. You could install a IPv6 aware DHCP client but they tend to support all the IPv6 auto configuration. I have not tested any in a KVM, so its left as an exercise for the reader.
Choose an IPv6 address in the 2001:db8:dead:beef:fe::/96 prefix but not 2001:db8:dead:beef:fe::2 which is virbr0. There are plenty to choose from, and use it in your config_eth0= statement as in the example below.
You can still use dhcpcd for IPv4 if you wish.
# make sure use use iproute2 modules="iproute2" config_eth0="192.168.122.104/24 2001:db8:dead:beef:fe::8001/96" routes_eth0="default via 192.168.122.1 default via fe80::wwww:xxxx:yyyy:zzzz"
The default route is a bit harder. Its the virbr0 link address. You can discover that with the ping all routers multicast.
# ping6 ff02::2 -I eth0
PING ff02::2(ff02::2) from fe80::wwww:xxxx:yyyy:zzzz eth0: 56 data bytes 64 bytes from fe80::wwww:xxxx:yyyy:zzzz: icmp_seq=1 ttl=64 time=0.020 ms 64 bytes from fe80::aaaa:bbbb:cccc:dddd: icmp_seq=1 ttl=64 time=0.985 ms (DUP!) ...
In theory, you can use any router that responds. You should use virbr0 as its your next hop. That's the fe80::wwww:xxxx:yyyy:zzzz response.
When you are done restart the eth0 interface:
# /etc/init.d/net.eth0 restart
That should all work, test it.
For IPv4, test with:
# ping google.com -c3
PING google.com (188.8.131.52) 56(84) bytes of data. 64 bytes from fra02s27-in-f5.1e100.net (184.108.40.206): icmp_seq=1 ttl=55 time=22.8 ms 64 bytes from fra02s27-in-f5.1e100.net (220.127.116.11): icmp_seq=2 ttl=55 time=29.2 ms 64 bytes from fra02s27-in-f5.1e100.net (18.104.22.168): icmp_seq=3 ttl=55 time=26.3 ms --- google.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 22.823/26.131/29.265/2.639 ms
For IPv6, test with
# ping6 google.com -c3
PING google.com(fra02s27-in-x06.1e100.net) 56 data bytes 64 bytes from fra02s27-in-x06.1e100.net: icmp_seq=1 ttl=55 time=37.3 ms 64 bytes from fra02s27-in-x06.1e100.net: icmp_seq=2 ttl=55 time=26.7 ms 64 bytes from fra02s27-in-x06.1e100.net: icmp_seq=3 ttl=55 time=36.4 ms --- google.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 26.727/33.505/37.360/4.810 ms
That all looks good but its not quite working as it should.
You only have IPv4 name servers in /etc/resolv.conf. That may not matter, they will still return IPv6 addresses for host that have them. However, one day, (not soon) IPv4 will be switched off and your KVM will not be able to reach any nameservers /etc/resolv.conf can contain up to three IPv4 nameservers and three IPv6 nameservers. Copy over the IPv6 nameservers from the hosts /etc/resolv.conf or use some of the public IPv6 nameservers. Google has one.
Footnote for the curious
The 2001:db8::/32 prefix is reserved for use in documentation, its not supposed to be routable. You won't find any of my hosts there.