Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions cmd/podman/networks/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ var (
RunE: networkCreate,
Args: cobra.MaximumNArgs(1),
Example: `podman network create podman1`,
Annotations: map[string]string{
registry.ParentNSRequired: "",
},
}
)

Expand Down
3 changes: 0 additions & 3 deletions cmd/podman/networks/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ var (
RunE: networkInspect,
Example: `podman network inspect podman`,
Args: cobra.MinimumNArgs(1),
Annotations: map[string]string{
registry.ParentNSRequired: "",
},
}
)

Expand Down
3 changes: 0 additions & 3 deletions cmd/podman/networks/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ var (
Long: networklistDescription,
RunE: networkList,
Example: `podman network list`,
Annotations: map[string]string{
registry.ParentNSRequired: "",
},
}
)

Expand Down
3 changes: 0 additions & 3 deletions cmd/podman/networks/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ var (
RunE: networkRm,
Example: `podman network rm podman`,
Args: cobra.MinimumNArgs(1),
Annotations: map[string]string{
registry.ParentNSRequired: "",
},
}
)

Expand Down
35 changes: 35 additions & 0 deletions contrib/rootless-cni-infra/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ARG GOLANG_VERSION=1.15
ARG ALPINE_VERSION=3.12
ARG CNI_VERSION=v0.8.0
ARG CNI_PLUGINS_VERSION=v0.8.7
# Aug 20, 2020
ARG DNSNAME_VESION=78b4da7bbfc51c27366da630e1df1c4f2e8b1b5b

FROM golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION} AS golang-base
RUN apk add --no-cache git

FROM golang-base AS cnitool
RUN git clone https://github.com/containernetworking/cni /go/src/github.com/containernetworking/cni
WORKDIR /go/src/github.com/containernetworking/cni
ARG CNI_VERSION
RUN git checkout ${CNI_VERSION}
RUN go build -o /cnitool ./cnitool

FROM golang-base AS dnsname
RUN git clone https://github.com/containers/dnsname /go/src/github.com/containers/dnsname
WORKDIR /go/src/github.com/containers/dnsname
ARG DNSNAME_VERSION
RUN git checkout ${DNSNAME_VERSION}
RUN go build -o /dnsname ./plugins/meta/dnsname

FROM alpine:${ALPINE_VERSION}
RUN apk add --no-cache curl dnsmasq iptables ip6tables iproute2
ARG TARGETARCH
ARG CNI_PLUGINS_VERSION
RUN mkdir -p /opt/cni/bin && \
curl -fsSL https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${TARGETARCH}-${CNI_PLUGINS_VERSION}.tgz | tar xz -C /opt/cni/bin
COPY --from=cnitool /cnitool /usr/local/bin
COPY --from=dnsname /dnsname /opt/cni/bin
COPY rootless-cni-infra /usr/local/bin
ENV CNI_PATH=/opt/cni/bin
CMD ["sleep", "infinity"]
22 changes: 22 additions & 0 deletions contrib/rootless-cni-infra/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# rootless-cni-infra

Infra container for CNI-in-slirp4netns.

## How it works

When a CNI network is specified for `podman run` in rootless mode, Podman launches the `rootless-cni-infra` container to execute CNI plugins inside slirp4netns.

The infra container is created per user, by executing an equivalent of:
`podman run -d --name rootless-cni-infra --pid=host --privileged -v $HOME/.config/cni/net.d:/etc/cni/net.d rootless-cni-infra`.
The infra container is automatically deleted when no CNI network is in use.

Podman then allocates a CNI netns in the infra container, by executing an equivalent of:
`podman exec rootless-cni-infra rootless-cni-infra alloc $CONTAINER_ID $NETWORK_NAME $POD_NAME`.

The allocated netns is deallocated when the container is being removed, by executing an equivalent of:
`podman exec rootless-cni-infra rootless-cni-infra dealloc $CONTAINER_ID $NETWORK_NAME`.

## Directory layout

* `/run/rootless-cni-infra/${CONTAINER_ID}/pid`: PID of the `sleep infinity` process that corresponds to the allocated netns
* `/run/rootless-cni-infra/${CONTAINER_ID}/attached/${NETWORK_NAME}`: CNI result
147 changes: 147 additions & 0 deletions contrib/rootless-cni-infra/rootless-cni-infra
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/bin/sh
set -eu

ARG0="$0"
VERSION="0.1.0"
BASE="/run/rootless-cni-infra"

