FS#35715 - [netctl] fails to start network inside Linux Container

Attached to Project: Arch Linux
Opened by John Lane (starfry) - Saturday, 08 June 2013, 10:54 GMT
Last edited by Jouke Witteveen (jouke) - Saturday, 17 November 2018, 12:03 GMT
Task Type Bug Report
Category Arch Projects
Status Closed
Assigned To Jouke Witteveen (jouke)
Architecture All
Severity Low
Priority Normal
Reported Version
Due in Version Undecided
Due Date Undecided
Percent Complete 0%
Votes 3
Private No

Details

Description:

Starting a netctl profile inside an LXC container fails because the unit file generated by netctl contains a dependency on a udev unit which will never exist because udev cannot run inside a Linux Container.

The solution is to for netctl to not add the dependency to the unit file that it writes if it is running inside LXC.

A patch file is attached that uses systemd-detect-virt to make this decision.

Additionally, the network interface inside the container is UP when the container starts and netctl will refuse to start if the interface is already up. The solution that I found to this problem was to add "ForceConnect=yes" to the profile (I could not find this option documented on the man page for netctl.profile so I don't know whether using it is the right thing to do).

Additional info:
* package version(s) netctl 1.1-1
* config and/or log files etc.




Steps to reproduce:

Create a container with a netctl profile. Use netctl to start the profile. It won't start.

Attempting to start directly with "/usr/lib/network/network start profile" will highlight the issue with the interface being up preventing start-up. This can be remedied with a "ip link set dev eth0 down" and then retrying. Also after bringing the interface down "netctl start profile" or "systemctl start netctl@profile" will also work. Add "ForceConnect=yes" to the profile to prevent this issue.
This task depends upon

Closed by  Jouke Witteveen (jouke)
Saturday, 17 November 2018, 12:03 GMT
Reason for closing:  None
Additional comments about closing:  Please reopen if this is still an issue.
Comment by John Lane (starfry) - Saturday, 08 June 2013, 13:04 GMT
I've been thinking about this and I'm not sure about the use of "ForceConnect=yes" - it feels like an override for something that is part of the standard workflow. I think it's better to make the code handle the case where it's in LXC and allow it to start without having to force it. I've done a quick test and a little patch to /usr/lib/network/network fixes it.

I also think the need to not depend on the udev interface covers more scenarios than lxc (e.g. running in a chroot, systemd-nspawn, etc) so rather than checking for systemd-detect-virt returning "lxc" I think it might be more approoriate to check when it does not return "none". I have attached a modified netctl patch for that.
Comment by Jouke Witteveen (jouke) - Sunday, 16 June 2013, 08:58 GMT
You could also do this with a hook that contains:

if [[ $(systemd-detect-virt) != none ]]; then
BindsToInterfaces=()
ForceConnect=yes
fi

These values can then still be overridden in profile files.
Comment by Stanislav Seletskiy (seletskiy) - Monday, 09 September 2013, 17:22 GMT
I've encountered same issue, but with Connection=vlan. It can't be fixed by proposed patches or hook because of /usr/lib/network/connections/vlan code, that contains:

[code]
if is_interface "$Interface"; then
report_error "Interface '$Interface' already exists"
return 1
else
bring_interface_up "$BindsToInterfaces"
ip link add link "$BindsToInterfaces" name "$Interface" type vlan id "$VLANID"
fi
[/code]

So, I've simply get "No unique physical device for VLAN interface 'eth0.2500' specified" error.
Comment by Jouke Witteveen (jouke) - Monday, 21 October 2013, 12:56 GMT
How about adding udev rules? Is that a possibility? I think the semantics of binding to interfaces you need are correct, so a patch would seem much like a hack.

About the usage of ForceConnect, this bug indeed indicates a valid use-case for it. It is documented in netctl >= 1.2.
Comment by Stanislav Seletskiy (seletskiy) - Friday, 25 October 2013, 07:59 GMT
jouke: what kind of udev rules? As far as I know, udev can't start in LXC container.
Comment by John Lane (starfry) - Friday, 25 October 2013, 10:48 GMT
that was my understanding as well, and the cause of the original issue (no udev = reason for dependency not being met).
Comment by Topo Lino (opotonil) - Monday, 17 February 2014, 20:45 GMT
"Additionally, the network interface inside the container is UP when the container starts and netctl will refuse to start if the interface is already up."

Have you tried to modify lxc configuration (/var/lib/lxc/[name]/config) and to remove "lxc.network.flags = up"?
Comment by John Lane (starfry) - Wednesday, 26 March 2014, 21:08 GMT
I've come back to this as a piece of work has landed me in the right place to devote a little time to it. I see the problem persists and have done some digging...

Re the suggestion of a hook

if [[ $(systemd-detect-virt) != none ]]; then
BindsToInterfaces=()
ForceConnect=yes
fi

This is executed and does what it says - it empties the BindsToInterfaces array. But it doesn't solve the problem because line 114 in netctl:

[[ -v BindsToInterfaces ]] || BindsToInterfaces=$Interface

which sets it to the named interface in the config.

The use of "ForceConnect" does work, however. But as per the suggestion above, isn't necessary if "lxc.network.flags = up" is removed from the container config.

I have also tried a systemd "drop-in" to unset the BindsTo but I can't get it to work either...

# cat /etc/systemd/system/netctl@.service.d/without_udev.conf
[Unit]
BindsTo=
After=

Comment by Joerg Gollnick (wurzelbenutzer) - Monday, 28 April 2014, 08:34 GMT
I run in a similar problem as starfry with a bridge outside a container.
My main issue is that test -v does not distinguish between an undefined BindsToInterfaces and an empty array.
Following patch solves it for me (unit_enable)
--- a/src/netctl.in
+++ b/src/netctl.in
@@ -111,7 +111,8 @@ unit_enable() {
echo ".include @systemdsystemunitdir@/netctl@.service" > "$unit"
echo -e "\n[Unit]" >> "$unit"
[[ -n $Description ]] && echo "Description=$Description" >> "$unit"
- [[ -v BindsToInterfaces ]] || BindsToInterfaces=$Interface
+ declare -p BindsToInterfaces >/dev/null 2>/dev/null
+ [[ $? -eq 1 ]] && BindsToInterfaces=$Interface
if (( ${#BindsToInterfaces[@]} )); then
: ${InterfaceRoot=sys/subsystem/net/devices/}
printf "BindsTo=$(sd_escape "$InterfaceRoot")%s.device\n" \


Comment by Jouke Witteveen (jouke) - Tuesday, 06 May 2014, 10:22 GMT
The problem of the last comment is fixed by commit b4f7b.

Loading...