Skip to content

Commit

Permalink
dhcpsvc: finish leases methods
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Feb 15, 2024
1 parent 3773628 commit 20f5ef8
Show file tree
Hide file tree
Showing 5 changed files with 484 additions and 45 deletions.
6 changes: 4 additions & 2 deletions internal/dhcpsvc/dhcpsvc.go
Expand Up @@ -14,7 +14,9 @@ import (
// Interface is a DHCP service.
//
// TODO(e.burkov): Separate HostByIP, MACByIP, IPByHost into a separate
// interface. This is also valid for Enabled method.
// interface. This is also applicable to Enabled method.
//
// TODO(e.burkov): Reconsider the requirements for the leases validity.
type Interface interface {
agh.ServiceWithConfig[*Config]

Expand Down Expand Up @@ -49,7 +51,7 @@ type Interface interface {
AddLease(l *Lease) (err error)

// UpdateStaticLease changes an existing DHCP lease. It returns an error if
// there is no lease with such hardware addressor if new values are invalid
// there is no lease with such hardware address or if new values are invalid
// or already exist.
UpdateStaticLease(l *Lease) (err error)

Expand Down
26 changes: 26 additions & 0 deletions internal/dhcpsvc/interface.go
Expand Up @@ -38,3 +38,29 @@ func (iface *netInterface) insertLease(l *Lease) (err error) {

return nil
}

// updateLease changes an existing lease within iface. It returns an error if
// there is no lease with such hardware address.
func (iface *netInterface) updateLease(l *Lease) (prev *Lease, err error) {
i, found := slices.BinarySearchFunc(iface.leases, l, compareLeaseMAC)
if !found {
return nil, fmt.Errorf("no lease for mac %s", l.HWAddr)
}

prev, iface.leases[i] = iface.leases[i], l

return prev, nil
}

// removeLease removes an existing lease from iface. It returns an error if
// there is no lease equal to l.
func (iface *netInterface) removeLease(l *Lease) (err error) {
i, found := slices.BinarySearchFunc(iface.leases, l, compareLeaseMAC)
if !found {
return fmt.Errorf("no lease for mac %s", l.HWAddr)
}

iface.leases = slices.Delete(iface.leases, i, i+1)

return nil
}
99 changes: 96 additions & 3 deletions internal/dhcpsvc/server.go
Expand Up @@ -193,19 +193,112 @@ func (srv *DHCPServer) AddLease(l *Lease) (err error) {
iface, ok = srv.interfaces6.find(addr)
}
if !ok {
return fmt.Errorf("no interface for IP address %s", addr)
return fmt.Errorf("no interface for ip %s", addr)
}

loweredHostname := strings.ToLower(l.Hostname)

srv.leasesMu.Lock()
defer srv.leasesMu.Unlock()

if _, ok = srv.leaseByIP[addr]; ok {
return fmt.Errorf("lease for ip %s already exists", addr)
} else if _, ok = srv.leaseByName[loweredHostname]; ok {
return fmt.Errorf("lease for hostname %s already exists", l.Hostname)
}

err = iface.insertLease(l)
if err != nil {
return err
}

srv.leaseByIP[l.IP] = l
srv.leaseByName[strings.ToLower(l.Hostname)] = l
srv.leaseByIP[addr] = l
srv.leaseByName[loweredHostname] = l

return nil
}

// UpdateStaticLease implements the [Interface] interface for *DHCPServer.
//
// TODO(e.burkov): Support moving leases between interfaces.
func (srv *DHCPServer) UpdateStaticLease(l *Lease) (err error) {
var ok bool
var iface *netInterface

addr := l.IP

if addr.Is4() {
iface, ok = srv.interfaces4.find(addr)
} else {
iface, ok = srv.interfaces6.find(addr)
}
if !ok {
return fmt.Errorf("no interface for ip %s", addr)
}

loweredHostname := strings.ToLower(l.Hostname)

srv.leasesMu.Lock()
defer srv.leasesMu.Unlock()

existing, ok := srv.leaseByIP[addr]
if ok && !slices.Equal(l.HWAddr, existing.HWAddr) {
return fmt.Errorf("lease for ip %s already exists", addr)
}

existing, ok = srv.leaseByName[loweredHostname]
if ok && !slices.Equal(l.HWAddr, existing.HWAddr) {
return fmt.Errorf("lease for hostname %s already exists", l.Hostname)
}

prev, err := iface.updateLease(l)
if err != nil {
return err
}

delete(srv.leaseByIP, prev.IP)
srv.leaseByIP[addr] = l

delete(srv.leaseByName, strings.ToLower(prev.Hostname))
srv.leaseByName[loweredHostname] = l

return nil
}

// RemoveLease implements the [Interface] interface for *DHCPServer.
func (srv *DHCPServer) RemoveLease(l *Lease) (err error) {
var ok bool
var iface *netInterface

addr := l.IP

if addr.Is4() {
iface, ok = srv.interfaces4.find(addr)
} else {
iface, ok = srv.interfaces6.find(addr)
}
if !ok {
return fmt.Errorf("no interface for ip %s", addr)
}

loweredHostname := strings.ToLower(l.Hostname)

srv.leasesMu.Lock()
defer srv.leasesMu.Unlock()

if _, ok = srv.leaseByIP[addr]; !ok {
return fmt.Errorf("no lease for ip %s", addr)
} else if _, ok = srv.leaseByName[loweredHostname]; !ok {
return fmt.Errorf("no lease for hostname %s", l.Hostname)
}

err = iface.removeLease(l)
if err != nil {
return err
}

delete(srv.leaseByIP, addr)
delete(srv.leaseByName, loweredHostname)

return nil
}

0 comments on commit 20f5ef8

Please sign in to comment.