LXD bridge not responding to DHCP?

Due to my issues getting static IPv6 addresses to work, I want to test SLAAC instead.

Since I think it doesn’t seem right to have these random-looking SLAAC addresses mixed with statically assigned IPv4 addresses, I want to switch to DHCP for IPv4.

I recall this being the “just works” default in LXD, but maybe that’s with Ubuntu containers. The host is running LXD 3.21 snap btw.

To be sure, I deleted my old bridge and created a new one without any customizations.

lxc network delete lxdbr0
lxc network create lxdbr5
lxc init images:alpine/3.11/amd64 a2
lxc network attach lxdbr5 a2
lxc start a2

The container unreliably acquires and IPv6 (presumably SLAAC) without me doing anything. The container does not however acquire an IPv4 address.

a2/etc/network/interfaces (default):

auto eth0
iface eth0 inet dhcp
hostname $(hostname)

When I restart a2’s network, it looks like it gets no DHCP response:

rc-service networking restart
 * Stopping networking ...
 *   eth0 ...                                                                                                                                   [ ok ]
 * Starting networking ...
 *   eth0 ...
udhcpc: started, v1.31.1
udhcpc: sending discover
udhcpc: sending discover
udhcpc: sending discover
udhcpc: sending discover
udhcpc: sending discover
udhcpc failed to get a DHCP lease
udhcpc: no lease, forking to background

It then keeps sending BOOTPC queries in the background to no avail.

Setting a static IP in a2/etc/network/interfaces works fine:

iface eth0 inet static
  address 10.42.0.88
  netmask 255.255.255.0
  gateway 10.42.0.1

Any idea what’s going on? Do Alpine containers require additional manual configuration? As I mentioned, I recall LXD forcing random addresses (IPv4 included) onto my containers in the past, and now I can’t even coax it to do so.

huh, did you forget to include something in your post ? how is it supposed to work if your default profile does not reference lxdbr5 ? I did not think it was even possible to delete a network (lxdbr0) that should be referenced in the default profile…

If you want to not use ipv6 at all, all you have to do is to include in your network definition (lxc edit network lxdbr5)

ipv6.address: none

and if you want dhcp4 you have to include it explicitly in a network you create, such as

ipv4.dhcp: “true”

The default profile doesn’t contain a bridge (since I’m testing), that’s why I attach the bridge manually.

If you want to not use ipv6 at all

That was my approach in the past, along with static IPv4 addresses, but I want to include IPv6 in my setups from now on as it becomes ubiquitous.

and if you want dhcp4 you have to include it explicitly in a network you create, such as

ipv4.dhcp: “true”

Believe me, I have tried. The documentation also states that this setting is enabled by default.

yes I missed that.
what is in lxc network edit lxdbr5 then ?

Don’t know why it works fine with default config, default Alpine container fresh from the factory then :wink:

NOTE: I think I may have found the issue, don’t expend any time on this until I report back! I need to test a few things to be sure.

Bloody hell, it was the firewall!

  1. Since I didn’t use DHCP prior, I had never thought about BOOTP traffic before!
  2. Moving my LXD experiments from my workstation to an (internet connected) server, I forgot to adapt the rules accordingly, punch the right holes through etc.
  3. Make sure to give yourself ample rest, productivity tanks and errors skyrocket when overworked.

I now have LXD related rules along those lines:

define lxd_bridge = "lxdbr0"
define lxd_subnet_ip = 10.100.0.0/24 
define lxd_subnet_ip6 = fd42:abbe:1234:5678::1/64 

table inet Filter {
    chain In {
        type filter hook input priority 0; policy drop

        (…)

        # DHCP (crucial line below, totally new to me)
        iifname $lxd_bridge ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp dport bootps accept
        iifname $lxd_bridge ip6 saddr fe80::/64 accept

        # DNS
        iifname $lxd_bridge ip saddr $lxd_subnet_ip udp dport domain accept
        iifname $lxd_bridge ip saddr $lxd_subnet_ip tcp dport domain accept
    }
}

table ip Nat4 {
    chain Pre {
        type nat hook prerouting priority 0
    }

    chain Post {
        type nat hook postrouting priority 0

        ip saddr $lxd_subnet_ip ip daddr != $lxd_subnet_ip masquerade
    }
}

table ip6 Nat6 {
    chain Pre {
        type nat hook prerouting priority 0
    }

    chain Post {
        type nat hook postrouting priority 0

        ip6 saddr $lxd_subnet_ip6 ip6 daddr != $lxd_subnet_ip6 masquerade
    }
}

Now the containers acquire IPs, automatically set their nameservers to the bridge IP (where Dnsmasq listens), and generally behave in a more predictable way.

I’ll also move away from manual IP assignment for good now, unless a special case requires it.

Thanks a lot @gpatel-fr and @tomp for the help here and in the other thread!

Edit: Fixed IPv6 DHCP, now SLAAC is fast as well.

Ah well you are using nftables.
And LXD 3.21 does NOT support it. That’s always the trick to relying on the fact that an issue is closed, it may not yet be applied to current release.

Indeed.

The next version of LXD will include nftables support, so when you upgrade you may find that you don’t need the rules that allow DHCP and DNS, you can see the sort of rules it will configure here:

1 Like