allocator_test.go
// Copyright 2018-2020 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !privileged_test
package ipam
import (
"net"
"time"
"github.com/cilium/cilium/common/addressing"
"github.com/cilium/cilium/pkg/datapath/fake"
. "gopkg.in/check.v1"
)
type ownerMock struct{}
func (o *ownerMock) K8sEventReceived(scope string, action string, valid, equal bool) {}
func (o *ownerMock) K8sEventProcessed(scope string, action string, status bool) {}
func (o *ownerMock) UpdateCiliumNodeResource() {}
func (s *IPAMSuite) TestAllocatedIPDump(c *C) {
fakeAddressing := fake.NewNodeAddressing()
ipam := NewIPAM(fakeAddressing, Configuration{EnableIPv4: true, EnableIPv6: true}, &ownerMock{}, &ownerMock{})
ipv4 := fakeAddressing.IPv4().AllocationCIDR().IP
ipv6 := fakeAddressing.IPv6().AllocationCIDR().IP
for i := 0; i < 10; i++ {
_, err := addressing.NewCiliumIPv4(ipv4.String())
c.Assert(err, IsNil)
nextIP(ipv4)
_, err = addressing.NewCiliumIPv6(ipv6.String())
c.Assert(err, IsNil)
nextIP(ipv6)
}
allocv4, allocv6, status := ipam.Dump()
c.Assert(status, Not(Equals), "")
// Test the format of the dumped ip addresses
for ip := range allocv4 {
c.Assert(net.ParseIP(ip), NotNil)
}
for ip := range allocv6 {
c.Assert(net.ParseIP(ip), NotNil)
}
}
func (s *IPAMSuite) TestExpirationTimer(c *C) {
ip := net.ParseIP("1.1.1.1")
timeout := 50 * time.Millisecond
fakeAddressing := fake.NewNodeAddressing()
ipam := NewIPAM(fakeAddressing, Configuration{EnableIPv4: true, EnableIPv6: true}, &ownerMock{}, &ownerMock{})
err := ipam.AllocateIP(ip, "foo")
c.Assert(err, IsNil)
uuid, err := ipam.StartExpirationTimer(ip, timeout)
c.Assert(err, IsNil)
c.Assert(uuid, Not(Equals), "")
// must fail, already registered
uuid, err = ipam.StartExpirationTimer(ip, timeout)
c.Assert(err, Not(IsNil))
c.Assert(uuid, Equals, "")
// must fail, already in use
err = ipam.AllocateIP(ip, "foo")
c.Assert(err, Not(IsNil))
// Let expiration timer expire
time.Sleep(2 * timeout)
// Must suceed, IP must be released again
err = ipam.AllocateIP(ip, "foo")
c.Assert(err, IsNil)
// register new expiration timer
uuid, err = ipam.StartExpirationTimer(ip, timeout)
c.Assert(err, IsNil)
c.Assert(uuid, Not(Equals), "")
// attempt to stop with an invalid uuid, must fail
err = ipam.StopExpirationTimer(ip, "unknown-uuid")
c.Assert(err, Not(IsNil))
// stop expiration with valid uuid
err = ipam.StopExpirationTimer(ip, uuid)
c.Assert(err, IsNil)
// Let expiration timer expire
time.Sleep(2 * timeout)
// must fail as IP is properly in use now
err = ipam.AllocateIP(ip, "foo")
c.Assert(err, Not(IsNil))
// release IP for real
err = ipam.ReleaseIP(ip)
c.Assert(err, IsNil)
// allocate IP again
err = ipam.AllocateIP(ip, "foo")
c.Assert(err, IsNil)
// register expiration timer
uuid, err = ipam.StartExpirationTimer(ip, timeout)
c.Assert(err, IsNil)
c.Assert(uuid, Not(Equals), "")
// release IP, must also stop expiration timer
err = ipam.ReleaseIP(ip)
c.Assert(err, IsNil)
// allocate same IP again
err = ipam.AllocateIP(ip, "foo")
c.Assert(err, IsNil)
// register expiration timer must succeed even though stop was never called
uuid, err = ipam.StartExpirationTimer(ip, timeout)
c.Assert(err, IsNil)
c.Assert(uuid, Not(Equals), "")
// release IP
err = ipam.ReleaseIP(ip)
c.Assert(err, IsNil)
}
func (s *IPAMSuite) TestAllocateNextWithExpiration(c *C) {
timeout := 50 * time.Millisecond
fakeAddressing := fake.NewNodeAddressing()
ipam := NewIPAM(fakeAddressing, Configuration{EnableIPv4: true, EnableIPv6: true}, &ownerMock{}, &ownerMock{})
ipv4, ipv6, err := ipam.AllocateNextWithExpiration("", "foo", timeout)
c.Assert(err, IsNil)
// IPv4 address must be in use
err = ipam.AllocateIP(ipv4.IP, "foo")
c.Assert(err, Not(IsNil))
// IPv6 address must be in use
err = ipam.AllocateIP(ipv6.IP, "foo")
c.Assert(err, Not(IsNil))
// Let expiration timer expire
time.Sleep(2 * timeout)
// IPv4 address must be available again
err = ipam.AllocateIP(ipv4.IP, "foo")
c.Assert(err, IsNil)
// IPv6 address must be available again
err = ipam.AllocateIP(ipv6.IP, "foo")
c.Assert(err, IsNil)
// Release IPs
err = ipam.ReleaseIP(ipv4.IP)
c.Assert(err, IsNil)
err = ipam.ReleaseIP(ipv6.IP)
c.Assert(err, IsNil)
// Allocate IPs again and test stopping the expiration timer
ipv4, ipv6, err = ipam.AllocateNextWithExpiration("", "foo", timeout)
c.Assert(err, IsNil)
// Stop expiration timer for IPv4 address
err = ipam.StopExpirationTimer(ipv4.IP, ipv4.ExpirationUUID)
c.Assert(err, IsNil)
// Let expiration timer expire
time.Sleep(2 * timeout)
// IPv4 address must be in use
err = ipam.AllocateIP(ipv4.IP, "foo")
c.Assert(err, Not(IsNil))
// IPv6 address must be available again
err = ipam.AllocateIP(ipv6.IP, "foo")
c.Assert(err, IsNil)
// Release IPv4 address
err = ipam.ReleaseIP(ipv4.IP)
c.Assert(err, IsNil)
}