Running dhcpcd under LXC
I’ve been working with Arch Linux recently, which uses dhcpcd
as its default DHCP agent. If you try booting Arch inside an LXC
container, you will find that dhcpcd
is unable to configure your
network interfaces. Running it by hand you will first see the
following error:
# dhcpcd eth0
dhcpcd[492]: version 5.6.4 starting
dhcpcd[492]: eth0: if_init: Read-only file system
dhcpcd[492]: eth0: interface not found or invalid
This happens because dhcpcd
is trying to modify a sysctl value.
Running dhcpcd
under strace
we see:
open("/proc/sys/net/ipv4/conf/eth0/promote_secondaries", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 EROFS (Read-only file system)
This happens because /proc
is typically mounted read-only in a
container environment (to prevent the container from modifying things
that would potentially affect the host system).
We can use a “bind mount” to solve this problem. A “bind mount”
allows you to mount part of a filesystem on another part of the
filesystem. In this case, we’re going to mask that value in /proc
by bind mounting a file on top of it.
First, we create the file we’ll use as a mask:
# echo 0 > /var/tmp/promote_secondaries
Then we mount in on top of the
/proc
entry:# mount -o bind /var/tmp/promote_secondaries \ /proc/sys/net/ipv4/conf/eth0/promote_secondaries
And now that /proc
value is “writable” from the perspective of
dhcpcd
. If we try to run dhcpcd
now, we see:
# dhcpcd eth0
dhcpcd[770]: version 5.6.4 starting
dhcpcd[770]: eth0: sending IPv6 Router Solicitation
dhcpcd[770]: eth0: rebinding lease of 192.168.117.53
dhcpcd[770]: eth0: acknowledged 192.168.117.53 from 192.168.117.1
dhcpcd[770]: eth0: checking for 192.168.117.53
dhcpcd[770]: eth0: sending IPv6 Router Solicitation
dhcpcd[770]: eth0: leased 192.168.117.53 for 3600 seconds
dhcpcd[770]: forked to background, child pid 796
If you are running dhcpcd
via the dhcpcd@.service
unit, then you
can automate this masking with the following service unit:
[Unit]
Description=Mask read-only /proc entries for %I.
RequiredBy=dhcpcd@%I
Before=dhcpcd@%I
[Service]
ExecStartPre=/bin/dd if=/proc/sys/net/ipv4/conf/%I/promote_secondaries \
of=/var/tmp/promote_secondaries_%I
ExecStart=/bin/mount -o bind /var/tmp/promote_secondaries_%I \
/proc/sys/net/ipv4/conf/%I/promote_secondaries
RemainAfterExit=yes
ExecStop=/bin/unmount /proc/sys/net/ipv4/conf/%I/promote_secondaries
[Install]
WantedBy=multi-user.target
If you see…
/usr/lib/dhcpcd/dhcpcd-hooks/30-hostname: line 17: /proc/sys/kernel/hostname: Read-only file system
…you may need to do something similar to mask the kernel.hostname
entry in /proc
, although this will need to be done once rather than
per-interface. Alternatively, you can modify the hook script
responsible for setting the hostname
(/usr/lib/dhcpcd/dhcpcd-hooks/30-hostname
).