# CLI subcommand: "alloc $CONTAINER_ID $NETWORK_NAME $POD_NAME"
cmd_entrypoint_alloc() {
if [ "$#" -ne 3 ]; then
echo >&2 "Usage: $ARG0 alloc CONTAINER_ID NETWORK_NAME POD_NAME"
exit 1
fi

ID="$1"
NET="$2"
K8S_POD_NAME="$3"

dir="${BASE}/${ID}"
mkdir -p "${dir}/attached"

pid=""
if [ -f "${dir}/pid" ]; then
pid=$(cat "${dir}/pid")
else
unshare -n sleep infinity &
pid="$!"
echo "${pid}" >"${dir}/pid"
nsenter -t "${pid}" -n ip link set lo up
fi
CNI_ARGS="IgnoreUnknown=1;K8S_POD_NAME=${K8S_POD_NAME}"
nwcount=$(find "${dir}/attached" -type f | wc -l)
CNI_IFNAME="eth${nwcount}"
export CNI_ARGS CNI_IFNAME
cnitool add "${NET}" "/proc/${pid}/ns/net" >"${dir}/attached/${NET}"

# return the result
ns="/proc/${pid}/ns/net"
echo "{\"ns\":\"${ns}\"}"
}

# CLI subcommand: "dealloc $CONTAINER_ID $NETWORK_NAME"
cmd_entrypoint_dealloc() {
if [ "$#" -ne 2 ]; then
echo >&2 "Usage: $ARG0 dealloc CONTAINER_ID NETWORK_NAME"
exit 1
fi

ID=$1
NET=$2

dir="${BASE}/${ID}"
if [ ! -f "${dir}/pid" ]; then
exit 0
fi
pid=$(cat "${dir}/pid")
cnitool del "${NET}" "/proc/${pid}/ns/net"
rm -f "${dir}/attached/${NET}"

nwcount=$(find "${dir}/attached" -type f | wc -l)
if [ "${nwcount}" = 0 ]; then
kill -9 "${pid}"
rm -rf "${dir}"
fi

# return empty json
echo "{}"
}

# CLI subcommand: "is-idle"
cmd_entrypoint_is_idle() {
if [ ! -d ${BASE} ]; then
echo '{"idle": true}'
elif [ -z "$(ls -1 ${BASE})" ]; then
echo '{"idle": true}'
else
echo '{"idle": false}'
fi
}

# CLI subcommand: "print-cni-result $CONTAINER_ID $NETWORK_NAME"
cmd_entrypoint_print_cni_result() {
if [ "$#" -ne 2 ]; then
echo >&2 "Usage: $ARG0 print-cni-result CONTAINER_ID NETWORK_NAME"
exit 1
fi

ID=$1
NET=$2

# the result shall be CNI JSON
cat "${BASE}/${ID}/attached/${NET}"
}

# CLI subcommand: "print-netns-path $CONTAINER_ID"
cmd_entrypoint_print_netns_path() {
if [ "$#" -ne 1 ]; then
echo >&2 "Usage: $ARG0 print-netns-path CONTAINER_ID"
exit 1
fi

ID=$1

pid=$(cat "${BASE}/${ID}/pid")
path="/proc/${pid}/ns/net"

# return the result
echo "{\"path\":\"${path}\"}"
}

# CLI subcommand: "help"
cmd_entrypoint_help() {
echo "Usage: ${ARG0} COMMAND"
echo
echo "Rootless CNI Infra container"
echo
echo "Commands:"
echo " alloc Allocate a netns"
echo " dealloc Deallocate a netns"
echo " is-idle Print whether the infra container is idle"
echo " print-cni-result Print CNI result"
echo " print-netns-path Print netns path"
echo " help Print help"
echo " version Print version"
}

# CLI subcommand: "version"
cmd_entrypoint_version() {
echo "{\"version\": \"${VERSION}\"}"
}

# parse args
command="${1:-}"
if [ -z "$command" ]; then
echo >&2 "No command was specified. Run \`${ARG0} help\` to see the usage."
exit 1
fi

command_func=$(echo "cmd_entrypoint_${command}" | sed -e "s/-/_/g")
if ! command -v "${command_func}" >/dev/null 2>&1; then
echo >&2 "Unknown command: ${command}. Run \`${ARG0} help\` to see the usage."
exit 1
fi

