From bcfd618a316097e5d2e1a20703b11beeb21b6899 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 19 Feb 2022 04:54:09 +0100 Subject: [PATCH] libpod: Add pasta networking mode Conceptually equivalent to networking by means of slirp4netns(1), with a few practical differences: - pasta(1) forks to background once networking is configured in the namespace and quits on its own once the namespace is deleted: file descriptor synchronisation and PID tracking are not needed - port forwarding is configured via command line options at start-up, instead of an API socket: this is taken care of right away as we're about to start pasta - there's no need for further selection of port forwarding modes: pasta behaves similarly to containers-rootlessport for local binds (splice() instead of read()/write() pairs, without L2-L4 translation), and keeps the original source address for non-local connections like slirp4netns does - IPv6 is enabled by default, it's not an experimental feature. It can be disabled using additional options as documented - by default, addresses and routes are copied from the host, that is, container users will see the same IP address and routes as if they were in the init namespace context. The interface name is also sourced from the host upstream interface with the first default route in the routing table. This is also configurable as documented - by default, the host is reachable using the gateway address from the container, unless the --no-map-gw option is passed - sandboxing and seccomp(2) policies cannot be disabled See https://passt.top for more details about pasta. Signed-off-by: Stefano Brivio --- SPDX-FileCopyrightText: 2021-2022 Red Hat GmbH SPDX-License-Identifier: Apache-2.0 docs/source/markdown/podman-create.1.md | 40 ++++++++++++- docs/source/markdown/podman-pod-create.1.md | 33 +++++++++++ docs/source/markdown/podman-run.1.md | 38 +++++++++++- docs/source/markdown/podman.1.md | 6 +- libpod/networking_linux.go | 6 +- libpod/networking_pasta.go | 64 +++++++++++++++++++++ pkg/namespaces/namespaces.go | 6 ++ pkg/specgen/generate/namespaces.go | 10 ++++ pkg/specgen/generate/pod_create.go | 6 ++ pkg/specgen/namespaces.go | 18 +++++- pkg/specgen/podspecgen.go | 2 +- 11 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 libpod/networking_pasta.go diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 2a0f3b738..5cc03bff3 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -699,12 +699,19 @@ Valid _mode_ values are: - **interface_name**: Specify a name for the created network interface inside the container. For example to set a static ipv4 address and a static mac address, use `--network bridge:ip=10.88.0.10,mac=44:33:22:11:00:99`. + - \[:OPTIONS,...]: Connect to a user-defined network; this is the network name or ID from a network created by **[podman network create](podman-network-create.1.md)**. Using the network name implies the bridge network mode. It is possible to specify the same options described under the bridge mode above. You can use the **--network** option multiple times to specify additional networks. + - **none**: Create a network namespace for the container but do not configure network interfaces for it, thus the container has no network connectivity. + - **container:**_id_: Reuse another container's network stack. + - **host**: Do not create a network namespace, the container will use the host's network. Note: The host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. + - **ns:**_path_: Path to a network namespace to join. + - **private**: Create a new namespace for the container. This will use the **bridge** mode for rootfull containers and **slirp4netns** for rootless ones. + - **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options: - **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`, which is added to `/etc/hosts` as `host.containers.internal` for your convenience). Default is false. - **mtu=MTU**: Specify the MTU to use for this network. (Default is `65520`). @@ -718,6 +725,30 @@ Valid _mode_ values are: Note: Rootlesskit changes the source IP address of incoming packets to an IP address in the container network namespace, usually `10.0.2.100`. If your application requires the real source IP address, e.g. web server logs, use the slirp4netns port handler. The rootlesskit port handler is also used for rootless containers when connected to user-defined networks. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding, it is slower than rootlesskit but preserves the correct source IP address. This port handler cannot be used for user-defined networks. +- **pasta[:OPTIONS,...]**: use **pasta**(1) to create a user-mode networking +stack. By default, IPv4 and IPv6 addresses and routes, as well as the pod +interface name, are copied from the host. If port forwarding isn't configured, +ports will be forwarded dynamically as services are bound on either side (init +namespace or container namespace). Port forwarding preserves the original source +IP address. Options described in pasta(1) can be specified as comma-separated +arguments. In terms of pasta(1) options, only **--config-net** is given by +default, in order to configure networking when the container is started. Some +examples: + - **pasta:--no-map-gw**: Don't allow the container to directly reach the host + using the gateway address, which would normally be mapped to a loopback or + link-local address. + - **pasta:--mtu,1500**: Specify a 1500 bytes MTU for the _tap_ interface in + the container. + - **pasta:--ipv4-only,-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3,-m,1500,--no-ndp,--no-dhcpv6,--no-dhcp**, + equivalent to default slirp4netns(1) options: disable IPv6, assign + `10.0.2.0/24` to the `tap0` interface in the container, with gateway + `10.0.2.3`, enable DNS forwarder reachable at `10.0.2.3`, set MTU to 1500 + bytes, disable NDP, DHCPv6 and DHCP support. + - **pasta:--no-map-gw,-I,tap0,--ipv4-only,-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3,--no-ndp,--no-dhcpv6,--no-dhcp**, + equivalent to default slirp4netns(1) options with Podman overrides: same as + above, but leave the MTU to 65520 bytes, and don't map the gateway address + from the container to a local address. + #### **--network-alias**=*alias* Add a network-scoped alias for the container, setting the alias for all networks that the container joins. To set a name only for a specific network, use the alias option as described under the **--network** option. @@ -1551,8 +1582,9 @@ In order for users to run rootless, there must be an entry for their username in Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed. The fuse-overlayfs package provides a userspace overlay storage driver, otherwise users need to use -the vfs storage driver, which is diskspace expensive and does not perform well. slirp4netns is -required for VPN, without it containers need to be run with the --network=host flag. +the vfs storage driver, which is diskspace expensive and does not perform well. +slirp4netns or pasta are required for VPN, without it containers need to be run +with the --network=host flag. ## ENVIRONMENT @@ -1601,7 +1633,9 @@ page. NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-save(1)](podman-save.1.md)**, **[podman-ps(1)](podman-ps.1.md)**, **[podman-attach(1)](podman-attach.1.md)**, **[podman-pod-create(1)](podman-pod-create.1.md)**, **[podman-port(1)](podman-port.1.md)**, **[podman-start(1)](podman-start.1.md)**, **[podman-kill(1)](podman-kill.1.md)**, **[podman-stop(1)](podman-stop.1.md)**, **[podman-generate-systemd(1)](podman-generate-systemd.1.md)**, **[podman-rm(1)](podman-rm.1.md)**, **[subgid(5)](https://www.unix.com/man-page/linux/5/subgid)**, **[subuid(5)](https://www.unix.com/man-page/linux/5/subuid)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[systemd.unit(5)](https://www.freedesktop.org/software/systemd/man/systemd.unit.html)**, **[setsebool(8)](https://man7.org/linux/man-pages/man8/setsebool.8.html)**, **[slirp4netns(1)](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md)**, **[fuse-overlayfs(1)](https://github.com/containers/fuse-overlayfs/blob/main/fuse-overlayfs.1.md)**, **proc(5)**, **[conmon(8)](https://github.com/containers/conmon/blob/main/docs/conmon.8.md)**, **personality(2)** +**[podman(1)](podman.1.md)**, **[podman-save(1)](podman-save.1.md)**, **[podman-ps(1)](podman-ps.1.md)**, **[podman-attach(1)](podman-attach.1.md)**, **[podman-pod-create(1)](podman-pod-create.1.md)**, **[podman-port(1)](podman-port.1.md)**, **[podman-start(1)](podman-start.1.md)**, **[podman-kill(1)](podman-kill.1.md)**, **[podman-stop(1)](podman-stop.1.md)**, **[podman-generate-systemd(1)](podman-generate-systemd.1.md)**, **[podman-rm(1)](podman-rm.1.md)**, **[subgid(5)](https://www.unix.com/man-page/linux/5/subgid)**, **[subuid(5)](https://www.unix.com/man-page/linux/5/subuid)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[systemd.unit(5)](https://www.freedesktop.org/software/systemd/man/systemd.unit.html)**, **[setsebool(8)](https://man7.org/linux/man-pages/man8/setsebool.8.html)**, **[slirp4netns(1)](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md)**, +**[pasta(1)](https://passt.top/builds/latest/web/passt.1.html)**, +**[fuse-overlayfs(1)](https://github.com/containers/fuse-overlayfs/blob/main/fuse-overlayfs.1.md)**, **proc(5)**, **[conmon(8)](https://github.com/containers/conmon/blob/main/docs/conmon.8.md)**, **personality(2)** ## HISTORY October 2017, converted from Docker documentation to Podman by Dan Walsh for Podman `` diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md index 8088e1d62..c94ac6061 100644 --- a/docs/source/markdown/podman-pod-create.1.md +++ b/docs/source/markdown/podman-pod-create.1.md @@ -175,12 +175,19 @@ Valid _mode_ values are: - **interface_name**: Specify a name for the created network interface inside the container. For example to set a static ipv4 address and a static mac address, use `--network bridge:ip=10.88.0.10,mac=44:33:22:11:00:99`. + - \[:OPTIONS,...]: Connect to a user-defined network; this is the network name or ID from a network created by **[podman network create](podman-network-create.1.md)**. Using the network name implies the bridge network mode. It is possible to specify the same options described under the bridge mode above. You can use the **--network** option multiple times to specify additional networks. + - **none**: Create a network namespace for the container but do not configure network interfaces for it, thus the container has no network connectivity. + - **container:**_id_: Reuse another container's network stack. + - **host**: Do not create a network namespace, the container will use the host's network. Note: The host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. + - **ns:**_path_: Path to a network namespace to join. + - **private**: Create a new namespace for the container. This will use the **bridge** mode for rootfull containers and **slirp4netns** for rootless ones. + - **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options: - **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`, which is added to `/etc/hosts` as `host.containers.internal` for your convenience). Default is false. - **mtu=MTU**: Specify the MTU to use for this network. (Default is `65520`). @@ -194,6 +201,30 @@ Valid _mode_ values are: Note: Rootlesskit changes the source IP address of incoming packets to an IP address in the container network namespace, usually `10.0.2.100`. If your application requires the real source IP address, e.g. web server logs, use the slirp4netns port handler. The rootlesskit port handler is also used for rootless containers when connected to user-defined networks. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding, it is slower than rootlesskit but preserves the correct source IP address. This port handler cannot be used for user-defined networks. +- **pasta[:OPTIONS,...]**: use **pasta**(1) to create a user-mode networking +stack. By default, IPv4 and IPv6 addresses and routes, as well as the pod +interface name, are copied from the host. If port forwarding isn't configured, +ports will be forwarded dynamically as services are bound on either side (init +namespace or container namespace). Port forwarding preserves the original source +IP address. Options described in pasta(1) can be specified as comma-separated +arguments. In terms of pasta(1) options, only **--config-net** is given by +default, in order to configure networking when the container is started. Some +examples: + - **pasta:--no-map-gw**: Don't allow the container to directly reach the host + using the gateway address, which would normally be mapped to a loopback or + link-local address. + - **pasta:--mtu,1500**: Specify a 1500 bytes MTU for the _tap_ interface in + the container. + - **pasta:--ipv4-only,-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3,-m,1500,--no-ndp,--no-dhcpv6,--no-dhcp**, + equivalent to default slirp4netns(1) options: disable IPv6, assign + `10.0.2.0/24` to the `tap0` interface in the container, with gateway + `10.0.2.3`, enable DNS forwarder reachable at `10.0.2.3`, set MTU to 1500 + bytes, disable NDP, DHCPv6 and DHCP support. + - **pasta:--no-map-gw,-I,tap0,--ipv4-only,-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3,--no-ndp,--no-dhcpv6,--no-dhcp**, + equivalent to default slirp4netns(1) options with Podman overrides: same as + above, but leave the MTU to 65520 bytes, and don't map the gateway address + from the container to a local address. + #### **--network-alias**=*alias* Add a network-scoped alias for the pod, setting the alias for all networks that the pod joins. To set a name only for a specific network, use the alias option as described under the **--network** option. @@ -527,6 +558,8 @@ $ podman pod create --network slirp4netns:outbound_addr=127.0.0.1,allow_host_loo $ podman pod create --network slirp4netns:cidr=192.168.0.0/24 +$ podman pod create --network pasta + $ podman pod create --network net1:ip=10.89.1.5 --network net2:ip=10.89.10.10 ``` diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 239cf3b83..7c12f5e88 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -726,12 +726,19 @@ Valid _mode_ values are: - **interface_name**: Specify a name for the created network interface inside the container. For example to set a static ipv4 address and a static mac address, use `--network bridge:ip=10.88.0.10,mac=44:33:22:11:00:99`. + - \[:OPTIONS,...]: Connect to a user-defined network; this is the network name or ID from a network created by **[podman network create](podman-network-create.1.md)**. Using the network name implies the bridge network mode. It is possible to specify the same options described under the bridge mode above. You can use the **--network** option multiple times to specify additional networks. + - **none**: Create a network namespace for the container but do not configure network interfaces for it, thus the container has no network connectivity. + - **container:**_id_: Reuse another container's network stack. + - **host**: Do not create a network namespace, the container will use the host's network. Note: The host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. + - **ns:**_path_: Path to a network namespace to join. + - **private**: Create a new namespace for the container. This will use the **bridge** mode for rootfull containers and **slirp4netns** for rootless ones. + - **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options: - **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`, which is added to `/etc/hosts` as `host.containers.internal` for your convenience). Default is false. - **mtu=MTU**: Specify the MTU to use for this network. (Default is `65520`). @@ -745,6 +752,30 @@ Valid _mode_ values are: Note: Rootlesskit changes the source IP address of incoming packets to an IP address in the container network namespace, usually `10.0.2.100`. If your application requires the real source IP address, e.g. web server logs, use the slirp4netns port handler. The rootlesskit port handler is also used for rootless containers when connected to user-defined networks. - **port_handler=slirp4netns**: Use the slirp4netns port forwarding, it is slower than rootlesskit but preserves the correct source IP address. This port handler cannot be used for user-defined networks. +- **pasta[:OPTIONS,...]**: use **pasta**(1) to create a user-mode networking +stack. By default, IPv4 and IPv6 addresses and routes, as well as the pod +interface name, are copied from the host. If port forwarding isn't configured, +ports will be forwarded dynamically as services are bound on either side (init +namespace or container namespace). Port forwarding preserves the original source +IP address. Options described in pasta(1) can be specified as comma-separated +arguments. In terms of pasta(1) options, only **--config-net** is given by +default, in order to configure networking when the container is started. Some +examples: + - **pasta:--no-map-gw**: Don't allow the container to directly reach the host + using the gateway address, which would normally be mapped to a loopback or + link-local address. + - **pasta:--mtu,1500**: Specify a 1500 bytes MTU for the _tap_ interface in + the container. + - **pasta:--ipv4-only,-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3,-m,1500,--no-ndp,--no-dhcpv6,--no-dhcp**, + equivalent to default slirp4netns(1) options: disable IPv6, assign + `10.0.2.0/24` to the `tap0` interface in the container, with gateway + `10.0.2.3`, enable DNS forwarder reachable at `10.0.2.3`, set MTU to 1500 + bytes, disable NDP, DHCPv6 and DHCP support. + - **pasta:--no-map-gw,-I,tap0,--ipv4-only,-a,10.0.2.0,-n,24,-g,10.0.2.2,--dns-forward,10.0.2.3,--no-ndp,--no-dhcpv6,--no-dhcp**, + equivalent to default slirp4netns(1) options with Podman overrides: same as + above, but leave the MTU to 65520 bytes, and don't map the gateway address + from the container to a local address. + #### **--network-alias**=*alias* Add a network-scoped alias for the container, setting the alias for all networks that the container joins. To set a name only for a specific network, use the alias option as described under the **--network** option. @@ -1935,8 +1966,9 @@ In order for users to run rootless, there must be an entry for their username in Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed. The **fuse-overlayfs** package provides a userspace overlay storage driver, otherwise users need to use -the **vfs** storage driver, which is diskspace expensive and does not perform well. slirp4netns is -required for VPN, without it containers need to be run with the **--network=host** flag. +the **vfs** storage driver, which is diskspace expensive and does not perform +well. slirp4netns or pasta are required for VPN, without it containers need to +be run with the **--network=host** flag. ## ENVIRONMENT @@ -1983,7 +2015,7 @@ page. NOTE: Use the environment variable `TMPDIR` to change the temporary storage location of downloaded container images. Podman defaults to use `/var/tmp`. ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-save(1)](podman-save.1.md)**, **[podman-ps(1)](podman-ps.1.md)**, **[podman-attach(1)](podman-attach.1.md)**, **[podman-pod-create(1)](podman-pod-create.1.md)**, **[podman-port(1)](podman-port.1.md)**, **[podman-start(1)](podman-start.1.md)**, **[podman-kill(1)](podman-kill.1.md)**, **[podman-stop(1)](podman-stop.1.md)**, **[podman-generate-systemd(1)](podman-generate-systemd.1.md)**, **[podman-rm(1)](podman-rm.1.md)**, **[subgid(5)](https://www.unix.com/man-page/linux/5/subgid)**, **[subuid(5)](https://www.unix.com/man-page/linux/5/subuid)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[systemd.unit(5)](https://www.freedesktop.org/software/systemd/man/systemd.unit.html)**, **[setsebool(8)](https://man7.org/linux/man-pages/man8/setsebool.8.html)**, **[slirp4netns(1)](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md)**, **[fuse-overlayfs(1)](https://github.com/containers/fuse-overlayfs/blob/main/fuse-overlayfs.1.md)**, **proc(5)**, **[conmon(8)](https://github.com/containers/conmon/blob/main/docs/conmon.8.md)**, **personality(2)** +**[podman(1)](podman.1.md)**, **[podman-save(1)](podman-save.1.md)**, **[podman-ps(1)](podman-ps.1.md)**, **[podman-attach(1)](podman-attach.1.md)**, **[podman-pod-create(1)](podman-pod-create.1.md)**, **[podman-port(1)](podman-port.1.md)**, **[podman-start(1)](podman-start.1.md)**, **[podman-kill(1)](podman-kill.1.md)**, **[podman-stop(1)](podman-stop.1.md)**, **[podman-generate-systemd(1)](podman-generate-systemd.1.md)**, **[podman-rm(1)](podman-rm.1.md)**, **[subgid(5)](https://www.unix.com/man-page/linux/5/subgid)**, **[subuid(5)](https://www.unix.com/man-page/linux/5/subuid)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[systemd.unit(5)](https://www.freedesktop.org/software/systemd/man/systemd.unit.html)**, **[setsebool(8)](https://man7.org/linux/man-pages/man8/setsebool.8.html)**, **[slirp4netns(1)](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md)**, **[pasta(1)](https://passt.top/builds/latest/web/passt.1.html)**, **[fuse-overlayfs(1)](https://github.com/containers/fuse-overlayfs/blob/main/fuse-overlayfs.1.md)**, **proc(5)**, **[conmon(8)](https://github.com/containers/conmon/blob/main/docs/conmon.8.md)**, **personality(2)** ## HISTORY September 2018, updated by Kunal Kushwaha `` diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index b318001e4..1ad808cba 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -95,7 +95,7 @@ Set libpod namespace. Namespaces are used to separate groups of containers and p When namespace is set, created containers and pods will join the given namespace, and only containers and pods in the given namespace will be visible to Podman. #### **--network-cmd-path**=*path* -Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable. +Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns(1) or pasta(1) network. If "" is used then the binary is looked up using the $PATH environment variable. #### **--noout** @@ -409,7 +409,7 @@ See the `subuid(5)` and `subgid(5)` man pages for more information. Images are pulled under `XDG_DATA_HOME` when specified, otherwise in the home directory of the user under `.local/share/containers/storage`. -Currently the slirp4netns package is required to be installed to create a network device, otherwise rootless containers need to run in the network namespace of the host. +Currently either slirp4netns or pasta are required to be installed to create a network device, otherwise rootless containers need to run in the network namespace of the host. In certain environments like HPC (High Performance Computing), users cannot take advantage of the additional UIDs and GIDs from the /etc/subuid and /etc/subgid systems. However, in this environment, rootless Podman can operate with a single UID. To make this work, set the `ignore_chown_errors` option in the /etc/containers/storage.conf or in ~/.config/containers/storage.conf files. This option tells Podman when pulling an image to ignore chown errors when attempting to change a file in a container image to match the non-root UID in the image. This means all files get saved as the user's UID. Note this could cause issues when running the container. @@ -422,7 +422,7 @@ The Network File System (NFS) and other distributed file systems (for example: L For more information, please refer to the [Podman Troubleshooting Page](https://github.com/containers/podman/blob/main/troubleshooting.md). ## SEE ALSO -**[containers-mounts.conf(5)](https://github.com/containers/common/blob/main/docs/containers-mounts.conf.5.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[containers-registries.conf(5)](https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md)**, **[containers-storage.conf(5)](https://github.com/containers/storage/blob/main/docs/containers-storage.conf.5.md)**, **[buildah(1)](https://github.com/containers/buildah/blob/main/docs/buildah.1.md)**, **oci-hooks(5)**, **[containers-policy.json(5)](https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md)**, **[crun(1)](https://github.com/containers/crun/blob/main/crun.1.md)**, **[runc(8)](https://github.com/opencontainers/runc/blob/master/man/runc.8.md)**, **[subuid(5)](https://www.unix.com/man-page/linux/5/subuid)**, **[subgid(5)](https://www.unix.com/man-page/linux/5/subgid)**, **[slirp4netns(1)](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md)**, **[conmon(8)](https://github.com/containers/conmon/blob/main/docs/conmon.8.md)** +**[containers-mounts.conf(5)](https://github.com/containers/common/blob/main/docs/containers-mounts.conf.5.md)**, **[containers.conf(5)](https://github.com/containers/common/blob/main/docs/containers.conf.5.md)**, **[containers-registries.conf(5)](https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md)**, **[containers-storage.conf(5)](https://github.com/containers/storage/blob/main/docs/containers-storage.conf.5.md)**, **[buildah(1)](https://github.com/containers/buildah/blob/main/docs/buildah.1.md)**, **oci-hooks(5)**, **[containers-policy.json(5)](https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md)**, **[crun(1)](https://github.com/containers/crun/blob/main/crun.1.md)**, **[runc(8)](https://github.com/opencontainers/runc/blob/master/man/runc.8.md)**, **[subuid(5)](https://www.unix.com/man-page/linux/5/subuid)**, **[subgid(5)](https://www.unix.com/man-page/linux/5/subgid)**, **[slirp4netns(1)](https://github.com/rootless-containers/slirp4netns/blob/master/slirp4netns.1.md)**, **[pasta(1)](https://passt.top/builds/latest/web/passt.1.html)**, **[conmon(8)](https://github.com/containers/conmon/blob/main/docs/conmon.8.md)** ## HISTORY Dec 2016, Originally compiled by Dan Walsh diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 19d5c7f76..183f815ba 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -636,6 +636,9 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (status map[str if ctr.config.NetMode.IsSlirp4netns() { return nil, r.setupSlirp4netns(ctr, ctrNS) } + if ctr.config.NetMode.IsPasta() { + return nil, r.setupPasta(ctr, ctrNS) + } networks, err := ctr.networks() if err != nil { return nil, err @@ -806,7 +809,8 @@ func (r *Runtime) teardownCNI(ctr *Container) error { return err } - if !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 { + if !ctr.config.NetMode.IsSlirp4netns() && + !ctr.config.NetMode.IsPasta() && len(networks) > 0 { netOpts, err := ctr.getNetworkOptions(networks) if err != nil { return err diff --git a/libpod/networking_pasta.go b/libpod/networking_pasta.go new file mode 100644 index 000000000..71595c87c --- /dev/null +++ b/libpod/networking_pasta.go @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// networking_pasta.go - Start pasta(1) to provide connectivity to the container +// +// Copyright (c) 2022 Red Hat GmbH +// Author: Stefano Brivio +// +// +build linux + +package libpod + +import ( + "os/exec" + "fmt" + "strings" + + "github.com/containernetworking/plugins/pkg/ns" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +func (r *Runtime) setupPasta(ctr *Container, netns ns.NetNS) error { + path := r.config.Engine.NetworkCmdPath + if path == "" { + var err error + path, err = exec.LookPath("pasta") + if err != nil { + logrus.Errorf("Could not find pasta, the network namespace won't be configured: %v", err) + return nil + } + } + + cmdArgs := []string{} + cmdArgs = append(cmdArgs, "--config-net") + + for _, i := range ctr.convertPortMappings() { + if i.Protocol == "tcp" { + cmdArgs = append(cmdArgs, "-t") + } else if i.Protocol == "udp" { + cmdArgs = append(cmdArgs, "-u") + } else { + logrus.Errorf("can't forward protocol: %s", i.Protocol) + return nil + } + + arg := fmt.Sprintf("%d:%d", i.HostPort, i.ContainerPort) + cmdArgs = append(cmdArgs, arg) + } + + cmdArgs = append(cmdArgs, ctr.config.NetworkOptions["pasta"]...) + + cmdArgs = append(cmdArgs, netns.Path()) + + logrus.Debugf("pasta arguments: %s", strings.Join(cmdArgs, " ")) + + // pasta forks once ready, and quits once we delete the target namespace + _, err := exec.Command(path, cmdArgs...).Output() + if err != nil { + return errors.Wrapf(err, "failed to start pasta: %s", + err.(*exec.ExitError).Stderr) + } + + return nil +} diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go index a7736aee0..0b2cb2b0b 100644 --- a/pkg/namespaces/namespaces.go +++ b/pkg/namespaces/namespaces.go @@ -19,6 +19,7 @@ const ( privateType = "private" shareableType = "shareable" slirpType = "slirp4netns" + pastaType = "pasta" ) // CgroupMode represents cgroup mode in the container. @@ -388,6 +389,11 @@ func (n NetworkMode) IsSlirp4netns() bool { return n == slirpType || strings.HasPrefix(string(n), slirpType+":") } +// IsPasta indicates if we are running a rootless network stack using pasta +func (n NetworkMode) IsPasta() bool { + return n == pastaType || strings.HasPrefix(string(n), pastaType + ":") +} + // IsNS indicates a network namespace passed in by path (ns:) func (n NetworkMode) IsNS() bool { return strings.HasPrefix(string(n), nsType) diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index 3f77cbe76..a72be1731 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -258,6 +258,16 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod. val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value) } toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil)) + case specgen.Pasta: + portMappings, expose, err := createPortMappings(ctx, s, imageData) + if err != nil { + return nil, err + } + val := "pasta" + if s.NetNS.Value != "" { + val = fmt.Sprintf("pasta:%s", s.NetNS.Value) + } + toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil)) case specgen.Private: fallthrough case specgen.Bridge: diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index 68fda3ad7..0d64027a3 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -232,6 +232,12 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) { p.InfraContainerSpec.NetworkOptions = p.NetworkOptions p.InfraContainerSpec.NetNS.NSMode = specgen.NamespaceMode("slirp4netns") } + case specgen.Pasta: + logrus.Debugf("Pod will use pasta") + if p.InfraContainerSpec.NetNS.NSMode != "host" { + p.InfraContainerSpec.NetworkOptions = p.NetworkOptions + p.InfraContainerSpec.NetNS.NSMode = specgen.NamespaceMode("pasta") + } case specgen.NoNetwork: logrus.Debugf("Pod will not use networking") if len(p.InfraContainerSpec.PortMappings) > 0 || diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go index e672bc65f..c7d443661 100644 --- a/pkg/specgen/namespaces.go +++ b/pkg/specgen/namespaces.go @@ -47,6 +47,9 @@ const ( // be used. // Only used with the network namespace, invalid otherwise. Slirp NamespaceMode = "slirp4netns" + // Pasta indicates that a pasta network stack should be used. + // Only used with the network namespace, invalid otherwise. + Pasta NamespaceMode = "pasta" // KeepId indicates a user namespace to keep the owner uid inside // of the namespace itself. // Only used with the user namespace, invalid otherwise. @@ -135,7 +138,7 @@ func validateNetNS(n *Namespace) error { return nil } switch n.NSMode { - case Slirp: + case Slirp, Pasta: break case "", Default, Host, Path, FromContainer, FromPod, Private, NoNetwork, Bridge: break @@ -167,7 +170,7 @@ func (n *Namespace) validate() error { switch n.NSMode { case "", Default, Host, Path, FromContainer, FromPod, Private: // Valid, do nothing - case NoNetwork, Bridge, Slirp: + case NoNetwork, Bridge, Slirp, Pasta: return errors.Errorf("cannot use network modes with non-network namespace") default: return errors.Errorf("invalid namespace type %s specified", n.NSMode) @@ -281,6 +284,8 @@ func ParseNetworkNamespace(ns string, rootlessDefaultCNI bool) (Namespace, map[s switch { case ns == string(Slirp), strings.HasPrefix(ns, string(Slirp)+":"): toReturn.NSMode = Slirp + case ns == string(Pasta), strings.HasPrefix(ns, string(Pasta) + ":"): + toReturn.NSMode = Pasta case ns == string(FromPod): toReturn.NSMode = FromPod case ns == "" || ns == string(Default) || ns == string(Private): @@ -349,6 +354,13 @@ func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetwork networkOptions[parts[0]] = strings.Split(parts[1], ",") } toReturn.NSMode = Slirp + case ns == string(Pasta), strings.HasPrefix(ns, string(Pasta) + ":"): + parts := strings.SplitN(ns, ":", 2) + if len(parts) > 1 { + networkOptions = make(map[string][]string) + networkOptions[parts[0]] = strings.Split(parts[1], ",") + } + toReturn.NSMode = Pasta case ns == string(FromPod): toReturn.NSMode = FromPod case ns == "" || ns == string(Default) || ns == string(Private): @@ -425,7 +437,7 @@ func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetwork if parts[0] == "" { return toReturn, nil, nil, errors.Wrapf(define.ErrInvalidArg, "network name cannot be empty") } - if util.StringInSlice(parts[0], []string{string(Bridge), string(Slirp), string(FromPod), string(NoNetwork), + if util.StringInSlice(parts[0], []string{string(Bridge), string(Slirp), string(Pasta), string(FromPod), string(NoNetwork), string(Default), string(Private), string(Path), string(FromContainer), string(Host)}) { return toReturn, nil, nil, errors.Wrapf(define.ErrInvalidArg, "can only set extra network names, selected mode %s conflicts with bridge", parts[0]) } diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go index 759caa0c0..f95bbffc7 100644 --- a/pkg/specgen/podspecgen.go +++ b/pkg/specgen/podspecgen.go @@ -93,7 +93,7 @@ type PodNetworkConfig struct { // PortMappings is a set of ports to map into the infra container. // As, by default, containers share their network with the infra // container, this will forward the ports to the entire pod. - // Only available if NetNS is set to Bridge or Slirp. + // Only available if NetNS is set to Bridge, Slirp, or Pasta. // Optional. PortMappings []types.PortMapping `json:"portmappings,omitempty"` // Map of networks names to ids the container should join to. -- 2.28.0