summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_api.go3
-rw-r--r--libpod/container_config.go7
-rw-r--r--libpod/container_inspect.go4
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/container_internal_linux.go22
-rw-r--r--libpod/define/container_inspect.go11
-rw-r--r--libpod/network/cni/cni_conversion.go15
-rw-r--r--libpod/network/cni/cni_types.go15
-rw-r--r--libpod/network/cni/config_test.go13
-rw-r--r--libpod/network/cni/network.go7
-rw-r--r--libpod/network/cni/run.go8
-rw-r--r--libpod/network/cni/run_test.go66
-rw-r--r--libpod/network/netavark/run_test.go48
-rw-r--r--libpod/network/types/network.go20
-rw-r--r--libpod/networking_linux.go100
-rw-r--r--libpod/networking_linux_test.go217
-rw-r--r--libpod/networking_machine.go121
-rw-r--r--libpod/networking_slirp4netns.go10
-rw-r--r--libpod/oci_conmon_linux.go21
-rw-r--r--libpod/options.go14
-rw-r--r--libpod/runtime_ctr.go2
21 files changed, 523 insertions, 205 deletions
diff --git a/libpod/container_api.go b/libpod/container_api.go
index a41bb03df..7ae9f497c 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -798,6 +798,9 @@ type ContainerCheckpointOptions struct {
// how much time each component in the stack requires to
// checkpoint a container.
PrintStats bool
+ // FileLocks tells the API to checkpoint/restore a container
+ // with file-locks
+ FileLocks bool
}
// Checkpoint checkpoints a container
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 412be835f..57f5b92ac 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -364,13 +364,6 @@ type ContainerMiscConfig struct {
PostConfigureNetNS bool `json:"postConfigureNetNS"`
// OCIRuntime used to create the container
OCIRuntime string `json:"runtime,omitempty"`
- // ExitCommand is the container's exit command.
- // This Command will be executed when the container exits by Conmon.
- // It is usually used to invoke post-run cleanup - for example, in
- // Podman, it invokes `podman container cleanup`, which in turn calls
- // Libpod's Cleanup() API to unmount the container and clean up its
- // network.
- ExitCommand []string `json:"exitCommand,omitempty"`
// IsInfra is a bool indicating whether this container is an infra container used for
// sharing kernel namespaces in a pod
IsInfra bool `json:"pause"`
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 277c3b960..76a08ce30 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -119,7 +119,6 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
},
Image: config.RootfsImageID,
ImageName: config.RootfsImageName,
- ExitCommand: config.ExitCommand,
Namespace: config.Namespace,
Rootfs: config.Rootfs,
Pod: config.Pod,
@@ -300,8 +299,7 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp
ctrConfig.User = c.config.User
if spec.Process != nil {
ctrConfig.Tty = spec.Process.Terminal
- ctrConfig.Env = []string{}
- ctrConfig.Env = append(ctrConfig.Env, spec.Process.Env...)
+ ctrConfig.Env = append([]string{}, spec.Process.Env...)
ctrConfig.WorkingDir = spec.Process.Cwd
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 4bf15be86..871c6787a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1050,8 +1050,8 @@ func (c *Container) cniHosts() string {
var hosts string
for _, status := range c.getNetworkStatus() {
for _, netInt := range status.Interfaces {
- for _, netAddress := range netInt.Networks {
- hosts += fmt.Sprintf("%s\t%s %s\n", netAddress.Subnet.IP.String(), c.Hostname(), c.config.Name)
+ for _, netAddress := range netInt.Subnets {
+ hosts += fmt.Sprintf("%s\t%s %s\n", netAddress.IPNet.IP.String(), c.Hostname(), c.config.Name)
}
}
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 1a4508448..364b77f29 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -709,18 +709,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
g.AddAnnotation(annotations.ContainerManager, annotations.ContainerManagerLibpod)
}
- // Only add container environment variable if not already present
- foundContainerEnv := false
- for _, env := range g.Config.Process.Env {
- if strings.HasPrefix(env, "container=") {
- foundContainerEnv = true
- break
- }
- }
- if !foundContainerEnv {
- g.AddProcessEnv("container", "libpod")
- }
-
cgroupPath, err := c.getOCICgroupPath()
if err != nil {
return nil, err
@@ -1353,8 +1341,8 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
perNetOpts.StaticMAC = netInt.MacAddress
}
if !options.IgnoreStaticIP {
- for _, netAddress := range netInt.Networks {
- perNetOpts.StaticIPs = append(perNetOpts.StaticIPs, netAddress.Subnet.IP)
+ for _, netAddress := range netInt.Subnets {
+ perNetOpts.StaticIPs = append(perNetOpts.StaticIPs, netAddress.IPNet.IP)
}
}
// Normally interfaces have a length of 1, only for some special cni configs we could get more.
@@ -1955,9 +1943,9 @@ func (c *Container) generateResolvConf() (string, error) {
netStatus := c.getNetworkStatus()
for _, status := range netStatus {
for _, netInt := range status.Interfaces {
- for _, netAddress := range netInt.Networks {
+ for _, netAddress := range netInt.Subnets {
// Note: only using To16() does not work since it also returns a valid ip for ipv4
- if netAddress.Subnet.IP.To4() == nil && netAddress.Subnet.IP.To16() != nil {
+ if netAddress.IPNet.IP.To4() == nil && netAddress.IPNet.IP.To16() != nil {
ipv6 = true
}
}
@@ -2163,7 +2151,7 @@ func (c *Container) getHosts() string {
if depCtr != nil {
for _, status := range depCtr.getNetworkStatus() {
for _, netInt := range status.Interfaces {
- for _, netAddress := range netInt.Networks {
+ for _, netAddress := range netInt.Subnets {
if netAddress.Gateway != nil {
hosts += fmt.Sprintf("%s host.containers.internal\n", netAddress.Gateway.String())
}
diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go
index 7decb18a8..8e07cff81 100644
--- a/libpod/define/container_inspect.go
+++ b/libpod/define/container_inspect.go
@@ -542,6 +542,12 @@ type InspectContainerHostConfig struct {
CgroupConf map[string]string `json:"CgroupConf"`
}
+// Address represents an IP address.
+type Address struct {
+ Addr string
+ PrefixLength int
+}
+
// InspectBasicNetworkConfig holds basic configuration information (e.g. IP
// addresses, MAC address, subnet masks, etc) that are common for all networks
// (both additional and main).
@@ -556,7 +562,7 @@ type InspectBasicNetworkConfig struct {
IPPrefixLen int `json:"IPPrefixLen"`
// SecondaryIPAddresses is a list of extra IP Addresses that the
// container has been assigned in this network.
- SecondaryIPAddresses []string `json:"SecondaryIPAddresses,omitempty"`
+ SecondaryIPAddresses []Address `json:"SecondaryIPAddresses,omitempty"`
// IPv6Gateway is the IPv6 gateway this network will use.
IPv6Gateway string `json:"IPv6Gateway"`
// GlobalIPv6Address is the global-scope IPv6 Address for this network.
@@ -565,7 +571,7 @@ type InspectBasicNetworkConfig struct {
GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"`
// SecondaryIPv6Addresses is a list of extra IPv6 Addresses that the
// container has been assigned in this network.
- SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty"`
+ SecondaryIPv6Addresses []Address `json:"SecondaryIPv6Addresses,omitempty"`
// MacAddress is the MAC address for the interface in this network.
MacAddress string `json:"MacAddress"`
// AdditionalMacAddresses is a set of additional MAC Addresses beyond
@@ -654,7 +660,6 @@ type InspectContainerData struct {
Mounts []InspectMount `json:"Mounts"`
Dependencies []string `json:"Dependencies"`
NetworkSettings *InspectNetworkSettings `json:"NetworkSettings"` //TODO
- ExitCommand []string `json:"ExitCommand"`
Namespace string `json:"Namespace"`
IsInfra bool `json:"IsInfra"`
Config *InspectContainerConfig `json:"Config"`
diff --git a/libpod/network/cni/cni_conversion.go b/libpod/network/cni/cni_conversion.go
index 70d259b60..788165b5e 100644
--- a/libpod/network/cni/cni_conversion.go
+++ b/libpod/network/cni/cni_conversion.go
@@ -295,10 +295,6 @@ func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writ
// Note: in the future we might like to allow for dynamic domain names
plugins = append(plugins, newDNSNamePlugin(defaultPodmanDomainName))
}
- // Add the podman-machine CNI plugin if we are in a machine
- if n.isMachine {
- plugins = append(plugins, newPodmanMachinePlugin())
- }
case types.MacVLANNetworkDriver:
plugins = append(plugins, newVLANPlugin(types.MacVLANNetworkDriver, network.NetworkInterface, vlanPluginMode, mtu, ipamConf))
@@ -369,3 +365,14 @@ func convertSpecgenPortsToCNIPorts(ports []types.PortMapping) ([]cniPortMapEntry
}
return cniPorts, nil
}
+
+func removeMachinePlugin(conf *libcni.NetworkConfigList) *libcni.NetworkConfigList {
+ plugins := make([]*libcni.NetworkConfig, 0, len(conf.Plugins))
+ for _, net := range conf.Plugins {
+ if net.Network.Type != "podman-machine" {
+ plugins = append(plugins, net)
+ }
+ }
+ conf.Plugins = plugins
+ return conf
+}
diff --git a/libpod/network/cni/cni_types.go b/libpod/network/cni/cni_types.go
index c70cb92b6..e5eb777de 100644
--- a/libpod/network/cni/cni_types.go
+++ b/libpod/network/cni/cni_types.go
@@ -110,12 +110,6 @@ type dnsNameConfig struct {
Capabilities map[string]bool `json:"capabilities"`
}
-// podmanMachineConfig enables port handling on the host OS
-type podmanMachineConfig struct {
- PluginType string `json:"type"`
- Capabilities map[string]bool `json:"capabilities"`
-}
-
// ncList describes a generic map
type ncList map[string]interface{}
@@ -285,12 +279,3 @@ func newVLANPlugin(pluginType, device, mode string, mtu int, ipam ipamConfig) VL
}
return m
}
-
-func newPodmanMachinePlugin() podmanMachineConfig {
- caps := make(map[string]bool, 1)
- caps["portMappings"] = true
- return podmanMachineConfig{
- PluginType: "podman-machine",
- Capabilities: caps,
- }
-}
diff --git a/libpod/network/cni/config_test.go b/libpod/network/cni/config_test.go
index 0dfc6173c..c2e5fc985 100644
--- a/libpod/network/cni/config_test.go
+++ b/libpod/network/cni/config_test.go
@@ -965,19 +965,6 @@ var _ = Describe("Config", func() {
Expect(logString).To(ContainSubstring("dnsname and internal networks are incompatible"))
})
- It("create config with podman machine plugin", func() {
- libpodNet, err := getNetworkInterface(cniConfDir, true)
- Expect(err).To(BeNil())
-
- network := types.Network{}
- network1, err := libpodNet.NetworkCreate(network)
- Expect(err).To(BeNil())
- Expect(network1.Driver).To(Equal("bridge"))
- path := filepath.Join(cniConfDir, network1.Name+".conflist")
- Expect(path).To(BeARegularFile())
- grepInFile(path, `"type": "podman-machine",`)
- })
-
It("network inspect partial ID", func() {
network := types.Network{Name: "net4"}
network1, err := libpodNet.NetworkCreate(network)
diff --git a/libpod/network/cni/network.go b/libpod/network/cni/network.go
index 3e9cdaa47..41e3e414e 100644
--- a/libpod/network/cni/network.go
+++ b/libpod/network/cni/network.go
@@ -150,6 +150,13 @@ func (n *cniNetwork) loadNetworks() error {
continue
}
+ // podman < v4.0 used the podman-machine cni plugin for podman machine port forwarding
+ // since this is now build into podman we no longer use the plugin
+ // old configs may still contain it so we just remove it here
+ if n.isMachine {
+ conf = removeMachinePlugin(conf)
+ }
+
if _, err := n.cniConf.ValidateNetworkList(context.Background(), conf); err != nil {
logrus.Warnf("Error validating CNI config file %s: %v", file, err)
continue
diff --git a/libpod/network/cni/run.go b/libpod/network/cni/run.go
index 667ed3ab1..d0ff49b73 100644
--- a/libpod/network/cni/run.go
+++ b/libpod/network/cni/run.go
@@ -135,8 +135,8 @@ func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) {
cniInt := cniResult.Interfaces[*ip.Interface]
netInt, ok := interfaces[cniInt.Name]
if ok {
- netInt.Networks = append(netInt.Networks, types.NetAddress{
- Subnet: types.IPNet{IPNet: ip.Address},
+ netInt.Subnets = append(netInt.Subnets, types.NetAddress{
+ IPNet: types.IPNet{IPNet: ip.Address},
Gateway: ip.Gateway,
})
interfaces[cniInt.Name] = netInt
@@ -147,8 +147,8 @@ func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) {
}
interfaces[cniInt.Name] = types.NetInterface{
MacAddress: types.HardwareAddr(mac),
- Networks: []types.NetAddress{{
- Subnet: types.IPNet{IPNet: ip.Address},
+ Subnets: []types.NetAddress{{
+ IPNet: types.IPNet{IPNet: ip.Address},
Gateway: ip.Gateway,
}},
}
diff --git a/libpod/network/cni/run_test.go b/libpod/network/cni/run_test.go
index 6c54f82ef..f6cc2d412 100644
--- a/libpod/network/cni/run_test.go
+++ b/libpod/network/cni/run_test.go
@@ -133,8 +133,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ Expect(res[defNet].Interfaces[intName].Subnets[0].IPNet.IP.String()).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
// default network has no dns
Expect(res[defNet].DNSServerIPs).To(BeEmpty())
@@ -170,8 +170,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP).To(Equal(ip))
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ Expect(res[defNet].Interfaces[intName].Subnets[0].IPNet.IP).To(Equal(ip))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
// default network has no dns
Expect(res[defNet].DNSServerIPs).To(BeEmpty())
@@ -209,8 +209,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ Expect(res[defNet].Interfaces[intName].Subnets[0].IPNet.IP.String()).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
// default network has no dns
Expect(res[defNet].DNSServerIPs).To(BeEmpty())
@@ -263,8 +263,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- containerIP := res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ containerIP := res[defNet].Interfaces[intName].Subnets[0].IPNet.IP.String()
Expect(containerIP).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
// default network has no dns
@@ -324,8 +324,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ Expect(res[defNet].Interfaces[intName].Subnets[0].IPNet.IP.String()).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
for _, proto := range []string{"tcp", "udp"} {
@@ -386,8 +386,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveKey(netName1))
Expect(res[netName1].Interfaces).To(HaveKey(intName1))
- Expect(res[netName1].Interfaces[intName1].Networks).To(HaveLen(1))
- ipInt1 := res[netName1].Interfaces[intName1].Networks[0].Subnet.IP
+ Expect(res[netName1].Interfaces[intName1].Subnets).To(HaveLen(1))
+ ipInt1 := res[netName1].Interfaces[intName1].Subnets[0].IPNet.IP
Expect(ipInt1).ToNot(BeEmpty())
macInt1 := res[netName1].Interfaces[intName1].MacAddress
Expect(macInt1).To(HaveLen(6))
@@ -436,8 +436,8 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveKey(netName2))
Expect(res[netName2].Interfaces).To(HaveKey(intName2))
- Expect(res[netName2].Interfaces[intName2].Networks).To(HaveLen(1))
- ipInt2 := res[netName2].Interfaces[intName2].Networks[0].Subnet.IP
+ Expect(res[netName2].Interfaces[intName2].Subnets).To(HaveLen(1))
+ ipInt2 := res[netName2].Interfaces[intName2].Subnets[0].IPNet.IP
Expect(ipInt2).ToNot(BeEmpty())
macInt2 := res[netName2].Interfaces[intName2].MacAddress
Expect(macInt2).To(HaveLen(6))
@@ -576,16 +576,16 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveKey(netName1))
Expect(res[netName1].Interfaces).To(HaveKey(intName1))
- Expect(res[netName1].Interfaces[intName1].Networks).To(HaveLen(1))
- ipInt1 := res[netName1].Interfaces[intName1].Networks[0].Subnet.IP
+ Expect(res[netName1].Interfaces[intName1].Subnets).To(HaveLen(1))
+ ipInt1 := res[netName1].Interfaces[intName1].Subnets[0].IPNet.IP
Expect(ipInt1.String()).To(ContainSubstring("192.168.0."))
macInt1 := res[netName1].Interfaces[intName1].MacAddress
Expect(macInt1).To(HaveLen(6))
Expect(res).To(HaveKey(netName2))
Expect(res[netName2].Interfaces).To(HaveKey(intName2))
- Expect(res[netName2].Interfaces[intName2].Networks).To(HaveLen(1))
- ipInt2 := res[netName2].Interfaces[intName2].Networks[0].Subnet.IP
+ Expect(res[netName2].Interfaces[intName2].Subnets).To(HaveLen(1))
+ ipInt2 := res[netName2].Interfaces[intName2].Subnets[0].IPNet.IP
Expect(ipInt2.String()).To(ContainSubstring("192.168.1."))
macInt2 := res[netName2].Interfaces[intName2].MacAddress
Expect(macInt2).To(HaveLen(6))
@@ -701,13 +701,13 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(netName))
Expect(res[netName].Interfaces).To(HaveKey(interfaceName))
- Expect(res[netName].Interfaces[interfaceName].Networks).To(HaveLen(2))
- Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.IP.String()).To(Equal(ip1.String()))
- Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.Mask).To(Equal(subnet1.Mask))
- Expect(res[netName].Interfaces[interfaceName].Networks[0].Gateway).To(Equal(net.ParseIP("192.168.0.1")))
- Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.IP.String()).To(Equal(ip2.String()))
- Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.Mask).To(Equal(subnet2.Mask))
- Expect(res[netName].Interfaces[interfaceName].Networks[1].Gateway).To(Equal(net.ParseIP("fd41:0a75:2ca0:48a9::1")))
+ Expect(res[netName].Interfaces[interfaceName].Subnets).To(HaveLen(2))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[0].IPNet.IP.String()).To(Equal(ip1.String()))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[0].IPNet.Mask).To(Equal(subnet1.Mask))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[0].Gateway).To(Equal(net.ParseIP("192.168.0.1")))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[1].IPNet.IP.String()).To(Equal(ip2.String()))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[1].IPNet.Mask).To(Equal(subnet2.Mask))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[1].Gateway).To(Equal(net.ParseIP("fd41:0a75:2ca0:48a9::1")))
Expect(res[netName].Interfaces[interfaceName].MacAddress).To(Equal(types.HardwareAddr(mac)))
// default network has no dns
Expect(res[netName].DNSServerIPs).To(BeEmpty())
@@ -799,9 +799,9 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(netName))
Expect(res[netName].Interfaces).To(HaveKey(intName))
- Expect(res[netName].Interfaces[intName].Networks).To(HaveLen(1))
- Expect(res[netName].Interfaces[intName].Networks[0].Subnet.IP.String()).To(Equal(ip))
- Expect(res[netName].Interfaces[intName].Networks[0].Subnet.Mask).To(Equal(net.CIDRMask(24, 32)))
+ Expect(res[netName].Interfaces[intName].Subnets).To(HaveLen(1))
+ Expect(res[netName].Interfaces[intName].Subnets[0].IPNet.IP.String()).To(Equal(ip))
+ Expect(res[netName].Interfaces[intName].Subnets[0].IPNet.Mask).To(Equal(net.CIDRMask(24, 32)))
// check in the container namespace if the settings are applied
err = netNSContainer.Do(func(_ ns.NetNS) error {
@@ -902,11 +902,11 @@ var _ = Describe("run CNI", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(netName))
Expect(res[netName].Interfaces).To(HaveKey(interfaceName))
- Expect(res[netName].Interfaces[interfaceName].Networks).To(HaveLen(2))
- Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.IP.String()).To(Equal(ip1.String()))
- Expect(res[netName].Interfaces[interfaceName].Networks[0].Subnet.Mask).To(Equal(mask1))
- Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.IP.String()).To(Equal(ip2.String()))
- Expect(res[netName].Interfaces[interfaceName].Networks[1].Subnet.Mask).To(Equal(mask2))
+ Expect(res[netName].Interfaces[interfaceName].Subnets).To(HaveLen(2))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[0].IPNet.IP.String()).To(Equal(ip1.String()))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[0].IPNet.Mask).To(Equal(mask1))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[1].IPNet.IP.String()).To(Equal(ip2.String()))
+ Expect(res[netName].Interfaces[interfaceName].Subnets[1].IPNet.Mask).To(Equal(mask2))
// dualstack network dns
Expect(res[netName].DNSServerIPs).To(HaveLen(2))
Expect(res[netName].DNSSearchDomains).To(HaveLen(1))
diff --git a/libpod/network/netavark/run_test.go b/libpod/network/netavark/run_test.go
index 3279203cc..67dc51c10 100644
--- a/libpod/network/netavark/run_test.go
+++ b/libpod/network/netavark/run_test.go
@@ -131,10 +131,10 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- ip := res[defNet].Interfaces[intName].Networks[0].Subnet.IP
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ ip := res[defNet].Interfaces[intName].Subnets[0].IPNet.IP
Expect(ip.String()).To(ContainSubstring("10.88.0."))
- gw := res[defNet].Interfaces[intName].Networks[0].Gateway
+ gw := res[defNet].Interfaces[intName].Subnets[0].Gateway
util.NormalizeIP(&gw)
Expect(gw.String()).To(Equal("10.88.0.1"))
macAddress := res[defNet].Interfaces[intName].MacAddress
@@ -222,8 +222,8 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- ip1 := res[defNet].Interfaces[intName].Networks[0].Subnet.IP
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ ip1 := res[defNet].Interfaces[intName].Subnets[0].IPNet.IP
Expect(ip1.String()).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
@@ -246,8 +246,8 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- ip2 := res[defNet].Interfaces[intName].Networks[0].Subnet.IP
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ ip2 := res[defNet].Interfaces[intName].Subnets[0].IPNet.IP
Expect(ip2.String()).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
Expect(ip1.Equal(ip2)).To(BeFalse(), "IP1 %s should not be equal to IP2 %s", ip1.String(), ip2.String())
@@ -286,14 +286,14 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(netName))
Expect(res[netName].Interfaces).To(HaveKey(intName))
- Expect(res[netName].Interfaces[intName].Networks).To(HaveLen(2))
- ip1 := res[netName].Interfaces[intName].Networks[0].Subnet.IP
+ Expect(res[netName].Interfaces[intName].Subnets).To(HaveLen(2))
+ ip1 := res[netName].Interfaces[intName].Subnets[0].IPNet.IP
Expect(ip1.String()).To(ContainSubstring("10.0.0."))
- gw1 := res[netName].Interfaces[intName].Networks[0].Gateway
+ gw1 := res[netName].Interfaces[intName].Subnets[0].Gateway
Expect(gw1.String()).To(Equal("10.0.0.1"))
- ip2 := res[netName].Interfaces[intName].Networks[1].Subnet.IP
+ ip2 := res[netName].Interfaces[intName].Subnets[1].IPNet.IP
Expect(ip2.String()).To(ContainSubstring("fd10:88:a::"))
- gw2 := res[netName].Interfaces[intName].Networks[0].Gateway
+ gw2 := res[netName].Interfaces[intName].Subnets[0].Gateway
Expect(gw2.String()).To(Equal("fd10:88:a::1"))
Expect(res[netName].Interfaces[intName].MacAddress).To(HaveLen(6))
@@ -380,14 +380,14 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveKey(netName2))
Expect(res[netName1].Interfaces).To(HaveKey(intName1))
Expect(res[netName2].Interfaces).To(HaveKey(intName2))
- Expect(res[netName1].Interfaces[intName1].Networks).To(HaveLen(1))
- ip1 := res[netName1].Interfaces[intName1].Networks[0].Subnet.IP
+ Expect(res[netName1].Interfaces[intName1].Subnets).To(HaveLen(1))
+ ip1 := res[netName1].Interfaces[intName1].Subnets[0].IPNet.IP
Expect(ip1.String()).To(ContainSubstring("10.0.0."))
- gw1 := res[netName1].Interfaces[intName1].Networks[0].Gateway
+ gw1 := res[netName1].Interfaces[intName1].Subnets[0].Gateway
Expect(gw1.String()).To(Equal("10.0.0.1"))
- ip2 := res[netName2].Interfaces[intName2].Networks[0].Subnet.IP
+ ip2 := res[netName2].Interfaces[intName2].Subnets[0].IPNet.IP
Expect(ip2.String()).To(ContainSubstring("10.1.0."))
- gw2 := res[netName2].Interfaces[intName2].Networks[0].Gateway
+ gw2 := res[netName2].Interfaces[intName2].Subnets[0].Gateway
Expect(gw2.String()).To(Equal("10.1.0.1"))
mac1 := res[netName1].Interfaces[intName1].MacAddress
Expect(mac1).To(HaveLen(6))
@@ -481,8 +481,8 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- Expect(res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()).To(ContainSubstring("10.88.0."))
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ Expect(res[defNet].Interfaces[intName].Subnets[0].IPNet.IP.String()).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
// default network has no dns
Expect(res[defNet].DNSServerIPs).To(BeEmpty())
@@ -535,8 +535,8 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- containerIP := res[defNet].Interfaces[intName].Networks[0].Subnet.IP.String()
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ containerIP := res[defNet].Interfaces[intName].Subnets[0].IPNet.IP.String()
Expect(containerIP).To(ContainSubstring("10.88.0."))
Expect(res[defNet].Interfaces[intName].MacAddress).To(HaveLen(6))
// default network has no dns
@@ -593,10 +593,10 @@ var _ = Describe("run netavark", func() {
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(defNet))
Expect(res[defNet].Interfaces).To(HaveKey(intName))
- Expect(res[defNet].Interfaces[intName].Networks).To(HaveLen(1))
- ip := res[defNet].Interfaces[intName].Networks[0].Subnet.IP
+ Expect(res[defNet].Interfaces[intName].Subnets).To(HaveLen(1))
+ ip := res[defNet].Interfaces[intName].Subnets[0].IPNet.IP
Expect(ip.String()).To(ContainSubstring("10.88.0."))
- gw := res[defNet].Interfaces[intName].Networks[0].Gateway
+ gw := res[defNet].Interfaces[intName].Subnets[0].Gateway
Expect(gw.String()).To(Equal("10.88.0.1"))
macAddress := res[defNet].Interfaces[intName].MacAddress
Expect(macAddress).To(HaveLen(6))
diff --git a/libpod/network/types/network.go b/libpod/network/types/network.go
index ba5e018fd..105641e70 100644
--- a/libpod/network/types/network.go
+++ b/libpod/network/types/network.go
@@ -38,11 +38,11 @@ type Network struct {
ID string `json:"id"`
// Driver for this Network, e.g. bridge, macvlan...
Driver string `json:"driver"`
- // InterfaceName is the network interface name on the host.
+ // NetworkInterface is the network interface name on the host.
NetworkInterface string `json:"network_interface,omitempty"`
// Created contains the timestamp when this network was created.
Created time.Time `json:"created,omitempty"`
- // Subnets to use.
+ // Subnets to use for this network.
Subnets []Subnet `json:"subnets,omitempty"`
// IPv6Enabled if set to true an ipv6 subnet should be created for this net.
IPv6Enabled bool `json:"ipv6_enabled"`
@@ -177,24 +177,24 @@ type StatusBlock struct {
// NetInterface contains the settings for a given network interface.
type NetInterface struct {
- // Networks list of assigned subnets with their gateway.
- Networks []NetAddress `json:"networks,omitempty"`
+ // Subnets list of assigned subnets with their gateway.
+ Subnets []NetAddress `json:"subnets,omitempty"`
// MacAddress for this Interface.
MacAddress HardwareAddr `json:"mac_address"`
}
-// NetAddress contains the subnet and gateway.
+// NetAddress contains the ip address, subnet and gateway.
type NetAddress struct {
- // Subnet of this NetAddress. Note that the subnet contains the
- // actual ip of the net interface and not the network address.
- Subnet IPNet `json:"subnet"`
- // Gateway for the Subnet. This can be nil if there is no gateway, e.g. internal network.
+ // IPNet of this NetAddress. Note that this is a subnet but it has to contain the
+ // actual ip of the network interface and not the network address.
+ IPNet IPNet `json:"ipnet"`
+ // Gateway for the network. This can be empty if there is no gateway, e.g. internal network.
Gateway net.IP `json:"gateway,omitempty"`
}
// PerNetworkOptions are options which should be set on a per network basis.
type PerNetworkOptions struct {
- // StaticIPv4 for this container. Optional.
+ // StaticIPs for this container. Optional.
StaticIPs []net.IP `json:"static_ips,omitempty"`
// Aliases contains a list of names which the dns server should resolve
// to this container. Should only be set when DNSEnabled is true on the Network.
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index fc91155fa..7d1214183 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -4,6 +4,7 @@ package libpod
import (
"crypto/rand"
+ "crypto/sha1"
"fmt"
"io/ioutil"
"net"
@@ -87,12 +88,28 @@ func (c *Container) GetNetworkAliases(netName string) ([]string, error) {
return aliases, nil
}
+// convertPortMappings will remove the HostIP part from the ports when running inside podman machine.
+// This is need because a HostIP of 127.0.0.1 would now allow the gvproxy forwarder to reach to open ports.
+// For machine the HostIP must only be used by gvproxy and never in the VM.
+func (c *Container) convertPortMappings() []types.PortMapping {
+ if !c.runtime.config.Engine.MachineEnabled || len(c.config.PortMappings) == 0 {
+ return c.config.PortMappings
+ }
+ // if we run in a machine VM we have to ignore the host IP part
+ newPorts := make([]types.PortMapping, 0, len(c.config.PortMappings))
+ for _, port := range c.config.PortMappings {
+ port.HostIP = ""
+ newPorts = append(newPorts, port)
+ }
+ return newPorts
+}
+
func (c *Container) getNetworkOptions() (types.NetworkOptions, error) {
opts := types.NetworkOptions{
ContainerID: c.config.ID,
ContainerName: getCNIPodName(c),
}
- opts.PortMappings = c.config.PortMappings
+ opts.PortMappings = c.convertPortMappings()
networks, _, err := c.networks()
if err != nil {
return opts, err
@@ -384,10 +401,7 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return nil, nil
}
var rootlessNetNS *RootlessNetNS
- runDir, err := util.GetRuntimeDir()
- if err != nil {
- return nil, err
- }
+ runDir := r.config.Engine.TmpDir
lfile := filepath.Join(runDir, "rootless-netns.lock")
lock, err := lockfile.GetLockfile(lfile)
@@ -413,7 +427,15 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
if err != nil {
return nil, err
}
- path := filepath.Join(nsDir, rootlessNetNsName)
+
+ // create a hash from the static dir
+ // the cleanup will check if there are running containers
+ // if you run a several libpod instances with different root/runroot directories this check will fail
+ // we want one netns for each libpod static dir so we use the hash to prevent name collisions
+ hash := sha1.Sum([]byte(r.config.Engine.StaticDir))
+ netnsName := fmt.Sprintf("%s-%x", rootlessNetNsName, hash[:10])
+
+ path := filepath.Join(nsDir, netnsName)
ns, err := ns.GetNS(path)
if err != nil {
if !new {
@@ -421,8 +443,8 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return nil, errors.Wrap(err, "error getting rootless network namespace")
}
// create a new namespace
- logrus.Debug("creating rootless network namespace")
- ns, err = netns.NewNSWithName(rootlessNetNsName)
+ logrus.Debugf("creating rootless network namespace with name %q", netnsName)
+ ns, err = netns.NewNSWithName(netnsName)
if err != nil {
return nil, errors.Wrap(err, "error creating rootless network namespace")
}
@@ -591,32 +613,9 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return rootlessNetNS, nil
}
-// setPrimaryMachineIP is used for podman-machine and it sets
-// and environment variable with the IP address of the podman-machine
-// host.
-func setPrimaryMachineIP() error {
- // no connection is actually made here
- conn, err := net.Dial("udp", "8.8.8.8:80")
- if err != nil {
- return err
- }
- defer func() {
- if err := conn.Close(); err != nil {
- logrus.Error(err)
- }
- }()
- addr := conn.LocalAddr().(*net.UDPAddr)
- return os.Setenv("PODMAN_MACHINE_HOST", addr.IP.String())
-}
-
// setUpNetwork will set up the the networks, on error it will also tear down the cni
// networks. If rootless it will join/create the rootless network namespace.
func (r *Runtime) setUpNetwork(ns string, opts types.NetworkOptions) (map[string]types.StatusBlock, error) {
- if r.config.MachineEnabled() {
- if err := setPrimaryMachineIP(); err != nil {
- return nil, err
- }
- }
rootlessNetNS, err := r.GetRootlessNetNs(true)
if err != nil {
return nil, err
@@ -650,7 +649,18 @@ func getCNIPodName(c *Container) string {
}
// Create and configure a new network namespace for a container
-func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (map[string]types.StatusBlock, error) {
+func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (status map[string]types.StatusBlock, rerr error) {
+ if err := r.exposeMachinePorts(ctr.config.PortMappings); err != nil {
+ return nil, err
+ }
+ defer func() {
+ // make sure to unexpose the gvproxy ports when an error happens
+ if rerr != nil {
+ if err := r.unexposeMachinePorts(ctr.config.PortMappings); err != nil {
+ logrus.Errorf("failed to free gvproxy machine ports: %v", err)
+ }
+ }
+ }()
if ctr.config.NetMode.IsSlirp4netns() {
return nil, r.setupSlirp4netns(ctr, ctrNS)
}
@@ -836,6 +846,10 @@ func (r *Runtime) teardownCNI(ctr *Container) error {
// Tear down a network namespace, undoing all state associated with it.
func (r *Runtime) teardownNetNS(ctr *Container) error {
+ if err := r.unexposeMachinePorts(ctr.config.PortMappings); err != nil {
+ // do not return an error otherwise we would prevent network cleanup
+ logrus.Errorf("failed to free gvproxy machine ports: %v", err)
+ }
if err := r.teardownCNI(ctr); err != nil {
return err
}
@@ -929,8 +943,8 @@ func (r *Runtime) reloadContainerNetwork(ctr *Container) (map[string]types.Statu
Aliases: aliases[network],
StaticMAC: netInt.MacAddress,
}
- for _, netAddress := range netInt.Networks {
- perNetOpts.StaticIPs = append(perNetOpts.StaticIPs, netAddress.Subnet.IP)
+ for _, netAddress := range netInt.Subnets {
+ perNetOpts.StaticIPs = append(perNetOpts.StaticIPs, netAddress.IPNet.IP)
}
// Normally interfaces have a length of 1, only for some special cni configs we could get more.
// For now just use the first interface to get the ips this should be good enough for most cases.
@@ -1116,25 +1130,25 @@ func (c *Container) setupNetworkDescriptions(networks []string) error {
func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNetworkConfig, error) {
config := define.InspectBasicNetworkConfig{}
for _, netInt := range result.Interfaces {
- for _, netAddress := range netInt.Networks {
- size, _ := netAddress.Subnet.Mask.Size()
- if netAddress.Subnet.IP.To4() != nil {
+ for _, netAddress := range netInt.Subnets {
+ size, _ := netAddress.IPNet.Mask.Size()
+ if netAddress.IPNet.IP.To4() != nil {
//ipv4
if config.IPAddress == "" {
- config.IPAddress = netAddress.Subnet.IP.String()
+ config.IPAddress = netAddress.IPNet.IP.String()
config.IPPrefixLen = size
config.Gateway = netAddress.Gateway.String()
} else {
- config.SecondaryIPAddresses = append(config.SecondaryIPAddresses, netAddress.Subnet.IP.String())
+ config.SecondaryIPAddresses = append(config.SecondaryIPAddresses, define.Address{Addr: netAddress.IPNet.IP.String(), PrefixLength: size})
}
} else {
//ipv6
if config.GlobalIPv6Address == "" {
- config.GlobalIPv6Address = netAddress.Subnet.IP.String()
+ config.GlobalIPv6Address = netAddress.IPNet.IP.String()
config.GlobalIPv6PrefixLen = size
config.IPv6Gateway = netAddress.Gateway.String()
} else {
- config.SecondaryIPv6Addresses = append(config.SecondaryIPv6Addresses, netAddress.Subnet.IP.String())
+ config.SecondaryIPv6Addresses = append(config.SecondaryIPv6Addresses, define.Address{Addr: netAddress.IPNet.IP.String(), PrefixLength: size})
}
}
}
@@ -1206,7 +1220,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
ContainerID: c.config.ID,
ContainerName: getCNIPodName(c),
}
- opts.PortMappings = c.config.PortMappings
+ opts.PortMappings = c.convertPortMappings()
eth, exists := c.state.NetInterfaceDescriptions.getInterfaceByName(netName)
if !exists {
return errors.Errorf("no network interface name for container %s on network %s", c.config.ID, netName)
@@ -1298,7 +1312,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
ContainerID: c.config.ID,
ContainerName: getCNIPodName(c),
}
- opts.PortMappings = c.config.PortMappings
+ opts.PortMappings = c.convertPortMappings()
eth, exists := c.state.NetInterfaceDescriptions.getInterfaceByName(netName)
if !exists {
return errors.Errorf("no network interface name for container %s on network %s", c.config.ID, netName)
diff --git a/libpod/networking_linux_test.go b/libpod/networking_linux_test.go
index 06bf05723..d925b69f7 100644
--- a/libpod/networking_linux_test.go
+++ b/libpod/networking_linux_test.go
@@ -2,10 +2,14 @@ package libpod
import (
"fmt"
+ "net"
+ "reflect"
"testing"
- "github.com/containers/podman/v3/libpod/network/types"
"github.com/stretchr/testify/assert"
+
+ "github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/libpod/network/types"
)
func Test_ocicniPortsToNetTypesPorts(t *testing.T) {
@@ -234,6 +238,217 @@ func Test_ocicniPortsToNetTypesPorts(t *testing.T) {
}
}
+func Test_resultToBasicNetworkConfig(t *testing.T) {
+ testCases := []struct {
+ description string
+ expectError bool
+ inputResult types.StatusBlock
+ expectedNetworkConfig define.InspectBasicNetworkConfig
+ }{
+ {
+ description: "single secondary IPv4 address is shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("172.26.0.1"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.2"),
+ Mask: net.CIDRMask(20, 32),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.3"),
+ Mask: net.CIDRMask(10, 32),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ IPAddress: "172.26.0.2",
+ IPPrefixLen: 20,
+ Gateway: "172.26.0.1",
+ SecondaryIPAddresses: []define.Address{
+ {
+ Addr: "172.26.0.3",
+ PrefixLength: 10,
+ },
+ },
+ },
+ },
+ {
+ description: "multiple secondary IPv4 addresses are shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("172.26.0.1"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.2"),
+ Mask: net.CIDRMask(20, 32),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.3"),
+ Mask: net.CIDRMask(10, 32),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("172.26.0.4"),
+ Mask: net.CIDRMask(24, 32),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ IPAddress: "172.26.0.2",
+ IPPrefixLen: 20,
+ Gateway: "172.26.0.1",
+ SecondaryIPAddresses: []define.Address{
+ {
+ Addr: "172.26.0.3",
+ PrefixLength: 10,
+ },
+ {
+ Addr: "172.26.0.4",
+ PrefixLength: 24,
+ },
+ },
+ },
+ },
+ {
+ description: "single secondary IPv6 address is shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("ff02::fb"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fc"),
+ Mask: net.CIDRMask(20, 128),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fd"),
+ Mask: net.CIDRMask(10, 128),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ GlobalIPv6Address: "ff02::fc",
+ GlobalIPv6PrefixLen: 20,
+ IPv6Gateway: "ff02::fb",
+ SecondaryIPv6Addresses: []define.Address{
+ {
+ Addr: "ff02::fd",
+ PrefixLength: 10,
+ },
+ },
+ },
+ },
+ {
+ description: "multiple secondary IPv6 addresses are shown as define.Address",
+ inputResult: types.StatusBlock{
+ Interfaces: map[string]types.NetInterface{
+ "eth1": {
+ Subnets: []types.NetAddress{
+ {
+ Gateway: net.ParseIP("ff02::fb"),
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fc"),
+ Mask: net.CIDRMask(20, 128),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fd"),
+ Mask: net.CIDRMask(10, 128),
+ },
+ },
+ },
+ {
+ IPNet: types.IPNet{
+ IPNet: net.IPNet{
+ IP: net.ParseIP("ff02::fe"),
+ Mask: net.CIDRMask(24, 128),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expectedNetworkConfig: define.InspectBasicNetworkConfig{
+ GlobalIPv6Address: "ff02::fc",
+ GlobalIPv6PrefixLen: 20,
+ IPv6Gateway: "ff02::fb",
+ SecondaryIPv6Addresses: []define.Address{
+ {
+ Addr: "ff02::fd",
+ PrefixLength: 10,
+ },
+ {
+ Addr: "ff02::fe",
+ PrefixLength: 24,
+ },
+ },
+ },
+ },
+ }
+
+ for _, tcl := range testCases {
+ tc := tcl
+ t.Run(tc.description, func(t *testing.T) {
+ t.Parallel()
+ actualNetworkConfig, err := resultToBasicNetworkConfig(tc.inputResult)
+
+ if tc.expectError && err == nil {
+ t.Fatalf("Expected error didn't happen")
+ }
+
+ if !tc.expectError && err != nil {
+ t.Fatalf("Unexpected error happened: %v", err)
+ }
+
+ if !reflect.DeepEqual(tc.expectedNetworkConfig, actualNetworkConfig) {
+ t.Fatalf(
+ "Expected networkConfig %+v didn't match actual value %+v", tc.expectedNetworkConfig, actualNetworkConfig)
+ }
+ })
+ }
+}
+
func benchmarkOCICNIPortsToNetTypesPorts(b *testing.B, ports []types.OCICNIPortMapping) {
for n := 0; n < b.N; n++ {
ocicniPortsToNetTypesPorts(ports)
diff --git a/libpod/networking_machine.go b/libpod/networking_machine.go
new file mode 100644
index 000000000..7cb2a00f7
--- /dev/null
+++ b/libpod/networking_machine.go
@@ -0,0 +1,121 @@
+package libpod
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "strconv"
+ "strings"
+
+ "github.com/containers/podman/v3/libpod/network/types"
+ "github.com/sirupsen/logrus"
+)
+
+const machineGvproxyEndpoint = "gateway.containers.internal"
+
+// machineExpose is the struct for the gvproxy port forwarding api send via json
+type machineExpose struct {
+ // Local is the local address on the vm host, format is ip:port
+ Local string `json:"local"`
+ // Remote is used to specify the vm ip:port
+ Remote string `json:"remote,omitempty"`
+ // Protocol to forward, tcp or udp
+ Protocol string `json:"protocol"`
+}
+
+func requestMachinePorts(expose bool, ports []types.PortMapping) error {
+ url := "http://" + machineGvproxyEndpoint + "/services/forwarder/"
+ if expose {
+ url = url + "expose"
+ } else {
+ url = url + "unexpose"
+ }
+ ctx := context.Background()
+ client := &http.Client{}
+ buf := new(bytes.Buffer)
+ for num, port := range ports {
+ protocols := strings.Split(port.Protocol, ",")
+ for _, protocol := range protocols {
+ for i := uint16(0); i < port.Range; i++ {
+ machinePort := machineExpose{
+ Local: net.JoinHostPort(port.HostIP, strconv.FormatInt(int64(port.HostPort+i), 10)),
+ Protocol: protocol,
+ }
+ if expose {
+ // only set the remote port the ip will be automatically be set by gvproxy
+ machinePort.Remote = ":" + strconv.FormatInt(int64(port.HostPort+i), 10)
+ }
+
+ // post request
+ if err := json.NewEncoder(buf).Encode(machinePort); err != nil {
+ if expose {
+ // in case of an error make sure to unexpose the other ports
+ if cerr := requestMachinePorts(false, ports[:num]); cerr != nil {
+ logrus.Errorf("failed to free gvproxy machine ports: %v", cerr)
+ }
+ }
+ return err
+ }
+ if err := makeMachineRequest(ctx, client, url, buf); err != nil {
+ if expose {
+ // in case of an error make sure to unexpose the other ports
+ if cerr := requestMachinePorts(false, ports[:num]); cerr != nil {
+ logrus.Errorf("failed to free gvproxy machine ports: %v", cerr)
+ }
+ }
+ return err
+ }
+ buf.Reset()
+ }
+ }
+ }
+ return nil
+}
+
+func makeMachineRequest(ctx context.Context, client *http.Client, url string, buf io.Reader) error {
+ //var buf io.ReadWriter
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, buf)
+ if err != nil {
+ return err
+ }
+ req.Header.Add("Accept", "application/json")
+ req.Header.Add("Content-Type", "application/json")
+ resp, err := client.Do(req)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return annotateGvproxyResponseError(resp.Body)
+ }
+ return nil
+}
+
+func annotateGvproxyResponseError(r io.Reader) error {
+ b, err := ioutil.ReadAll(r)
+ if err == nil && len(b) > 0 {
+ return fmt.Errorf("something went wrong with the request: %q", string(b))
+ }
+ return errors.New("something went wrong with the request, could not read response")
+}
+
+// exposeMachinePorts exposes the ports for podman machine via gvproxy
+func (r *Runtime) exposeMachinePorts(ports []types.PortMapping) error {
+ if !r.config.Engine.MachineEnabled {
+ return nil
+ }
+ return requestMachinePorts(true, ports)
+}
+
+// unexposeMachinePorts closes the ports for podman machine via gvproxy
+func (r *Runtime) unexposeMachinePorts(ports []types.PortMapping) error {
+ if !r.config.Engine.MachineEnabled {
+ return nil
+ }
+ return requestMachinePorts(false, ports)
+}
diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go
index 674075e23..cc1b3cfdc 100644
--- a/libpod/networking_slirp4netns.go
+++ b/libpod/networking_slirp4netns.go
@@ -509,7 +509,7 @@ func (r *Runtime) setupRootlessPortMappingViaRLK(ctr *Container, netnsPath strin
childIP := getRootlessPortChildIP(ctr, netStatus)
cfg := rootlessport.Config{
- Mappings: ctr.config.PortMappings,
+ Mappings: ctr.convertPortMappings(),
NetNSPath: netnsPath,
ExitFD: 3,
ReadyFD: 4,
@@ -594,7 +594,7 @@ func (r *Runtime) setupRootlessPortMappingViaSlirp(ctr *Container, cmd *exec.Cmd
// for each port we want to add we need to open a connection to the slirp4netns control socket
// and send the add_hostfwd command.
- for _, i := range ctr.config.PortMappings {
+ for _, i := range ctr.convertPortMappings() {
conn, err := net.Dial("unix", apiSocket)
if err != nil {
return errors.Wrapf(err, "cannot open connection to %s", apiSocket)
@@ -660,12 +660,12 @@ func getRootlessPortChildIP(c *Container, netStatus map[string]types.StatusBlock
var ipv6 net.IP
for _, status := range netStatus {
for _, netInt := range status.Interfaces {
- for _, netAddress := range netInt.Networks {
- ipv4 := netAddress.Subnet.IP.To4()
+ for _, netAddress := range netInt.Subnets {
+ ipv4 := netAddress.IPNet.IP.To4()
if ipv4 != nil {
return ipv4.String()
}
- ipv6 = netAddress.Subnet.IP
+ ipv6 = netAddress.IPNet.IP
}
}
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 533a0d78b..bcf45ec8d 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -30,6 +30,7 @@ import (
"github.com/containers/podman/v3/pkg/checkpoint/crutils"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/rootless"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/podman/v3/utils"
"github.com/containers/storage/pkg/homedir"
@@ -794,6 +795,9 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
if options.TCPEstablished {
args = append(args, "--tcp-established")
}
+ if options.FileLocks {
+ args = append(args, "--file-locks")
+ }
if !options.PreCheckPoint && options.KeepRunning {
args = append(args, "--leave-running")
}
@@ -1071,11 +1075,15 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
args = append(args, "--no-pivot")
}
- if len(ctr.config.ExitCommand) > 0 {
- args = append(args, "--exit-command", ctr.config.ExitCommand[0])
- for _, arg := range ctr.config.ExitCommand[1:] {
- args = append(args, []string{"--exit-command-arg", arg}...)
- }
+ exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), false)
+ if err != nil {
+ return 0, err
+ }
+ exitCommand = append(exitCommand, ctr.config.ID)
+
+ args = append(args, "--exit-command", exitCommand[0])
+ for _, arg := range exitCommand[1:] {
+ args = append(args, []string{"--exit-command-arg", arg}...)
}
// Pass down the LISTEN_* environment (see #10443).
@@ -1101,6 +1109,9 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if restoreOptions.TCPEstablished {
args = append(args, "--runtime-opt", "--tcp-established")
}
+ if restoreOptions.FileLocks {
+ args = append(args, "--runtime-opt", "--file-locks")
+ }
if restoreOptions.Pod != "" {
mountLabel := ctr.config.MountLabel
processLabel := ctr.config.ProcessLabel
diff --git a/libpod/options.go b/libpod/options.go
index 0cc4c784c..3f0f9fbe0 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -835,20 +835,6 @@ func WithIDMappings(idmappings storage.IDMappingOptions) CtrCreateOption {
}
}
-// WithExitCommand sets the ExitCommand for the container, appending on the ctr.ID() to the end
-func WithExitCommand(exitCommand []string) CtrCreateOption {
- return func(ctr *Container) error {
- if ctr.valid {
- return define.ErrCtrFinalized
- }
-
- ctr.config.ExitCommand = exitCommand
- ctr.config.ExitCommand = append(ctr.config.ExitCommand, ctr.ID())
-
- return nil
- }
-}
-
// WithUTSNSFromPod indicates the the container should join the UTS namespace of
// its pod
func WithUTSNSFromPod(p *Pod) CtrCreateOption {
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 114bf9315..05f22c1fe 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -186,8 +186,6 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
// If the ID is empty a new name for the restored container was requested
if ctr.config.ID == "" {
ctr.config.ID = stringid.GenerateNonCryptoID()
- // Fixup ExitCommand with new ID
- ctr.config.ExitCommand[len(ctr.config.ExitCommand)-1] = ctr.config.ID
}
// Reset the log path to point to the default
ctr.config.LogPath = ""