astro / microvm.nix

NixOS MicroVMs
https://astro.github.io/microvm.nix/
MIT License
1.24k stars 93 forks source link

interface `type = "tap"` not working out of the box #247

Closed Ramblurr closed 3 months ago

Ramblurr commented 3 months ago

I followed the simple networking docs, but had the experience that the tap network was not working out of the box.

My host's bridge device is brprim4. This was my interfaces config for the guest:

interfaces = [{
  type = "tap";
  id = "my-microvm";
  mac = "02:00:00:00:00:01";
}]

I inspected the microvm-tap-interfaces@ service and saw that it wasn't setting the master iface (my bridge) for the tuntap device.

Workaround

So I overrode the service's script with:

systemd.services."microvm-tap-interfaces@" = {
script = lib.mkForce ''
    cd ${config.microvm.stateDir}/$1
    TAP_FLAGS="$(cat current/share/microvm/tap-flags)"

    for id in $(cat current/share/microvm/tap-interfaces); do
    if [ -e /sys/class/net/$id ]; then
        ${pkgs.iproute2}/bin/ip tuntap del name $id mode tap $TAP_FLAGS
    fi

    ${pkgs.iproute2}/bin/ip tuntap add name $id mode tap user microvm $TAP_FLAGS
    ${pkgs.iproute2}/bin/ip link set $id up
    ${pkgs.iproute2}/bin/ip link set $id master brprim4    # <---- I added this line
    done
'';
};

Then I restarted my-microvm and networking to the guset worked as advertised!

In the working case, ip link shows:

22: my-microvm: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master brprim4 state UP mode DEFAULT group default qlen 1000
    link/ether 3a:84:d4:6f:f4:ae brd ff:ff:ff:ff:ff:ff

.. notice the master brprim4 option, that is the bridge on my host.

Compare that to what ip link shows when the master option isn't set:

21: my-microvm: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 3a:84:d4:6f:f4:ae brd ff:ff:ff:ff:ff:ff

Why Me?

Why is this happening to me and not others following the docs?

I suspect because I have a more complicated network setup on my host. I have several vlans and other bridges for other activities. But I'm also not sure, I've never created a tuntap device and not specified a master, so I'm not sure what the default behavior is.

Proposal

I would propose adding a tap.link (or tap.master?) option to the tap config, similiar to macvtap.link for the macvtap type. For example:

interfaces = [{
  type = "tap";
  id = "my-microvm";
  mac = "02:00:00:00:00:01";
  tap.link = "brprim4";
}]
astro commented 3 months ago

There are many ways to do this. So far, I've been solving this with systemd-networkd.

Sure, we already support qemu's bridge helper but I fear that modelling too much host network configuration is broadening the scope too much for this VM abstraction project.

As a compromise I'm open to make this extensible with a script option.

Ramblurr commented 3 months ago

but I fear that modelling too much host network configuration is broadening the scope too much for this VM abstraction project.

I agree with this 💯.

Instead of providing extra options for the existing systems sibling services that setup host networking, if you exposed a module options for users to include their own required systems services? On the other hand it's relatively simple to override that, so maybe that also isn't necessary.

Ramblurr commented 3 months ago

Actually this is likely a case of PEBKAC, I missed one bit in my host's networkd config (I already had the bridge existing so I didn't bother changing it).

That is I forgot to edit the matchConfig.Name to include the microvms' ifaces, which you've already clearly documented:

image