diff options
author | baude <bbaude@redhat.com> | 2018-07-12 09:51:31 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-07-12 21:45:47 +0000 |
commit | 4f699db8dad05b770b4e02d3de67137517c3463b (patch) | |
tree | a7f474b248d283dd8805da73bf2b63ca56e4fd67 /libpod | |
parent | e615b7d67124c548a3c7b422348821204ce32775 (diff) | |
download | podman-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.go | 42 | ||||
-rw-r--r-- | libpod/container_internal.go | 4 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 4 | ||||
-rw-r--r-- | libpod/networking_linux.go | 77 | ||||
-rw-r--r-- | libpod/options.go | 3 | ||||
-rw-r--r-- | libpod/runtime.go | 5 |
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") } |