From 666d8cf1deeba4113a9b03e0bc208b1a14122733 Mon Sep 17 00:00:00 2001
From: Matthew Heon <matthew.heon@pm.me>
Date: Mon, 17 Feb 2020 16:21:07 -0500
Subject: Add ability for pods to use the host network

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
---
 libpod/options.go                 | 53 ++++++++++++++++++++++++++++++++++-----
 libpod/pod.go                     |  1 +
 libpod/runtime_pod_infra_linux.go | 18 ++++++++-----
 3 files changed, 60 insertions(+), 12 deletions(-)

(limited to 'libpod')

diff --git a/libpod/options.go b/libpod/options.go
index 4957f822d..1d8405841 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -953,6 +953,16 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo
 			return define.ErrCtrFinalized
 		}
 
+		if rootless.IsRootless() {
+			if len(networks) > 0 {
+				return errors.Wrapf(define.ErrInvalidArg, "cannot use CNI networks with rootless containers")
+			}
+		}
+
+		if len(networks) > 1 && (ctr.config.StaticIP != nil || ctr.config.StaticMAC != nil) {
+			return errors.Wrapf(define.ErrInvalidArg, "cannot join more than one CNI network if configuring a static IP or MAC address")
+		}
+
 		if ctr.config.NetNsCtr != "" {
 			return errors.Wrapf(define.ErrInvalidArg, "container is already set to join another container's net ns, cannot create a new net ns")
 		}
@@ -962,12 +972,6 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo
 		ctr.config.CreateNetNS = true
 		ctr.config.PortMappings = portMappings
 
-		if rootless.IsRootless() {
-			if len(networks) > 0 {
-				return errors.New("cannot use CNI networks with rootless containers")
-			}
-		}
-
 		ctr.config.Networks = networks
 
 		return nil
@@ -1792,6 +1796,10 @@ func WithPodStaticIP(ip net.IP) PodCreateOption {
 			return define.ErrPodFinalized
 		}
 
+		if pod.config.InfraContainer.HostNetwork {
+			return errors.Wrapf(define.ErrInvalidArg, "cannot set static IP if host network is specified")
+		}
+
 		if len(pod.config.InfraContainer.Networks) > 1 {
 			return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining more than 1 CNI network")
 		}
@@ -1809,6 +1817,10 @@ func WithPodStaticMAC(mac net.HardwareAddr) PodCreateOption {
 			return define.ErrPodFinalized
 		}
 
+		if pod.config.InfraContainer.HostNetwork {
+			return errors.Wrapf(define.ErrInvalidArg, "cannot set static MAC if host network is specified")
+		}
+
 		if len(pod.config.InfraContainer.Networks) > 1 {
 			return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining more than 1 CNI network")
 		}
@@ -1932,8 +1944,37 @@ func WithPodNetworks(networks []string) PodCreateOption {
 			return define.ErrPodFinalized
 		}
 
+		if (pod.config.InfraContainer.StaticIP != nil || pod.config.InfraContainer.StaticMAC != nil) &&
+			len(networks) > 1 {
+			return errors.Wrapf(define.ErrInvalidArg, "cannot join more than one CNI network if setting a static IP or MAC address")
+		}
+
+		if pod.config.InfraContainer.HostNetwork {
+			return errors.Wrapf(define.ErrInvalidArg, "cannot join pod to CNI networks if host network is specified")
+		}
+
 		pod.config.InfraContainer.Networks = networks
 
 		return nil
 	}
 }
+
+// WithPodHostNetwork tells the pod to use the host's network namespace.
+func WithPodHostNetwork() PodCreateOption {
+	return func(pod *Pod) error {
+		if pod.valid {
+			return define.ErrPodFinalized
+		}
+
+		if len(pod.config.InfraContainer.PortBindings) > 0 ||
+			pod.config.InfraContainer.StaticIP != nil ||
+			pod.config.InfraContainer.StaticMAC != nil ||
+			len(pod.config.InfraContainer.Networks) > 0 {
+			return errors.Wrapf(define.ErrInvalidArg, "cannot set host network if network-related configuration is specified")
+		}
+
+		pod.config.InfraContainer.HostNetwork = true
+
+		return nil
+	}
+}
diff --git a/libpod/pod.go b/libpod/pod.go
index 4f85caf08..1b4c06c9d 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -99,6 +99,7 @@ type PodContainerInfo struct {
 // InfraContainerConfig is the configuration for the pod's infra container
 type InfraContainerConfig struct {
 	HasInfraContainer  bool                 `json:"makeInfraContainer"`
+	HostNetwork        bool                 `json:"infraHostNetwork,omitempty"`
 	PortBindings       []ocicni.PortMapping `json:"infraPortBindings"`
 	StaticIP           net.IP               `json:"staticIP,omitempty"`
 	StaticMAC          net.HardwareAddr     `json:"staticMAC,omitempty"`
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 1b1421ca8..3aded61f2 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -94,13 +94,19 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID
 	options = append(options, withIsInfra())
 
 	// Since user namespace sharing is not implemented, we only need to check if it's rootless
-	netmode := "bridge"
-	if isRootless {
-		netmode = "slirp4netns"
+	if !p.config.InfraContainer.HostNetwork {
+		netmode := "bridge"
+		if isRootless {
+			netmode = "slirp4netns"
+		}
+		// PostConfigureNetNS should not be set since user namespace sharing is not implemented
+		// and rootless networking no longer supports post configuration setup
+		options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, p.config.InfraContainer.Networks))
+	} else {
+		if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
+			return nil, errors.Wrapf(err, "error removing network namespace from pod %s infra container", p.ID())
+		}
 	}
-	// PostConfigureNetNS should not be set since user namespace sharing is not implemented
-	// and rootless networking no longer supports post configuration setup
-	options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, p.config.InfraContainer.Networks))
 
 	if p.config.InfraContainer.StaticIP != nil {
 		options = append(options, WithStaticIP(p.config.InfraContainer.StaticIP))
-- 
cgit v1.2.3-54-g00ecf