summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-07-12 09:51:31 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-07-12 21:45:47 +0000
commit4f699db8dad05b770b4e02d3de67137517c3463b (patch)
treea7f474b248d283dd8805da73bf2b63ca56e4fd67 /libpod
parente615b7d67124c548a3c7b422348821204ce32775 (diff)
downloadpodman-4f699db8dad05b770b4e02d3de67137517c3463b.tar.gz
podman-4f699db8dad05b770b4e02d3de67137517c3463b.tar.bz2
podman-4f699db8dad05b770b4e02d3de67137517c3463b.zip
Support multiple networks
This is a refresh of Dan William's PR #974 with a rebase and proper vendoring of ocicni and containernetworking/cni. It adds the ability to define multiple networks as so: podman run --network=net1,net2,foobar ... Signed-off-by: baude <bbaude@redhat.com> Closes: #1082 Approved by: baude
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go42
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/container_internal_linux.go4
-rw-r--r--libpod/networking_linux.go77
-rw-r--r--libpod/options.go3
-rw-r--r--libpod/runtime.go5
6 files changed, 58 insertions, 77 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 9486986ab..f882868ed 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -143,18 +143,11 @@ type containerState struct {
// ExecSessions contains active exec sessions for container
// Exec session ID is mapped to PID of exec process
ExecSessions map[string]*ExecSession `json:"execSessions,omitempty"`
- // IPs contains IP addresses assigned to the container
- // Only populated if we created a network namespace for the container,
- // and the network namespace is currently active
- IPs []*cnitypes.IPConfig `json:"ipAddresses,omitempty"`
- // Interfaces contains interface information about the container
- // Only populated if we created a network namespace for the container,
- // and the network namespace is currently active
- Interfaces []*cnitypes.Interface `json:"interfaces,omitempty"`
- // Routes contains network routes present in the container
- // Only populated if we created a network namespace for the container,
- // and the network namespace is currently active
- Routes []*types.Route `json:"routes,omitempty"`
+ // NetworkStatus contains the configuration results for all networks
+ // the pod is attached to. Only populated if we created a network
+ // namespace for the container, and the network namespace is currently
+ // active
+ NetworkStatus []*cnitypes.Result `json:"networkResults,omitempty"`
// BindMounts contains files that will be bind-mounted into the
// container when it is mounted.
// These include /etc/hosts and /etc/resolv.conf
@@ -268,6 +261,8 @@ type ContainerConfig struct {
// Hosts to add in container
// Will be appended to host's host file
HostAdd []string `json:"hostsAdd,omitempty"`
+ // Network names (CNI) to add container to. Empty to use default network.
+ Networks []string `json:"networks,omitempty"`
// Image Config
@@ -773,10 +768,12 @@ func (c *Container) IPs() ([]net.IPNet, error) {
return nil, errors.Wrapf(ErrInvalidArg, "container %s network namespace is not managed by libpod")
}
- ips := make([]net.IPNet, 0, len(c.state.IPs))
+ ips := make([]net.IPNet, 0)
- for _, ip := range c.state.IPs {
- ips = append(ips, ip.Address)
+ for _, r := range c.state.NetworkStatus {
+ for _, ip := range r.IPs {
+ ips = append(ips, ip.Address)
+ }
}
return ips, nil
@@ -799,15 +796,16 @@ func (c *Container) Routes() ([]types.Route, error) {
return nil, errors.Wrapf(ErrInvalidArg, "container %s network namespace is not managed by libpod")
}
- routes := make([]types.Route, 0, len(c.state.Routes))
+ routes := make([]types.Route, 0)
- for _, route := range c.state.Routes {
- newRoute := types.Route{
- Dst: route.Dst,
- GW: route.GW,
+ for _, r := range c.state.NetworkStatus {
+ for _, route := range r.Routes {
+ newRoute := types.Route{
+ Dst: route.Dst,
+ GW: route.GW,
+ }
+ routes = append(routes, newRoute)
}
-
- routes = append(routes, newRoute)
}
return routes, nil
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index eb9b39a02..905402c47 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -321,9 +321,7 @@ func resetState(state *containerState) error {
state.Mounted = false
state.State = ContainerStateConfigured
state.ExecSessions = make(map[string]*ExecSession)
- state.IPs = nil
- state.Interfaces = nil
- state.Routes = nil
+ state.NetworkStatus = nil
state.BindMounts = make(map[string]string)
return nil
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 9ad825458..e7e3b6ce9 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -75,9 +75,7 @@ func (c *Container) cleanupNetwork() error {
}
c.state.NetNS = nil
- c.state.IPs = nil
- c.state.Interfaces = nil
- c.state.Routes = nil
+ c.state.NetworkStatus = nil
if c.valid {
return c.save()
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 59666b534..d9eb87572 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -5,7 +5,6 @@ package libpod
import (
"crypto/rand"
"fmt"
- "net"
"os"
"path/filepath"
"strconv"
@@ -24,21 +23,22 @@ import (
)
// Get an OCICNI network config
-func getPodNetwork(id, name, nsPath string, ports []ocicni.PortMapping) ocicni.PodNetwork {
+func getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping) ocicni.PodNetwork {
return ocicni.PodNetwork{
Name: name,
Namespace: name, // TODO is there something else we should put here? We don't know about Kube namespaces
ID: id,
NetNS: nsPath,
PortMappings: ports,
+ Networks: networks,
}
}
// Create and configure a new network namespace for a container
func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
- podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.PortMappings)
+ podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings)
- result, err := r.netPlugin.SetUpPod(podNetwork)
+ results, err := r.netPlugin.SetUpPod(podNetwork)
if err != nil {
return errors.Wrapf(err, "error configuring network namespace for container %s", ctr.ID())
}
@@ -50,28 +50,28 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
}
}()
- logrus.Debugf("Response from CNI plugins: %v", result.String())
-
- resultStruct, err := cnitypes.GetResult(result)
- if err != nil {
- return errors.Wrapf(err, "error parsing result from CNI plugins")
+ ctr.state.NetNS = ctrNS
+ ctr.state.NetworkStatus = make([]*cnitypes.Result, 0)
+ for idx, r := range results {
+ logrus.Debugf("[%d] CNI result: %v", idx, r.String())
+ resultCurrent, err := cnitypes.GetResult(r)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing CNI plugin result %q: %v", r.String(), err)
+ }
+ ctr.state.NetworkStatus = append(ctr.state.NetworkStatus, resultCurrent)
}
- ctr.state.NetNS = ctrNS
- ctr.state.IPs = resultStruct.IPs
- ctr.state.Routes = resultStruct.Routes
- ctr.state.Interfaces = resultStruct.Interfaces
-
- // We need to temporarily use iptables to allow the container
- // to resolve DNS until this issue is fixed upstream.
- // https://github.com/containernetworking/plugins/pull/75
- if resultStruct.IPs != nil {
- for _, ip := range resultStruct.IPs {
+ for _, r := range ctr.state.NetworkStatus {
+ // We need to temporarily use iptables to allow the container
+ // to resolve DNS until this issue is fixed upstream.
+ // https://github.com/containernetworking/plugins/pull/75
+ for _, ip := range r.IPs {
if ip.Address.IP.To4() != nil {
iptablesDNS("-I", ip.Address.IP.String())
}
}
}
+
return nil
}
@@ -148,27 +148,6 @@ func joinNetNS(path string) (ns.NetNS, error) {
return ns, nil
}
-// Get a container's IP address
-func (r *Runtime) getContainerIP(ctr *Container) (net.IP, error) {
- if ctr.state.NetNS == nil {
- return nil, errors.Wrapf(ErrInvalidArg, "container %s has no network namespace, cannot get IP", ctr.ID())
- }
-
- podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.PortMappings)
-
- ipStr, err := r.netPlugin.GetPodNetworkStatus(podNetwork)
- if err != nil {
- return nil, errors.Wrapf(err, "error retrieving network status of container %s", ctr.ID())
- }
-
- ip := net.ParseIP(ipStr)
- if ip == nil {
- return nil, errors.Wrapf(ErrInternal, "error parsing IP address %s for container %s", ipStr, ctr.ID())
- }
-
- return ip, nil
-}
-
// Tear down a network namespace
func (r *Runtime) teardownNetNS(ctr *Container) error {
if ctr.state.NetNS == nil {
@@ -180,15 +159,17 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
// on per IP address, we also need to try to remove the iptables rule
// on cleanup. Remove when https://github.com/containernetworking/plugins/pull/75
// is merged.
- for _, ip := range ctr.state.IPs {
- if ip.Address.IP.To4() != nil {
- iptablesDNS("-D", ip.Address.IP.String())
+ for _, r := range ctr.state.NetworkStatus {
+ for _, ip := range r.IPs {
+ if ip.Address.IP.To4() != nil {
+ iptablesDNS("-D", ip.Address.IP.String())
+ }
}
}
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.PortMappings)
+ podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings)
// The network may have already been torn down, so don't fail here, just log
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
@@ -232,9 +213,11 @@ func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
}
func (c *Container) getContainerNetworkInfo(data *inspect.ContainerInspectData) *inspect.ContainerInspectData {
- if c.state.NetNS != nil {
+ if c.state.NetNS != nil && len(c.state.NetworkStatus) > 0 {
+ // Report network settings from the first pod network
+ result := c.state.NetworkStatus[0]
// Go through our IP addresses
- for _, ctrIP := range c.state.IPs {
+ for _, ctrIP := range result.IPs {
ipWithMask := ctrIP.Address.String()
splitIP := strings.Split(ipWithMask, "/")
mask, _ := strconv.Atoi(splitIP[1])
@@ -253,7 +236,7 @@ func (c *Container) getContainerNetworkInfo(data *inspect.ContainerInspectData)
data.NetworkSettings.SandboxKey = c.state.NetNS.Path()
// Set MAC address of interface linked with network namespace path
- for _, i := range c.state.Interfaces {
+ for _, i := range result.Interfaces {
if i.Sandbox == data.NetworkSettings.SandboxKey {
data.NetworkSettings.MacAddress = i.Mac
}
diff --git a/libpod/options.go b/libpod/options.go
index c02bd4336..718b44930 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -733,7 +733,7 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption {
// namespace with a minimal configuration.
// An optional array of port mappings can be provided.
// Conflicts with WithNetNSFrom().
-func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool) CtrCreateOption {
+func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, networks []string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
@@ -746,6 +746,7 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool) CtrCr
ctr.config.PostConfigureNetNS = postConfigureNetNS
ctr.config.CreateNetNS = true
ctr.config.PortMappings = portMappings
+ ctr.config.Networks = networks
return nil
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index ce64f0d5b..9ba6acb78 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -134,6 +134,9 @@ type RuntimeConfig struct {
CNIPluginDir []string `toml:"cni_plugin_dir"`
// HooksDir Path to the directory containing hooks configuration files
HooksDir string `toml:"hooks_dir"`
+ // CNIDefaultNetwork is the network name of the default CNI network
+ // to attach pods to
+ CNIDefaultNetwork string `toml:"cni_default_network,omitempty"`
// HooksDirNotExistFatal switches between fatal errors and non-fatal warnings if the configured HooksDir does not exist.
HooksDirNotExistFatal bool `toml:"hooks_dir_not_exist_fatal"`
// DefaultMountsFile is the path to the default mounts file for testing purposes only
@@ -442,7 +445,7 @@ func makeRuntime(runtime *Runtime) (err error) {
}
// Set up the CNI net plugin
- netPlugin, err := ocicni.InitCNI(runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...)
+ netPlugin, err := ocicni.InitCNI(runtime.config.CNIDefaultNetwork, runtime.config.CNIConfigDir, runtime.config.CNIPluginDir...)
if err != nil {
return errors.Wrapf(err, "error configuring CNI network plugin")
}