Connecting a Cloud Hypervisor guest to the internet using NAT

Cloud Hypervisor is a Virtual Machine Monitor (VMM) for modern cloud workloads. Recently, I found myself in the need of a simple way to connect a Cloud Hypervisor guest to the internet. Unfortunately, no such method has been documented in the in-tree documentation. So, I set out experimenting with iptables and NAT (network address translation). After playing around with the iptables rules required to set this up I finally arrived at a simple setup that worked.

For this to work, Cloud Hypervisor needs to be started with the --net argument like so:

cloud-hypervisor \
        --kernel ./vmlinux.bin \
        --cmdline "console=ttyS0 root=/dev/vda1 rw" \
        --disk path=/home/cloud/focal-server-cloudimg-amd64.raw path=/home/cloud/ubuntu-cloudinit.img \
        --cpus boot=8 \
        --memory size=0 \
        --memory-zone id=mem0,size=4G,host_numa_node=0 \
        --net "tap=,mac=12:34:56:78:90:ab,ip=192.168.249.1,mask=255.255.255.0" \
        --serial tty \
        --console off

When tap=  is left empty, Cloud Hypervisor will create a tap device with the default naming vmtapN where N is 0,1,2,3 and so on. mac= can be any valid MAC address. The ip= value will later be the default gateway IP for the guest.

Let's say the host is connected to the internet via the eth0 interface. We need to define iptables rules to enable traffic to be routed between vmtap0 and eth0. Here are the rules:

sudo iptables -A INPUT -i vmtap0 -j ACCEPT
sudo iptables -A INPUT -i vmtap0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

sudo iptables -A FORWARD -i eth0 -o vmtap0 -j ACCEPT
sudo iptables -A FORWARD -i vmtap0 -o eth0 -j ACCEPT

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Next, configure a static IP for the guest via cloud-init. Here are the contents of my cloud-init network-config file:

version: 2
ethernets:
  id0:
    match:
       macaddress: 12:34:56:78:90:ab
    addresses: [192.168.249.55/24]
    gateway4: 192.168.249.1

The above file configures 192.168.245.55 as the guest IP.

The last thing to do is to configure a DNS server in the guest (/etc/resolv.conf). Configure any public DNS server you like.

And that's it! The guest should now be able to connect to the internet.

Comments

Popular posts from this blog

Problem discussion: ShufflingCardsDiv2 - Topcoder SRM 641 900pt

Introduction to tries through Facebook Hacker Cup 2015 Round 1 - Autocomplete

Problem discussion: Facebook Hacker Cup 2015 Round 1 - Homework