diff --git a/content/en/docs/getting-started.md b/content/en/docs/getting-started.md index b9aef54..fd5ac39 100644 --- a/content/en/docs/getting-started.md +++ b/content/en/docs/getting-started.md @@ -17,7 +17,9 @@ description: >- `lowerdir+=`). Without it images are extracted as flat directories. - **iproute2** and **nftables** (`ip` and `nft`) for the bridge network. Nothing else: the bridge does not need systemd-networkd or NetworkManager on the host. - Only `--network veth` needs systemd-networkd. + Only `--network veth` needs systemd-networkd, and only `--interface` with a + wifi adapter needs `iw` (for an app on the bridge) or systemd 256 (for a + booted machine). - **Root, or an administrator with polkit.** Every command is a call to the [service](/docs/overview/#the-service) on the system bus, which asks polkit who you are: root is never asked, an administrator is asked for a password, diff --git a/content/en/docs/machines.md b/content/en/docs/machines.md index 2ddd766..578b4ce 100644 --- a/content/en/docs/machines.md +++ b/content/en/docs/machines.md @@ -386,6 +386,10 @@ its unit: - `--sysctl KEY=VALUE`: `net.*` keys, set in the network namespace nspawn makes for an app machine on a bridge network. Nothing else is accepted, and a booted machine sets its own. +- `--interface IFACE`: a network interface of the host, moved into the + machine while it runs and back on the host when it stops, a wifi adapter + with its whole phy included; no docker counterpart. See [Physical + interfaces](/docs/networking/#physical-interfaces). A list takes `none` to forget it (`--cap-drop none`, `--tmpfs none`), a value an empty string (`--hostname ""`) or `0` (`--oom-score-adj 0`), and diff --git a/content/en/docs/networking.md b/content/en/docs/networking.md index afdfad7..d9ba46d 100644 --- a/content/en/docs/networking.md +++ b/content/en/docs/networking.md @@ -259,6 +259,66 @@ sudo nspawn run -d docker.io/qmcgaw/gluetun --name vpn --cap-add NET_ADMIN --dev sudo nspawn run -d docker.io/library/nginx:1.27 --name web --network container:vpn ``` +## Physical interfaces + +`--interface IFACE` on `run`, `create` and `start` gives a machine a network +interface of the host, whole: a second ethernet port, or a wifi adapter for a +machine doing wireless work. `--device` cannot do it, since a network interface +is not a node under `/dev`, and `--network host` cannot either: the machines +run in a user namespace, which may not configure the host's interfaces. The +interface is moved into the machine's network namespace before its program or +init runs and is back on the host when the machine stops or is removed, with +its name kept on both sides, as systemd-nspawn's `Interface=` and LXC's `phys` +type do it. It arrives down and unconfigured, as the kernel moves it: the +machine brings it up and configures it, with `ip` in an app or its +systemd-networkd in a booted machine. The flag is repeatable and remembered +like the rest, `--interface none` forgets them, and `inspect` lists them as +`interfaces`. + +```shell +sudo nspawn run -d kali:latest --name kali --interface wlp11s0f3u2u3 +sudo nspawn exec kali -- iw dev +sudo nspawn stop kali # the adapter is back on the host +``` + +Where systemd-nspawn makes the machine's network namespace (a booted machine, +on the bridge or with veth, and any machine with `--network none`) the +interface goes into the machine's settings file as `Interface=` and +systemd-nspawn moves it at start and back at exit. An app machine on a bridge +network gets its namespace from nspawn itself (`NamespacePath=`, which allows +no `Interface=` beside it), so the unit's hooks move the interface in with `ip` +before systemd-nspawn runs and give it back after; such an app runs without a +user namespace, so `iw reg set` and monitor mode work inside as on the host. +Either way the unit waits for the interface's device unit, so that a machine +started at boot waits for a USB adapter udev has not seen yet. + +A wifi adapter cannot leave its phy, so the phy moves whole, every interface it +carries with it (nspawn says which), and a driver without namespace support +(`ath6kl`, `wilc1000`) refuses the move naming the phy. An app on the bridge +takes a wireless interface on any systemd, through `iw`, which has to be +installed on the host; `Interface=` moves a phy since systemd 256, so on an +older host a wireless interface is refused for a booted machine or one with +`--network none`, with a message that says so. The regulatory domain (`iw reg +set`) and rfkill are host-wide: they are set on the host, or from an app on +the bridge; `--device /dev/rfkill` hands the switch to such an app. + +One machine at a time takes an interface: a second one naming it is refused +while the first runs (`stop` it, or start it with `--interface none`). Refused +as well: `lo`, the bridges and veth ends of nspawn's own, a port of a bridge or +bond (`ip link set IFACE nomaster` first), a name that is not on the host (a +machine that ended a moment ago may still hold it: the kernel gives interfaces +back a little after their namespace dies), a machine with `--network host`, one +with `--network container:NAME` (give the interface to `NAME`) and the mstack +backend. The interface of the host's default route is allowed with a warning, +since the host loses its route while the machine runs. When the interface +comes back, NetworkManager or systemd-networkd manage it again as before, and +a name taken on the host in the meantime makes the kernel rename it (`dev0`, +`wlan0`). `stop --force` kills the machine: an app on the bridge still gets +every interface back from its release hook, while a machine that took them +through `Interface=` may not get to give them back, and the kernel then +returns a physical interface or a wifi phy a moment later and destroys a +virtual one (a VLAN, a macvlan, a dummy) with the namespace. + Behind the scenes the service binds the name systemd-nspawn looks for (`/run/netns/nspawn-web`) to the network namespace of `vpn`'s leader process, the mount `ip netns attach` would make, so the settings are the ones of any diff --git a/content/en/docs/reference.md b/content/en/docs/reference.md index 8f371b2..cfd86f9 100644 --- a/content/en/docs/reference.md +++ b/content/en/docs/reference.md @@ -121,7 +121,7 @@ size, speed and time left; in a pipe or a log only the lines are written. nspawn create SOURCE NAME [--backend BACKEND] [--network NETWORK]... [--network-alias [NETWORK=]NAME]... [-p [IP:]HOST:CONTAINER[/udp]]... [--entrypoint PROGRAM] [-e VAR[=VALUE]]... [-v SOURCE:TARGET[:ro]]... [-l KEY=VALUE]... [--restart POLICY] [-m SIZE] [--cpus N] - [--pids-limit N] [HEALTHCHECK OPTIONS] [OTHER OPTIONS] [--secret SECRET]... + [--pids-limit N] [HEALTHCHECK OPTIONS] [OTHER OPTIONS] [--interface IFACE]... [--secret SECRET]... [-f] [--no-verify] [-- ARGUMENTS...] ``` @@ -142,7 +142,7 @@ the image's own name, as `run` does. The layers are shared with the source. | `-v`, `--volume SOURCE:TARGET[:ro]` | Mount a host directory or a named volume, like `docker -v`. | | `-l`, `--label KEY=VALUE` | Label the machine, on top of the image's own labels, like `docker --label`. Not inherited from the source. | | `--restart`, `-m`, `--cpus`, `--pids-limit` | Restart policy and limits, as for [start](#start). Not inherited from the source. | -| the healthcheck options, the other options, `--secret` | As for [start](#start). Not inherited from the source. | +| the healthcheck options, the other options, `--interface`, `--secret` | As for [start](#start). Not inherited from the source. | | `-f`, `--force` | Replace an existing machine with the same name. | | `--no-verify` | Skip the signature check of an image that has to be pulled (a local source is not checked); like docker's `--disable-content-trust`. | | `-- ARGUMENTS...` | App images: replace the image's cmd; they follow its entrypoint, as with docker. | @@ -268,7 +268,8 @@ nspawn start NAME [--network NETWORK]... [--network-alias [NETWORK=]NAME]... [-p [--device HOST[:CONTAINER[:PERMISSIONS]]]... [--dns ADDRESS]... [--dns-search DOMAIN]... [--add-host HOST:IP]... [--ulimit NAME=SOFT[:HARD]]... [--oom-score-adj N] [--stop-signal SIGNAL] [--stop-timeout SECONDS] [--init] [--sysctl KEY=VALUE]... - [--secret NAME[:TARGET[:MODE[:UID:GID]]]]... [--image-command] [--no-wait] [-- ARGUMENTS...] + [--interface IFACE]... [--secret NAME[:TARGET[:MODE[:UID:GID]]]]... [--image-command] [--no-wait] + [-- ARGUMENTS...] ``` Boots an image as a machine. Every option is remembered for the next start. @@ -312,6 +313,7 @@ Boots an image as a machine. Every option is remembered for the next start. | `--stop-timeout SECONDS` | Seconds `stop` waits after the signal before SIGKILL, unless `-t` says otherwise. Default: 10. | | `--init` | Accepted for docker's sake: nspawn's stub init reaps orphans anyway. App images only. | | `--sysctl KEY=VALUE` | A `net.*` sysctl for an app machine's network namespace. Repeatable; `none` forgets them. | +| `--interface IFACE` | A network interface of the host, moved into the machine while it runs and given back when it stops: an ethernet one, or a wifi adapter with its whole phy (`iw` on the host for an app on the bridge, systemd 256 for a booted machine); the name is kept inside. Not with `--network host` or `container:NAME`; one machine at a time. See [Physical interfaces](/docs/networking/#physical-interfaces). Repeatable; `none` forgets them. | | `--secret NAME[:TARGET[:MODE[:UID:GID]]]` | A secret made with [secret create](#secret-create) as a read-only file inside the machine, like docker's `--secret`: `NAME` alone is `/run/secrets/NAME` with mode 0444, root's. Repeatable; `none` forgets them. Not on `mstack` machines. | | `--image-command` | Forget the remembered entrypoint and arguments and run the image's own again. | | `--no-wait` | Do not wait for a booted machine's init to be up before returning. Its registration is still awaited, so that ports and firewall rules can be applied. | @@ -353,7 +355,7 @@ image shows its console until it powers off, and Ctrl-C powers it off. | `--mode auto\|boot\|app` | As for `pull`; a mode other than `auto` always pulls. | | `-f`, `--force` | Make the machine anew when one of that name exists; it must be stopped. | | `--no-verify` | Skip the signature check of the image, as for `pull`. | -| the options of `start` | `--network`, `--network-alias`, `-p`, `--entrypoint`, `-e`, `-v`, `-l`, `--restart`, `-m`, `--cpus`, `--pids-limit`, the healthcheck options, the other options, `--secret` and `--no-wait` (with `-d` only), as for [start](#start). Options may come before or after the reference, as long as they come before the command. | +| the options of `start` | `--network`, `--network-alias`, `-p`, `--entrypoint`, `-e`, `-v`, `-l`, `--restart`, `-m`, `--cpus`, `--pids-limit`, the healthcheck options, the other options, `--interface`, `--secret` and `--no-wait` (with `-d` only), as for [start](#start). Options may come before or after the reference, as long as they come before the command. | ## stop diff --git a/hugo.yaml b/hugo.yaml index c7af227..7c40db3 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -53,7 +53,7 @@ params: privacy_policy: /about/#privacy # Version of nspawn the documentation describes. - version: 1.5.1 + version: 1.6.0 archived_version: false # In-page links to open issues and suggest changes.