diff --git a/dhcpd/db.go b/dhcpd/db.go index 46a24b7d..8de5ba79 100644 --- a/dhcpd/db.go +++ b/dhcpd/db.go @@ -36,6 +36,8 @@ func ipInRange(start, stop, ip net.IP) bool { func (s *Server) dbLoad() { s.leases = nil s.IPpool = make(map[[4]byte]net.HardwareAddr) + dynLeases := []*Lease{} + staticLeases := []*Lease{} data, err := ioutil.ReadFile(s.conf.DBFilePath) if err != nil { @@ -69,11 +71,47 @@ func (s *Server) dbLoad() { Expiry: time.Unix(obj[i].Expiry, 0), } - s.leases = append(s.leases, &lease) + if obj[i].Expiry == leaseExpireStatic { + staticLeases = append(staticLeases, &lease) + } else { + dynLeases = append(dynLeases, &lease) + } + } + s.leases = normalizeLeases(staticLeases, dynLeases) + + for _, lease := range s.leases { s.reserveIP(lease.IP, lease.HWAddr) } - log.Info("DHCP: loaded %d leases from DB", numLeases) + + log.Info("DHCP: loaded %d (%d) leases from DB", len(s.leases), numLeases) +} + +// Skip duplicate leases +// Static leases have a priority over dynamic leases +func normalizeLeases(staticLeases, dynLeases []*Lease) []*Lease { + leases := []*Lease{} + index := map[string]int{} + + for i, lease := range staticLeases { + _, ok := index[lease.HWAddr.String()] + if ok { + continue // skip the lease with the same HW address + } + index[lease.HWAddr.String()] = i + leases = append(leases, lease) + } + + for i, lease := range dynLeases { + _, ok := index[lease.HWAddr.String()] + if ok { + continue // skip the lease with the same HW address + } + index[lease.HWAddr.String()] = i + leases = append(leases, lease) + } + + return leases } // Store lease table in DB diff --git a/dhcpd/dhcpd_test.go b/dhcpd/dhcpd_test.go index 5e3494ea..00c17276 100644 --- a/dhcpd/dhcpd_test.go +++ b/dhcpd/dhcpd_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/krolaw/dhcp4" + "github.com/stretchr/testify/assert" ) func check(t *testing.T, result bool, msg string) { @@ -211,3 +212,32 @@ func TestIsValidSubnetMask(t *testing.T) { t.Fatalf("isValidSubnetMask([]byte{255,255,253,0})") } } + +func TestNormalizeLeases(t *testing.T) { + dynLeases := []*Lease{} + staticLeases := []*Lease{} + leases := []*Lease{} + + lease := &Lease{} + lease.HWAddr = []byte{1, 2, 3, 4} + dynLeases = append(dynLeases, lease) + lease = new(Lease) + lease.HWAddr = []byte{1, 2, 3, 5} + dynLeases = append(dynLeases, lease) + + lease = new(Lease) + lease.HWAddr = []byte{1, 2, 3, 4} + lease.IP = []byte{0, 2, 3, 4} + staticLeases = append(staticLeases, lease) + lease = new(Lease) + lease.HWAddr = []byte{2, 2, 3, 4} + staticLeases = append(staticLeases, lease) + + leases = normalizeLeases(staticLeases, dynLeases) + + assert.True(t, len(leases) == 3) + assert.True(t, bytes.Equal(leases[0].HWAddr, []byte{1, 2, 3, 4})) + assert.True(t, bytes.Equal(leases[0].IP, []byte{0, 2, 3, 4})) + assert.True(t, bytes.Equal(leases[1].HWAddr, []byte{2, 2, 3, 4})) + assert.True(t, bytes.Equal(leases[2].HWAddr, []byte{1, 2, 3, 5})) +}