436 lines
13 KiB
Go
436 lines
13 KiB
Go
// +build linux
|
|
|
|
package netavark
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/containers/common/libnetwork/types"
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var _ = Describe("IPAM", func() {
|
|
var (
|
|
networkInterface *netavarkNetwork
|
|
networkConfDir string
|
|
logBuffer bytes.Buffer
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
var err error
|
|
networkConfDir, err = ioutil.TempDir("", "podman_netavark_test")
|
|
if err != nil {
|
|
Fail("Failed to create tmpdir")
|
|
|
|
}
|
|
logBuffer = bytes.Buffer{}
|
|
logrus.SetOutput(&logBuffer)
|
|
})
|
|
|
|
JustBeforeEach(func() {
|
|
libpodNet, err := NewNetworkInterface(&InitConfig{
|
|
NetworkConfigDir: networkConfDir,
|
|
IPAMDBPath: filepath.Join(networkConfDir, "ipam.db"),
|
|
LockFile: filepath.Join(networkConfDir, "netavark.lock"),
|
|
})
|
|
if err != nil {
|
|
Fail("Failed to create NewCNINetworkInterface")
|
|
}
|
|
|
|
networkInterface = libpodNet.(*netavarkNetwork)
|
|
// run network list to force a network load
|
|
networkInterface.NetworkList()
|
|
})
|
|
|
|
AfterEach(func() {
|
|
os.RemoveAll(networkConfDir)
|
|
})
|
|
|
|
It("simple ipam alloc", func() {
|
|
netName := types.DefaultNetworkName
|
|
for i := 2; i < 100; i++ {
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
err := networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.88.0.%d", i)).To4()))
|
|
}
|
|
})
|
|
|
|
It("ipam try to alloc same ip", func() {
|
|
netName := types.DefaultNetworkName
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
err := networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.88.0.2").To4()))
|
|
|
|
opts = &types.NetworkOptions{
|
|
ContainerID: "otherID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {StaticIPs: []net.IP{net.ParseIP("10.88.0.2")}},
|
|
},
|
|
}
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err.Error()).To(Equal("IPAM error: requested ip address 10.88.0.2 is already allocated to container ID someContainerID"))
|
|
})
|
|
|
|
It("ipam try to alloc more ips as in range", func() {
|
|
s, _ := types.ParseCIDR("10.0.0.1/24")
|
|
network, err := networkInterface.NetworkCreate(types.Network{
|
|
Subnets: []types.Subnet{
|
|
{
|
|
Subnet: s,
|
|
LeaseRange: &types.LeaseRange{
|
|
StartIP: net.ParseIP("10.0.0.10"),
|
|
EndIP: net.ParseIP("10.0.0.20"),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName := network.Name
|
|
|
|
for i := 10; i < 21; i++ {
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: fmt.Sprintf("someContainerID-%d", i),
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4()))
|
|
}
|
|
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID-22",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
// now this should fail because all free ips are already assigned
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err.Error()).To(Equal("IPAM error: failed to find free IP in range: 10.0.0.10 - 10.0.0.20"))
|
|
})
|
|
|
|
It("ipam basic setup", func() {
|
|
netName := types.DefaultNetworkName
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
expectedIP := net.ParseIP("10.88.0.2").To4()
|
|
|
|
err := networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(expectedIP))
|
|
|
|
// remove static ips from opts
|
|
netOpts := opts.Networks[netName]
|
|
netOpts.StaticIPs = nil
|
|
opts.Networks[netName] = netOpts
|
|
|
|
err = networkInterface.getAssignedIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(expectedIP))
|
|
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err.Error()).To(Equal("IPAM error: requested ip address 10.88.0.2 is already allocated to container ID someContainerID"))
|
|
|
|
// dealloc the ip
|
|
err = networkInterface.deallocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(expectedIP))
|
|
})
|
|
|
|
It("ipam dual stack", func() {
|
|
s1, _ := types.ParseCIDR("10.0.0.0/26")
|
|
s2, _ := types.ParseCIDR("fd80::/24")
|
|
network, err := networkInterface.NetworkCreate(types.Network{
|
|
Subnets: []types.Subnet{
|
|
{
|
|
Subnet: s1,
|
|
},
|
|
{
|
|
Subnet: s2,
|
|
},
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName := network.Name
|
|
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(2))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4()))
|
|
Expect(opts.Networks[netName].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2")))
|
|
|
|
// remove static ips from opts
|
|
netOpts := opts.Networks[netName]
|
|
netOpts.StaticIPs = nil
|
|
opts.Networks[netName] = netOpts
|
|
|
|
err = networkInterface.getAssignedIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(2))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4()))
|
|
Expect(opts.Networks[netName].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2")))
|
|
|
|
err = networkInterface.deallocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// try to alloc the same again
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(2))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4()))
|
|
Expect(opts.Networks[netName].StaticIPs[1]).To(Equal(net.ParseIP("fd80::2")))
|
|
})
|
|
|
|
It("ipam with two networks", func() {
|
|
s, _ := types.ParseCIDR("10.0.0.0/24")
|
|
network, err := networkInterface.NetworkCreate(types.Network{
|
|
Subnets: []types.Subnet{
|
|
{
|
|
Subnet: s,
|
|
},
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName1 := network.Name
|
|
|
|
s, _ = types.ParseCIDR("10.0.1.0/24")
|
|
network, err = networkInterface.NetworkCreate(types.Network{
|
|
Subnets: []types.Subnet{
|
|
{
|
|
Subnet: s,
|
|
},
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName2 := network.Name
|
|
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName1: {},
|
|
netName2: {},
|
|
},
|
|
}
|
|
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName1))
|
|
Expect(opts.Networks[netName1].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4()))
|
|
Expect(opts.Networks).To(HaveKey(netName2))
|
|
Expect(opts.Networks[netName2].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName2].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4()))
|
|
|
|
// remove static ips from opts
|
|
netOpts := opts.Networks[netName1]
|
|
netOpts.StaticIPs = nil
|
|
opts.Networks[netName1] = netOpts
|
|
netOpts = opts.Networks[netName2]
|
|
netOpts.StaticIPs = nil
|
|
opts.Networks[netName2] = netOpts
|
|
|
|
err = networkInterface.getAssignedIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName1))
|
|
Expect(opts.Networks[netName1].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4()))
|
|
Expect(opts.Networks).To(HaveKey(netName2))
|
|
Expect(opts.Networks[netName2].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName2].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4()))
|
|
|
|
err = networkInterface.deallocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// try to alloc the same again
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName1))
|
|
Expect(opts.Networks[netName1].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName1].StaticIPs[0]).To(Equal(net.ParseIP("10.0.0.2").To4()))
|
|
Expect(opts.Networks).To(HaveKey(netName2))
|
|
Expect(opts.Networks[netName2].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName2].StaticIPs[0]).To(Equal(net.ParseIP("10.0.1.2").To4()))
|
|
})
|
|
|
|
It("ipam alloc more ips as in subnet", func() {
|
|
s, _ := types.ParseCIDR("10.0.0.0/26")
|
|
network, err := networkInterface.NetworkCreate(types.Network{
|
|
Subnets: []types.Subnet{
|
|
{
|
|
Subnet: s,
|
|
},
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName := network.Name
|
|
|
|
for i := 2; i < 64; i++ {
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: fmt.Sprintf("id-%d", i),
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
err = networkInterface.allocIPs(opts)
|
|
if i < 63 {
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4()))
|
|
} else {
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err.Error()).To(Equal("IPAM error: failed to find free IP in range: 10.0.0.1 - 10.0.0.62"))
|
|
}
|
|
}
|
|
})
|
|
|
|
It("ipam alloc -> dealloc -> alloc", func() {
|
|
s, _ := types.ParseCIDR("10.0.0.0/27")
|
|
network, err := networkInterface.NetworkCreate(types.Network{
|
|
Subnets: []types.Subnet{
|
|
{
|
|
Subnet: s,
|
|
},
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName := network.Name
|
|
|
|
for i := 2; i < 10; i++ {
|
|
opts := types.NetworkOptions{
|
|
ContainerID: fmt.Sprintf("id-%d", i),
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
err = networkInterface.allocIPs(&opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", i)).To4()))
|
|
|
|
err = networkInterface.deallocIPs(&opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
}
|
|
|
|
for i := 0; i < 30; i++ {
|
|
opts := types.NetworkOptions{
|
|
ContainerID: fmt.Sprintf("id-%d", i),
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
err = networkInterface.allocIPs(&opts)
|
|
if i < 29 {
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(1))
|
|
// The (i+8)%29+2 part looks cryptic but it is actually simple, we already have 8 ips allocated above
|
|
// so we expect the 8 available ip. We have 29 assignable ip addresses in this subnet because "i"+8 can
|
|
// be greater than 30 we have to modulo by 29 to go back to the beginning. Also the first free ip is
|
|
// network address + 2, so we have to add 2 to the result
|
|
Expect(opts.Networks[netName].StaticIPs[0]).To(Equal(net.ParseIP(fmt.Sprintf("10.0.0.%d", (i+8)%29+2)).To4()))
|
|
} else {
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err.Error()).To(Equal("IPAM error: failed to find free IP in range: 10.0.0.1 - 10.0.0.30"))
|
|
}
|
|
}
|
|
})
|
|
|
|
It("ipam with dhcp driver should not set ips", func() {
|
|
network, err := networkInterface.NetworkCreate(types.Network{
|
|
IPAMOptions: map[string]string{
|
|
"driver": types.DHCPIPAMDriver,
|
|
},
|
|
})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
netName := network.Name
|
|
|
|
opts := &types.NetworkOptions{
|
|
ContainerID: "someContainerID",
|
|
Networks: map[string]types.PerNetworkOptions{
|
|
netName: {},
|
|
},
|
|
}
|
|
|
|
err = networkInterface.allocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(0))
|
|
|
|
err = networkInterface.getAssignedIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(opts.Networks).To(HaveKey(netName))
|
|
Expect(opts.Networks[netName].StaticIPs).To(HaveLen(0))
|
|
|
|
// dealloc the ip
|
|
err = networkInterface.deallocIPs(opts)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
})
|