# start the command func
shift
"${command_func}" "$@"
4 changes: 3 additions & 1 deletion libpod/container_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -957,8 +957,10 @@ func (c *Container) completeNetworkSetup() error {
if err := c.syncContainer(); err != nil {
return err
}
if c.config.NetMode.IsSlirp4netns() {
if rootless.IsRootless() {
return c.runtime.setupRootlessNetNS(c)
} else if c.config.NetMode.IsSlirp4netns() {
return c.runtime.setupSlirp4netns(c)
}
if err := c.runtime.setupNetNS(c); err != nil {
return err
Expand Down
14 changes: 11 additions & 3 deletions libpod/container_internal_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ func (c *Container) prepare() error {
// Set up network namespace if not already set up
noNetNS := c.state.NetNS == nil
if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
if rootless.IsRootless() && len(c.config.Networks) > 0 {
netNS, networkStatus, createNetNSErr = AllocRootlessCNI(context.Background(), c)
} else {
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
}
if createNetNSErr != nil {
return
}
Expand All @@ -98,8 +102,12 @@ func (c *Container) prepare() error {
}

// handle rootless network namespace setup
if noNetNS && c.config.NetMode.IsSlirp4netns() && !c.config.PostConfigureNetNS {
createNetNSErr = c.runtime.setupRootlessNetNS(c)
if noNetNS && !c.config.PostConfigureNetNS {
if rootless.IsRootless() {
createNetNSErr = c.runtime.setupRootlessNetNS(c)
} else if c.config.NetMode.IsSlirp4netns() {
createNetNSErr = c.runtime.setupSlirp4netns(c)
}
}
}()
// Mount storage if not mounted
Expand Down
11 changes: 0 additions & 11 deletions libpod/container_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package libpod

import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/rootless"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -68,16 +67,6 @@ func (c *Container) validate() error {
}
}

// Rootless has some requirements, compared to networks.
if rootless.IsRootless() {
if len(c.config.Networks) > 0 {
return errors.Wrapf(define.ErrInvalidArg, "cannot join CNI networks if running rootless")
}

// TODO: Should we make sure network mode is set to Slirp if set
// at all?
}

// Can only set static IP or MAC is creating a network namespace.
if !c.config.CreateNetNS && (c.config.StaticIP != nil || c.config.StaticMAC != nil) {
return errors.Wrapf(define.ErrInvalidArg, "cannot set static IP or MAC address if not creating a network namespace")
Expand Down
24 changes: 23 additions & 1 deletion libpod/networking_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package libpod

import (
"bytes"
"context"
"crypto/rand"
"fmt"
"io"
Expand Down Expand Up @@ -208,6 +209,20 @@ func checkSlirpFlags(path string) (*slirpFeatures, error) {

// Configure the network namespace for a rootless container
func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
if ctr.config.NetMode.IsSlirp4netns() {
return r.setupSlirp4netns(ctr)
}
if len(ctr.config.Networks) > 0 {
// set up port forwarder for CNI-in-slirp4netns
netnsPath := ctr.state.NetNS.Path()
// TODO: support slirp4netns port forwarder as well
return r.setupRootlessPortMappingViaRLK(ctr, netnsPath)
}
return nil
}

// setupSlirp4netns can be called in rootful as well as in rootless
func (r *Runtime) setupSlirp4netns(ctr *Container) error {
path := r.config.Engine.NetworkCmdPath

if path == "" {
Expand Down Expand Up @@ -711,7 +726,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {

logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())

// rootless containers do not use the CNI plugin
// rootless containers do not use the CNI plugin directly
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
var requestedIP net.IP
if ctr.requestedIP != nil {
Expand All @@ -738,6 +753,13 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
}
}

// CNI-in-slirp4netns
if rootless.IsRootless() && len(ctr.config.Networks) != 0 {
if err := DeallocRootlessCNI(context.Background(), ctr); err != nil {
return errors.Wrapf(err, "error tearing down CNI-in-slirp4netns for container %s", ctr.ID())
}
}

// First unmount the namespace
if err := netns.UnmountNS(ctr.state.NetNS); err != nil {
return errors.Wrapf(err, "error unmounting network namespace for container %s", ctr.ID())
Expand Down
4 changes: 4 additions & 0 deletions libpod/networking_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
return define.ErrNotImplemented
}

func (r *Runtime) setupSlirp4netns(ctr *Container) error {
return define.ErrNotImplemented
}

func (r *Runtime) setupNetNS(ctr *Container) error {
return define.ErrNotImplemented
}
Expand Down
4 changes: 2 additions & 2 deletions libpod/oci_conmon_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
cmd.ExtraFiles = append(cmd.ExtraFiles, childSyncPipe, childStartPipe)
cmd.ExtraFiles = append(cmd.ExtraFiles, envFiles...)

if r.reservePorts && !ctr.config.NetMode.IsSlirp4netns() {
if r.reservePorts && !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
ports, err := bindPorts(ctr.config.PortMappings)
if err != nil {
return err
Expand All @@ -1098,7 +1098,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
cmd.ExtraFiles = append(cmd.ExtraFiles, ports...)
}

if ctr.config.NetMode.IsSlirp4netns() {
if ctr.config.NetMode.IsSlirp4netns() || rootless.IsRootless() {
if ctr.config.PostConfigureNetNS {
havePortMapping := len(ctr.Config().PortMappings) > 0
if havePortMapping {
Expand Down
Loading