mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00
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 not an experimental feature, and enabled by default. IPv6 port forwarding is supported - 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 - sandboxing and seccomp(2) policies cannot be disabled - only rootless mode is supported. See https://passt.top for more details about pasta. Also add a link to the maintained build of pasta(1) manual as valid in the man page cross-reference checks: that's where the man page for the latest build actually is -- it's not on Github and it doesn't match any existing pattern, so add it explicitly. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
@ -95,7 +95,7 @@ func DefineNetFlags(cmd *cobra.Command) {
|
||||
}
|
||||
|
||||
// NetFlagsToNetOptions parses the network flags for the given cmd.
|
||||
func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet) (*entities.NetOptions, error) {
|
||||
func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet, pastaNetworkNameExists bool) (*entities.NetOptions, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
@ -192,7 +192,7 @@ func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet) (*enti
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ns, networks, options, err := specgen.ParseNetworkFlag(network)
|
||||
ns, networks, options, err := specgen.ParseNetworkFlag(network, pastaNetworkNameExists)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -105,8 +105,15 @@ func init() {
|
||||
|
||||
func commonFlags(cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
report, err := registry.ContainerEngine().NetworkExists(registry.Context(), "pasta")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pastaNetworkNameExists := report.Value
|
||||
|
||||
flags := cmd.Flags()
|
||||
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags)
|
||||
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags, pastaNetworkNameExists)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -130,12 +130,18 @@ func create(cmd *cobra.Command, args []string) error {
|
||||
createOptions.Infra = false
|
||||
}
|
||||
|
||||
report, err := registry.ContainerEngine().NetworkExists(registry.Context(), "pasta")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pastaNetworkNameExists := report.Value
|
||||
|
||||
if !createOptions.Infra {
|
||||
if cmd.Flag("no-hosts").Changed {
|
||||
return fmt.Errorf("cannot specify --no-hosts without an infra container")
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
createOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags)
|
||||
createOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, pastaNetworkNameExists)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -152,7 +158,7 @@ func create(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
// reassign certain options for lbpod api, these need to be populated in spec
|
||||
flags := cmd.Flags()
|
||||
infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags)
|
||||
infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, pastaNetworkNameExists)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -35,3 +35,42 @@ Valid _mode_ values are:
|
||||
- **port_handler=rootlesskit**: Use rootlesskit for port forwarding. Default.
|
||||
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. \
|
||||
This is only supported in rootless mode. \
|
||||
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, **--config-net** is given by default, in
|
||||
order to configure networking when the container is started, and
|
||||
**--no-map-gw** is also assumed by default, to avoid direct access from
|
||||
container to host using the gateway address. The latter can be overridden
|
||||
by passing **--map-gw** in the pasta-specific options (despite not being an
|
||||
actual pasta(1) option). \
|
||||
Also, **-t none** and **-u none** are passed if, respectively, no TCP or
|
||||
UDP port forwarding from host to container is configured, to disable
|
||||
automatic port forwarding based on bound ports. Similarly, **-T none** and
|
||||
**-U none** are given to disable the same functionality from container to
|
||||
host. \
|
||||
Some examples:
|
||||
- **pasta:--map-gw**: Allow the container to directly reach the host using the
|
||||
gateway 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:-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
|
||||
- **pasta:-t,auto,-u,auto,-T,auto,-U,auto**: enable automatic port forwarding
|
||||
based on observed bound ports from both host and container sides
|
||||
- **pasta:-T,5201**: enable forwarding of TCP port 5201 from container to
|
||||
host, using the loopback interface instead of the tap interface for improved
|
||||
performance
|
||||
|
@ -491,8 +491,11 @@ 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 can be disk space expensive and less performant
|
||||
than other drivers.
|
||||
|
||||
To enable VPN on the container, slirp4netns or pasta needs to be specified;
|
||||
without either, containers need to be run with the --network=host flag.
|
||||
|
||||
## ENVIRONMENT
|
||||
|
||||
@ -541,7 +544,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
|
||||
October 2017, converted from Docker documentation to Podman by Dan Walsh for Podman `<dwalsh@redhat.com>`
|
||||
|
@ -219,6 +219,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
|
||||
```
|
||||
|
||||
|
@ -837,8 +837,11 @@ 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 can be disk space expensive and less
|
||||
performant than other drivers.
|
||||
|
||||
To enable VPN on the container, slirp4netns or pasta needs to be specified;
|
||||
without either, containers need to be run with the --network=host flag.
|
||||
|
||||
## ENVIRONMENT
|
||||
|
||||
@ -885,7 +888,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 `<kushwaha_kunal_v7@lab.ntt.co.jp>`
|
||||
|
@ -88,7 +88,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.
|
||||
|
||||
#### **--network-config-dir**=*directory*
|
||||
|
||||
@ -422,7 +422,9 @@ 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 slirp4netns or pasta is 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.
|
||||
|
||||
@ -435,7 +437,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 <dwalsh@redhat.com>
|
||||
|
@ -619,6 +619,8 @@ sub _is_valid_external_link {
|
||||
return 1 if $link eq "https://www.freedesktop.org/software/systemd/man/$base.html";
|
||||
}
|
||||
|
||||
return 1 if $link eq "https://passt.top/builds/latest/web/passt.1.html";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,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 := ctr.getNetworkOptions(networks)
|
||||
return r.teardownNetwork(ctr.state.NetNS.Path(), netOpts)
|
||||
}
|
||||
|
@ -563,6 +563,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
|
||||
|
108
libpod/networking_pasta_linux.go
Normal file
108
libpod/networking_pasta_linux.go
Normal file
@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// networking_pasta_linux.go - Start pasta(1) for user-mode connectivity
|
||||
//
|
||||
// Copyright (c) 2022 Red Hat GmbH
|
||||
// Author: Stefano Brivio <sbrivio@redhat.com>
|
||||
|
||||
package libpod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (r *Runtime) setupPasta(ctr *Container, netns ns.NetNS) error {
|
||||
var NoTCPInitPorts = true
|
||||
var NoUDPInitPorts = true
|
||||
var NoTCPNamespacePorts = true
|
||||
var NoUDPNamespacePorts = true
|
||||
var NoMapGW = true
|
||||
|
||||
path, err := r.config.FindHelperBinary("pasta", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find pasta, the network namespace can't be configured: %w", err)
|
||||
}
|
||||
|
||||
cmdArgs := []string{}
|
||||
cmdArgs = append(cmdArgs, "--config-net")
|
||||
|
||||
for _, i := range ctr.convertPortMappings() {
|
||||
protocols := strings.Split(i.Protocol, ",")
|
||||
for _, protocol := range protocols {
|
||||
var addr string
|
||||
|
||||
if i.HostIP != "" {
|
||||
addr = fmt.Sprintf("%s/", i.HostIP)
|
||||
}
|
||||
|
||||
switch protocol {
|
||||
case "tcp":
|
||||
cmdArgs = append(cmdArgs, "-t")
|
||||
case "udp":
|
||||
cmdArgs = append(cmdArgs, "-u")
|
||||
case "default":
|
||||
return fmt.Errorf("can't forward protocol: %s", protocol)
|
||||
}
|
||||
|
||||
arg := fmt.Sprintf("%s%d-%d:%d-%d", addr,
|
||||
i.HostPort,
|
||||
i.HostPort+i.Range-1,
|
||||
i.ContainerPort,
|
||||
i.ContainerPort+i.Range-1)
|
||||
cmdArgs = append(cmdArgs, arg)
|
||||
}
|
||||
}
|
||||
|
||||
cmdArgs = append(cmdArgs, ctr.config.NetworkOptions["pasta"]...)
|
||||
|
||||
for i, opt := range cmdArgs {
|
||||
switch opt {
|
||||
case "-t", "--tcp-ports":
|
||||
NoTCPInitPorts = false
|
||||
case "-u", "--udp-ports":
|
||||
NoUDPInitPorts = false
|
||||
case "-T", "--tcp-ns":
|
||||
NoTCPNamespacePorts = false
|
||||
case "-U", "--udp-ns":
|
||||
NoUDPNamespacePorts = false
|
||||
case "--map-gw":
|
||||
NoMapGW = false
|
||||
// not an actual pasta(1) option
|
||||
cmdArgs = append(cmdArgs[:i], cmdArgs[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if NoTCPInitPorts {
|
||||
cmdArgs = append(cmdArgs, "-t", "none")
|
||||
}
|
||||
if NoUDPInitPorts {
|
||||
cmdArgs = append(cmdArgs, "-u", "none")
|
||||
}
|
||||
if NoTCPNamespacePorts {
|
||||
cmdArgs = append(cmdArgs, "-T", "none")
|
||||
}
|
||||
if NoUDPNamespacePorts {
|
||||
cmdArgs = append(cmdArgs, "-U", "none")
|
||||
}
|
||||
if NoMapGW {
|
||||
cmdArgs = append(cmdArgs, "--no-map-gw")
|
||||
}
|
||||
|
||||
cmdArgs = append(cmdArgs, "--netns", 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 fmt.Errorf("failed to start pasta:\n%s",
|
||||
err.(*exec.ExitError).Stderr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -267,7 +267,8 @@ func cliOpts(cc handlers.CreateContainerConfig, rtc *config.Config) (*entities.C
|
||||
if netmode == "" || netmode == "default" {
|
||||
netmode = "bridge"
|
||||
}
|
||||
nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{netmode})
|
||||
|
||||
nsmode, networks, netOpts, err := specgen.ParseNetworkFlag([]string{netmode}, false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) NetworkCreate(ctx context.Context, network types.Network) (*types.Network, error) {
|
||||
// TODO (5.0): Stop accepting "pasta" as value here
|
||||
if util.StringInSlice(network.Name, []string{"none", "host", "bridge", "private", "slirp4netns", "container", "ns"}) {
|
||||
return nil, fmt.Errorf("cannot create network with name %q because it conflicts with a valid network mode", network.Name)
|
||||
}
|
||||
|
@ -375,7 +375,14 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||
}
|
||||
|
||||
if len(options.Networks) > 0 {
|
||||
ns, networks, netOpts, err := specgen.ParseNetworkFlag(options.Networks)
|
||||
var pastaNetworkNameExists bool
|
||||
|
||||
_, err := ic.Libpod.Network().NetworkInspect("pasta")
|
||||
if err == nil {
|
||||
pastaNetworkNameExists = true
|
||||
}
|
||||
|
||||
ns, networks, netOpts, err := specgen.ParseNetworkFlag(options.Networks, pastaNetworkNameExists)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ const (
|
||||
privateType = "private"
|
||||
shareableType = "shareable"
|
||||
slirpType = "slirp4netns"
|
||||
pastaType = "pasta"
|
||||
)
|
||||
|
||||
// KeepIDUserNsOptions defines how to keepIDmatically create a user namespace.
|
||||
@ -440,6 +441,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:<path>)
|
||||
func (n NetworkMode) IsNS() bool {
|
||||
return strings.HasPrefix(string(n), nsType)
|
||||
@ -461,5 +467,5 @@ func (n NetworkMode) IsPod() bool {
|
||||
|
||||
// IsUserDefined indicates user-created network
|
||||
func (n NetworkMode) IsUserDefined() bool {
|
||||
return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() && !n.IsSlirp4netns() && !n.IsNS()
|
||||
return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() && !n.IsSlirp4netns() && !n.IsPasta() && !n.IsNS()
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod)
|
||||
case "cgroup":
|
||||
return specgen.ParseCgroupNamespace(cfg.Containers.CgroupNS)
|
||||
case "net":
|
||||
ns, _, _, err := specgen.ParseNetworkFlag(nil)
|
||||
ns, _, _, err := specgen.ParseNetworkFlag(nil, false)
|
||||
return ns, err
|
||||
}
|
||||
|
||||
@ -300,6 +300,13 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *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(s, imageData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val := "pasta"
|
||||
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil))
|
||||
case specgen.Bridge, specgen.Private, specgen.Default:
|
||||
portMappings, expose, err := createPortMappings(s, imageData)
|
||||
if err != nil {
|
||||
|
@ -38,7 +38,7 @@ func canMountSys(isRootless, isNewUserns bool, s *specgen.SpecGenerator) bool {
|
||||
}
|
||||
if isNewUserns {
|
||||
switch s.NetNS.NSMode {
|
||||
case specgen.Slirp, specgen.Private, specgen.NoNetwork, specgen.Bridge:
|
||||
case specgen.Slirp, specgen.Pasta, specgen.Private, specgen.NoNetwork, specgen.Bridge:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
@ -195,11 +195,16 @@ func MapSpec(p *specgen.PodSpecGenerator) (*specgen.SpecGenerator, error) {
|
||||
p.InfraContainerSpec.NetworkOptions = p.NetworkOptions
|
||||
p.InfraContainerSpec.NetNS.NSMode = specgen.Slirp
|
||||
}
|
||||
case specgen.Pasta:
|
||||
logrus.Debugf("Pod will use pasta")
|
||||
if p.InfraContainerSpec.NetNS.NSMode != specgen.Host {
|
||||
p.InfraContainerSpec.NetworkOptions = p.NetworkOptions
|
||||
p.InfraContainerSpec.NetNS.NSMode = specgen.Pasta
|
||||
}
|
||||
case specgen.Path:
|
||||
logrus.Debugf("Pod will use namespace path networking")
|
||||
p.InfraContainerSpec.NetNS.NSMode = specgen.Path
|
||||
p.InfraContainerSpec.NetNS.Value = p.PodNetworkConfig.NetNS.Value
|
||||
|
||||
case specgen.NoNetwork:
|
||||
logrus.Debugf("Pod will not use networking")
|
||||
if len(p.InfraContainerSpec.PortMappings) > 0 ||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
cutil "github.com/containers/common/pkg/util"
|
||||
"github.com/containers/podman/v4/libpod/define"
|
||||
"github.com/containers/podman/v4/pkg/namespaces"
|
||||
"github.com/containers/podman/v4/pkg/rootless"
|
||||
"github.com/containers/podman/v4/pkg/util"
|
||||
"github.com/containers/storage"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
@ -52,6 +53,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.
|
||||
@ -156,6 +160,11 @@ func validateNetNS(n *Namespace) error {
|
||||
switch n.NSMode {
|
||||
case Slirp:
|
||||
break
|
||||
case Pasta:
|
||||
if rootless.IsRootless() {
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("pasta networking is only supported for rootless mode")
|
||||
case "", Default, Host, Path, FromContainer, FromPod, Private, NoNetwork, Bridge:
|
||||
break
|
||||
default:
|
||||
@ -197,7 +206,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.New("cannot use network modes with non-network namespace")
|
||||
default:
|
||||
return fmt.Errorf("invalid namespace type %s specified", n.NSMode)
|
||||
@ -329,7 +338,8 @@ func ParseUserNamespace(ns string) (Namespace, error) {
|
||||
|
||||
// ParseNetworkFlag parses a network string slice into the network options
|
||||
// If the input is nil or empty it will use the default setting from containers.conf
|
||||
func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetworkOptions, map[string][]string, error) {
|
||||
// TODO (5.0): Drop pastaNetworkNameExists
|
||||
func ParseNetworkFlag(networks []string, pastaNetworkNameExists bool) (Namespace, map[string]types.PerNetworkOptions, map[string][]string, error) {
|
||||
var networkOptions map[string][]string
|
||||
// by default we try to use the containers.conf setting
|
||||
// if we get at least one value use this instead
|
||||
@ -385,6 +395,22 @@ func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetwork
|
||||
}
|
||||
toReturn.NSMode = FromContainer
|
||||
toReturn.Value = split[1]
|
||||
case ns == string(Pasta), strings.HasPrefix(ns, string(Pasta)+":"):
|
||||
var parts []string
|
||||
|
||||
if pastaNetworkNameExists {
|
||||
goto nextCase
|
||||
}
|
||||
|
||||
parts = strings.SplitN(ns, ":", 2)
|
||||
if len(parts) > 1 {
|
||||
networkOptions = make(map[string][]string)
|
||||
networkOptions[parts[0]] = strings.Split(parts[1], ",")
|
||||
}
|
||||
toReturn.NSMode = Pasta
|
||||
break
|
||||
nextCase:
|
||||
fallthrough
|
||||
default:
|
||||
// we should have a normal network
|
||||
parts := strings.SplitN(ns, ":", 2)
|
||||
@ -419,6 +445,7 @@ func ParseNetworkFlag(networks []string) (Namespace, map[string]types.PerNetwork
|
||||
if parts[0] == "" {
|
||||
return toReturn, nil, nil, fmt.Errorf("network name cannot be empty: %w", define.ErrInvalidArg)
|
||||
}
|
||||
// TODO (5.0): Don't accept string(Pasta) here once we drop pastaNetworkNameExists
|
||||
if cutil.StringInSlice(parts[0], []string{string(Bridge), string(Slirp), string(FromPod), string(NoNetwork),
|
||||
string(Default), string(Private), string(Path), string(FromContainer), string(Host)}) {
|
||||
return toReturn, nil, nil, fmt.Errorf("can only set extra network names, selected mode %s conflicts with bridge: %w", parts[0], define.ErrInvalidArg)
|
||||
|
@ -241,7 +241,7 @@ func TestParseNetworkFlag(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1, got2, err := ParseNetworkFlag(tt.args)
|
||||
got, got1, got2, err := ParseNetworkFlag(tt.args, false)
|
||||
if tt.err != "" {
|
||||
assert.EqualError(t, err, tt.err, tt.name)
|
||||
} else {
|
||||
|
@ -65,9 +65,9 @@ func (p *PodSpecGenerator) Validate() error {
|
||||
return exclusivePodOptions("NoInfra", "NoManageResolvConf")
|
||||
}
|
||||
}
|
||||
if p.NetNS.NSMode != "" && p.NetNS.NSMode != Bridge && p.NetNS.NSMode != Slirp && p.NetNS.NSMode != Default {
|
||||
if p.NetNS.NSMode != "" && p.NetNS.NSMode != Bridge && p.NetNS.NSMode != Slirp && p.NetNS.NSMode != Pasta && p.NetNS.NSMode != Default {
|
||||
if len(p.PortMappings) > 0 {
|
||||
return errors.New("PortMappings can only be used with Bridge or slirp4netns networking")
|
||||
return errors.New("PortMappings can only be used with Bridge, slirp4netns, or pasta networking")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,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.
|
||||
|
@ -421,7 +421,7 @@ type ContainerNetworkConfig struct {
|
||||
// Mandatory.
|
||||
NetNS Namespace `json:"netns,omitempty"`
|
||||
// PortBindings is a set of ports to map into the container.
|
||||
// Only available if NetNS is set to bridge or slirp.
|
||||
// Only available if NetNS is set to bridge, slirp, or pasta.
|
||||
// Optional.
|
||||
PortMappings []nettypes.PortMapping `json:"portmappings,omitempty"`
|
||||
// PublishExposedPorts will publish ports specified in the image to
|
||||
|
Reference in New Issue
Block a user