Forget the network card as a specific hardware. Just consider you have a network interface and it has to be moved to a container. This is not USB or PCI pass-through. Let's call it interface pass-through and it's specifically handled by the network namespace logic using for example ip link
:
netns NETNSNAME | PID
move the device to the network namespace associated with name NETNSNAME or process PID.
Some devices are not allowed to change network namespace: loopback, bridge, ppp, wireless. These are network namespace local
devices. In such case ip tool will return "Invalid argument" error. It
is possible to find out if device is local to a single network
namespace by checking netns-local
flag in the output of the ethtool
:
ethtool -k DEVICE
To change network namespace for wireless devices the iw
tool can be used. But it allows to change network namespace only for physical
devices and by process PID.
The interface has to appear initially on the host, but you can move it to the container. There's no option to have it directly appear in a container when plugged (of course at container start, with a specific configuration for the container, the interface can be moved, see later), but it's probably scriptable with udev
. Moreover, the kernel being unique across host and containers, the host, even if not using network at all, must of course have all required network options compiled-in and is still in charge of loading relevant kernel modules if needed (it's usually transparently done).
So if in the end your card is called eth0
on the host and is really ethernet (not wireless), this command will move it to the target namespace:
ip link set eth0 netns NETNSNAME
Where NETNSNAME can be either a pid of a process in the target network namespace or a network namespace "mounted" and handled by ip netns add NETNSNAME
as described above.
For two common container technology, LXC and Docker, here's how to replace NETNSNAME with a target container named containername
:
LXC:
ip link set eth0 netns $(lxc-info -H -p -n containername)
Docker:
ip link set eth0 netns $(docker inspect --format '{{.State.Pid}}' containername)
For wireless the (not very well documented) command would be if there's only one wireless interface, then clearly associated with phy0
:
iw phy phy0 set netns $(lxc-info -H -p -n containername)
But this will work only if the driver supports it, displaying this:
# iw phy0 info|grep netns
* set_wiphy_netns
This should probably not be done manually with the commands above, but with the specific container's configuration (LXC, Docker...). Eg, for LXC 3.0 (syntax changed from LXC 2.x) the configuration file would include lines like:
lxc.net.1.type = phys
lxc.net.1.link = eth0
Same config will handle ethernet or wireless.
and whenever the container is started, the interface would be swallowed by the container. When the container (more precisely its network namespace) stops, the interface is returned to the host (there's no way to return it to an other container directly).
Wireguard describes some use cases.