package dhcpsvc import ( "fmt" "log/slog" "net" "time" ) // macKey contains hardware address as byte array of 6, 8, or 20 bytes. // // TODO(e.burkov): Move to aghnet or even to netutil. type macKey any // macToKey converts mac into macKey, which is used as the key for the lease // maps. mac must be a valid hardware address of length 6, 8, or 20 bytes, see // [netutil.ValidateMAC]. func macToKey(mac net.HardwareAddr) (key macKey) { switch len(mac) { case 6: return [6]byte(mac) case 8: return [8]byte(mac) case 20: return [20]byte(mac) default: panic(fmt.Errorf("invalid mac address %#v", mac)) } } // netInterface is a common part of any interface within the DHCP server. // // TODO(e.burkov): Add other methods as [DHCPServer] evolves. type netInterface struct { // logger logs the events related to the network interface. logger *slog.Logger // leases is the set of DHCP leases assigned to this interface. leases map[macKey]*Lease // name is the name of the network interface. name string // leaseTTL is the default Time-To-Live value for leases. leaseTTL time.Duration } // newNetInterface creates a new netInterface with the given name, leaseTTL, and // logger. func newNetInterface(name string, l *slog.Logger, leaseTTL time.Duration) (iface *netInterface) { return &netInterface{ logger: l, leases: map[macKey]*Lease{}, name: name, leaseTTL: leaseTTL, } } // reset clears all the slices in iface for reuse. func (iface *netInterface) reset() { clear(iface.leases) } // addLease inserts the given lease into iface. It returns an error if the // lease can't be inserted. func (iface *netInterface) addLease(l *Lease) (err error) { mk := macToKey(l.HWAddr) _, found := iface.leases[mk] if found { return fmt.Errorf("lease for mac %s already exists", l.HWAddr) } iface.leases[mk] = l return nil } // updateLease replaces an existing lease within iface with the given one. It // returns an error if there is no lease with such hardware address. func (iface *netInterface) updateLease(l *Lease) (prev *Lease, err error) { mk := macToKey(l.HWAddr) prev, found := iface.leases[mk] if !found { return nil, fmt.Errorf("no lease for mac %s", l.HWAddr) } iface.leases[mk] = 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) { mk := macToKey(l.HWAddr) _, found := iface.leases[mk] if !found { return fmt.Errorf("no lease for mac %s", l.HWAddr) } delete(iface.leases, mk) return nil }