12

I know, that I can assign static IP manually, using /etc/network/interfaces.

I also know, that I can read the MAC address of the LXC container (e.g. by looking for lxc.network.hwaddr entry in /var/lib/lxc/<container-name>/config and assign the IP based using entries dhcp-host=<mac-addr>,10.0.3.3 in /etc/dnsmasq.d/<some file>.

In the file /etc/default/lxc-net I read

# Uncomment the next line if you'd like to use a conf-file for the lxcbr0
# dnsmasq.  For instance, you can use 'dhcp-host=mail1,10.0.3.100' to have
# container 'mail1' always get ip address 10.0.3.100.
#LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

That would suit my needs; unfortunately doing so has no effect.

4
  • 2
    It works for me, but note that you have to restart lxc-net for it to take effect. And there is a known issue that lxc-net doesnt restart if any container is currently started. You need to stop all of them and then restart the lxc-net service.
    – HRJ
    Aug 19, 2014 at 14:28
  • Also, I was not able to assign ip-addresses using container name alone. I had to hard-code a MAC address for the container and for the DHCP configuration.
    – HRJ
    Aug 19, 2014 at 14:29
  • @HRJ, could you post your dnsmasq.conf file please?
    – tonytony
    Sep 2, 2014 at 11:22
  • @HRJ On Ubuntu 14.04 restarting lxc-net doesn't help if you don't remove your lxcbr0 bridge. See my answer. Oct 18, 2014 at 16:03

6 Answers 6

20

I ran into this recently and I think I found an easy solution. I (only) tested it on Ubuntu 14.04.

First, uncomment this line /etc/default/lxc-net:

LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

In /etc/lxc/dnsmasq.conf, define a dhcp-hostsfile:

dhcp-hostsfile=/etc/lxc/dnsmasq-hosts.conf

Then add entries in /etc/lxc/dnsmasq-hosts.conf like this:

mail,10.0.3.16
web,10.0.3.17

Beware: changes will become effective after you have restarted lxc-net (which restarts dnsmasq):

service lxc-net restart

Afterwards you can modify /etc/lxc/dnsmasq-hosts.conf and send the SIGHUP signal to dnsmasq:

killall -s SIGHUP dnsmasq

So yes, you need to restart lxc-net, but only once. Hope this helps.

6
  • I like the idea of delegating list of hosts to a external file. Besides that, your method differs from mine because of the killall -s SIGHUP dnsmasq. I agree, that just "SIGHUP-ing" dnsmasq is more efficient then restarting the whole daemon (especially if it doesn't work without patching its upstart scripts). Jan 8, 2015 at 9:51
  • Restarting the service lxc-net is only needed to let the dnsmasq use configuration from /etc/lxc/dnsmasq.conf (and this piece of information is present in the /etc/default/lxc-net which is unknown to the dnsmasq). If you had it set before, just another SIGHUP should suffice. Jan 8, 2015 at 9:53
  • Beware: lxc-net will not restart dnsmasq if there are running containers.
    – s3v3n
    Mar 9, 2015 at 10:34
  • IMO this is the best answer
    – s3v3n
    Mar 9, 2015 at 10:38
  • kill -HUP $(cat /var/run/lxc/dnsmasq.pid) if you don't want to install killall or reload other dnsmasq instances
    – gertas
    Nov 18, 2016 at 7:52
4

It works fine in Ubuntu 14.04.1

Uncomment this line /etc/default/lxc-net

#LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

stop all containers, restart lxc-net:

service lxc-net restart

Configure ip addresses in /etc/lxc/dnsmasq.conf

dhcp-host={NAME},10.0.3.2

where {NAME} is the name of your LXC container:

/var/lib/lxc/{NAME}
3
  • It works only if the script can shut down the lxcbr0 network, which excludes the case when there are other lxc containers running. In short, as it stands now, you cannot assign static dhcp leases without restarting all the containers. Nov 5, 2014 at 9:33
  • Yes, that true, it's quite inconvenient :(. I find much easier solution to edit /var/lib/lxc/<container-name>/rootfs/etc/network/interfaces file and assign static ip address to the container.
    – Tombart
    Nov 6, 2014 at 11:08
  • True, but then there is nothing to protect you against giving two guests the same IP. See my accepted answer - it solves the problem. Nov 6, 2014 at 11:36
1

The Tombart's answer works if you are patient enough to wait for the DNS refresh AND you are willing to restart the container (the guest) afterwards.

What follows is the recipe that requires that all other possibly running lxc containers are shut down. If you cannot afford that, then I see no way of forcing new dnsmasq configuration. (For some reasone signaling HUP to dnsmasq's pid found in /run/lxc/dnsmasq.pid doesn't work either.)

So if you want to have something that works instantly and there is no other lxc containers running, follow my answer. $name is the name of the node for which we want to reset the assignment, and $internalif is the name of the LXC's bridged adapter. You can get the value of the $internalif with e.g. augtool -L -A --transform "Shellvars incl /etc/default/lxc-net" get "/files/etc/default/lxc-net/LXC_BRIDGE" | sed -En 's/\/.* = (.*)/\1/p' if you install augeas-tools but usually it is just lxcbr0.

sudo lxc-stop -n $name >/dev/null
sudo service lxc-net stop >/dev/null
if [ -d /sys/class/net/$internalif ]; then
   sudo brctl delbr $internalif >/dev/null #Why? See below.
fi
sudo rm /var/lib/misc/dnsmasq.$internalif.leases
sudo service lxc-net start >/dev/null
sudo lxc-start -d -n $name >/dev/null
sleep 5

Unfortunately, there is a bug (feature?) in the /etc/init/lxc-net.conf in Ubuntu 14.04 that prevents reloading the dnsmasq unless the bridge device is down for the host.

0

This solution works by patching the lxc upstart scripts. It does split the complex task of bringing the lxcbr0 bridge up and starting a dnsmasq into two separate jobs. Now you don't need to restart the whole lxc-net bridge to just reload the dnsmasq - reloading the sudo service restart lxc-dnsmasq is sufficient and does not require shutting down the bridge.

  1. Stop the lxc-net service sudo service lxc-net stop and make sure there is no lxcbr0 (or equivalent) bridge up.
  2. Replace the contents of the /etc/init/lxc-net.conf with the following contents:

.

description "lxc network"
author "Serge Hallyn <[email protected]>"

start on starting lxc
stop on stopped lxc

env USE_LXC_BRIDGE="true"
env LXC_BRIDGE="lxcbr0"
env LXC_ADDR="10.0.3.1"
env LXC_NETMASK="255.255.255.0"
env LXC_NETWORK="10.0.3.0/24"
env varrun="/run/lxc"
env LXC_DOMAIN=""

pre-start script
    [ -f /etc/default/lxc ] && . /etc/default/lxc

    [ "x$USE_LXC_BRIDGE" = "xtrue" ] || { stop; exit 0; }

    use_iptables_lock="-w"
    iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
    cleanup() {
        # dnsmasq failed to start, clean up the bridge
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE || true
        iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
        ifconfig ${LXC_BRIDGE} down || true
        brctl delbr ${LXC_BRIDGE} || true
    }
    if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
        if [ ! -f ${varrun}/network_up ]; then
            # bridge exists, but we didn't start it
            stop;
        fi
        exit 0;
    fi

    # set up the lxc network
    brctl addbr ${LXC_BRIDGE} || { echo "Missing bridge support in kernel"; stop; exit 0; }
    echo 1 > /proc/sys/net/ipv4/ip_forward
    mkdir -p ${varrun}
    ifconfig ${LXC_BRIDGE} ${LXC_ADDR} netmask ${LXC_NETMASK} up
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
    iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
    iptables $use_iptables_lock -I FORWARD -i ${LXC_BRIDGE} -j ACCEPT
    iptables $use_iptables_lock -I FORWARD -o ${LXC_BRIDGE} -j ACCEPT
    iptables $use_iptables_lock -t nat -A POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE
    iptables $use_iptables_lock -t mangle -A POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill

    touch ${varrun}/network_up
end script

post-stop script
    [ -f /etc/default/lxc ] && . /etc/default/lxc
    [ -f "${varrun}/network_up" ] || exit 0;
    # if $LXC_BRIDGE has attached interfaces, don't shut it down
    ls /sys/class/net/${LXC_BRIDGE}/brif/* > /dev/null 2>&1 && exit 0;

    if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
        use_iptables_lock="-w"
        iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
        ifconfig ${LXC_BRIDGE} down
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
        iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE || true
        iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
        pid=`cat ${varrun}/dnsmasq.pid 2>/dev/null` && kill -9 $pid || true
        rm -f ${varrun}/dnsmasq.pid
        brctl delbr ${LXC_BRIDGE}
    fi
    rm -f ${varrun}/network_up
end script
  1. Add another file, /etc/init/lxc-dnsmasq with the following contents:

.

description "lxc dnsmasq service"
author "Adam Ryczkowski, ispired by Serge Hallyn <[email protected]>"

expect fork

start on started lxc-net
stop on stopped lxc-net

env USE_LXC_BRIDGE="true"
env LXC_BRIDGE="lxcbr0"
env LXC_ADDR="10.0.3.1"
env LXC_NETMASK="255.255.255.0"
env LXC_NETWORK="10.0.3.0/24"
env LXC_DHCP_RANGE="10.0.3.2,10.0.3.254"
env LXC_DHCP_MAX="253"
env LXC_DHCP_CONFILE=""
env varrun="/run/lxc-dnsmasq"
env LXC_DOMAIN=""

pre-start script
    [ -f /etc/default/lxc ] && . /etc/default/lxc

    [ "x$USE_LXC_BRIDGE" = "xtrue" ] || { stop; exit 0; }

    if [ ! -d ${varrun} ]; then
        mkdir -p ${varrun}
    fi
    opts="$LXC_DOMAIN_ARG -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=${varrun}/dnsmasq.pid --conf-file=${LXC_DHCP_CONFILE} --listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} --dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override --except-interface=lo --interface=${LXC_BRIDGE} --dhcp-leasefile=/var/lib/misc/dnsmasq2.${LXC_BRIDGE}.leases --dhcp-authoritative --keep-in-foreground"

    /usr/sbin/dnsmasq $opts &

end script

post-stop script
    if [ -f ${varrun}/dnsmasq.pid ]; then
        PID=`cat ${varrun}/dnsmasq.pid`
        kill $PID
    fi
end script
0

Here is simple python script which releases LXC dnsmasq lease. You can run it from host machine or forge it from another container - yes that works!:

#!/usr/bin/env python
from scapy.all import *
conf.checkIPaddr=False
leaseMAC = '00:16:3e:11:71:b0' #container MAC here
releaseIP='10.0.3.33' #container IP here
serverIP='10.0.3.1'
hostname='container-name-here'
rawMAC = leaseMAC.replace(':','').decode('hex')
send(IP(dst=serverIP) / \
     UDP(sport=68,dport=67) / \
     BOOTP(chaddr=rawMAC, ciaddr=releaseIP, xid=RandInt()) / \
     DHCP(options=[('message-type','release'),('server_id',serverIP),('hostname',hostname), ('end')]))

The perequisite for above is scapy python library:

pip install scapy

Once run you should see in system log something like:

dnsmasq-dhcp[3242]: DHCPRELEASE(lxcbr0) 10.0.3.33 00:16:3e:11:71:b0 container-name-here

To confirm just check if entry is removed from /var/lib/misc/dnsmasq.lxcbr0.leases. The container itself will keep the IP so it should be stopped before starting any new container which should reuse the IP.

1
  • 1
    That's cool! I didn't even know that DHCP supports that! I will upvote immediately after I confirm it works. Dec 16, 2016 at 9:34
0

I realize my answer is years late, but maybe it helps someone else. The issue was that you edited code specific to the LXC Ubuntu package (write_lxc_net function) that was meant to be written to another destination as a string, not processed within the lxc-net script itself!

As a result, the dnsmasq process didn't receive the config file you tried to tried to pass it, leaving you with "no effect", as you say.

Instead, you'd want to set this variable near the top of the script, among the rest:

#!/bin/sh -

distrosysconfdir="/etc/default"
varrun="/run/lxc"
varlib="/var/lib"

# These can be overridden in /etc/default/lxc
#   or in /etc/default/lxc-net

USE_LXC_BRIDGE="true"
LXC_BRIDGE="lxcbr0"
LXC_BRIDGE_MAC="00:16:3e:00:00:00"
LXC_ADDR="10.0.3.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.3.0/24"
LXC_DHCP_RANGE="10.0.3.2,10.0.3.254"
LXC_DHCP_MAX="253"
LXC_DHCP_CONFILE="/etc/lxc/dnsmasq.conf"   <-- Here for instance
LXC_DOMAIN=""

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .