// Assumes RWLock is held func (subnet *Subnet) getFreeIP() (*net.IP, bool) { bit, success := firstClearBit(subnet.ActiveBits) if success { subnet.ActiveBits.Set(bit) ip := dhcp.IPAdd(subnet.ActiveStart, int(bit)) return &ip, true } // Free invalid or expired leases save_me := false now := time.Now() for k, lease := range subnet.Leases { if now.After(lease.ExpireTime) { if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) { subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1)) } delete(subnet.Leases, k) save_me = true } } bit, success = firstClearBit(subnet.ActiveBits) if success { subnet.ActiveBits.Set(bit) ip := dhcp.IPAdd(subnet.ActiveStart, int(bit)) return &ip, true } // We got nothin' return nil, save_me }
func newSubnet(dt *DataTracker, name, subnet string) (s *Subnet) { _, theNet, _ := net.ParseCIDR(subnet) s = NewSubnet() s.Name = name s.Subnet = &MyIPNet{theNet} s.ActiveStart = dhcp.IPAdd(theNet.IP, 5) s.ActiveEnd = dhcp.IPAdd(theNet.IP, 25) return }
func (d *DHCPService) getIPFromPool() net.IP { // locate an unused IP address (can this be more efficient? yes! FIXME) // TODO: Create a channel and spawn a goproc with something like this function to feed it; then have the server pull addresses from that channel for ip := dhcp4.IPAdd(d.guestPool.IP, 1); d.guestPool.Contains(ip); ip = dhcp4.IPAdd(ip, 1) { //log.Println(ip.String()) if !d.db.HasIP(ip) { // this means that the IP is not already occupied return ip } } return nil }
// Assign assigns an ip to the node with the specified nic // Will use etcd machines records as LeasePool // part of DHCPDataSource interface implementation func (ds *EtcdDataSource) Assign(nic string) (net.IP, error) { ds.lockDHCPAssign() defer ds.unlockdhcpAssign() // TODO: first try to retrieve the machine, if exists (for performance) assignedIPs := make(map[string]bool) //find by Mac machines, _ := ds.Machines() for _, node := range machines { if node.Mac().String() == nic { ip, _ := node.IP() ds.store(node, ip) return ip, nil } nodeIP, _ := node.IP() assignedIPs[nodeIP.String()] = true } //find an unused ip for i := 0; i < ds.LeaseRange(); i++ { ip := dhcp4.IPAdd(ds.LeaseStart(), i) if _, exists := assignedIPs[ip.String()]; !exists { macAddress, _ := net.ParseMAC(nic) ds.CreateMachine(macAddress, ip) return ip, nil } } //use an expired ip //not implemented logging.Log(debugTag, "DHCP pool is full") return nil, nil }
func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) { switch msgType { case dhcp.Discover: free, nic := -1, p.CHAddr().String() for i, v := range h.leases { // Find previous lease if v.nic == nic { free = i goto reply } } if free = h.freeLease(); free == -1 { return } reply: return dhcp.ReplyPacket(p, dhcp.Offer, h.ip, dhcp.IPAdd(h.start, free), h.leaseDuration, h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList])) case dhcp.Request: if server, ok := options[dhcp.OptionServerIdentifier]; ok && !net.IP(server).Equal(h.ip) { return nil // Message not for this dhcp server } reqIP := net.IP(options[dhcp.OptionRequestedIPAddress]) if reqIP == nil { reqIP = net.IP(p.CIAddr()) } if len(reqIP) == 4 && !reqIP.Equal(net.IPv4zero) { if leaseNum := dhcp.IPRange(h.start, reqIP) - 1; leaseNum >= 0 && leaseNum < h.leaseRange { if l, exists := h.leases[leaseNum]; !exists || l.nic == p.CHAddr().String() { h.leases[leaseNum] = lease{nic: p.CHAddr().String(), expiry: time.Now().Add(h.leaseDuration)} return dhcp.ReplyPacket(p, dhcp.ACK, h.ip, net.IP(options[dhcp.OptionRequestedIPAddress]), h.leaseDuration, h.options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList])) } } } return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil) case dhcp.Release, dhcp.Decline: nic := p.CHAddr().String() for i, v := range h.leases { if v.nic == nic { delete(h.leases, i) break } } } return nil }
func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) { switch msgType { case dhcp.Discover: log.Info("discover received") fallthrough case dhcp.Request: if msgType == dhcp.Request { log.Info("request received") } hwaddr := p.CHAddr().String() var msg dhcp.MessageType if msgType == dhcp.Discover { msg = dhcp.Offer } else if msgType == dhcp.Request { msg = dhcp.ACK } if _, ok := h.leases[hwaddr]; ok { log.Infof("Replying with existing lease %s", h.leases[hwaddr].String()) return dhcp.ReplyPacket(p, msg, h.myIP, h.leases[hwaddr], time.Hour, nil) } else { log.Info("new interface; attempting to allocate ip") h.allocatorMutex.Lock() if h.latest == nil { h.latest = h.allocator.IP } h.latest = dhcp.IPAdd(h.latest, 1) h.leases[hwaddr] = h.latest.To4() h.allocatorMutex.Unlock() log.Infof("Replying with address %s for hardware addr %s", h.leases[hwaddr].String(), hwaddr) return dhcp.ReplyPacket(p, msg, h.myIP, h.leases[hwaddr], time.Hour, nil) } } return nil }
// Assign will find an IP for the specified nic func (p *LeasePool) Assign(nic string) (net.IP, error) { p.assignLock.Lock() defer p.assignLock.Unlock() leases, err := p.Leases() if err != nil { return nil, err } // try to find by mac address for _, lease := range leases { if lease.Nic == nic { p.Store(newLease(nic, lease.IP, p.expireDuration, &lease.FirstAssigned)) return lease.IP, nil } } // find an unseen ip for i := 0; i < p.rangeLen; i++ { ip := dhcp4.IPAdd(p.startIP, i) _, exists := leases[ip.String()] if !exists { err := p.Store(newLease(nic, ip, p.expireDuration, nil)) if err != nil { return nil, err } return ip, nil } } // find an expired ip now := time.Now() for _, lease := range leases { if lease.ExpireTime.Before(now) { p.Store(newLease(nic, lease.IP, p.expireDuration, nil)) return lease.IP, nil } } return nil, ErrLeasePoolIsFull }
func (m *etcdMachineInterface) store(machine *Machine) error { if machine.Type == 0 { if machine.IP == nil { machine.Type = MTNormal } else { machine.Type = MTStatic } } m.etcdDS.dhcpAssignLock.Lock() defer m.etcdDS.dhcpAssignLock.Unlock() machineInterfaces, err := m.etcdDS.MachineInterfaces() if err != nil { return fmt.Errorf("error while getting the machine interfaces: %s", err) } ipToMac := make(map[string]net.HardwareAddr) for _, mi := range machineInterfaces { machine, err := mi.Machine(false, nil) if err != nil { return fmt.Errorf("error while getting the machine for (%s): %s", mi.Mac().String(), err) } ipToMac[machine.IP.String()] = mi.Mac() } if machine.IP == nil { // To avoid concurrency problems // We expect rhis part to be triggered only through DHCP, so we expect // IsMaster() to returns true if err := m.etcdDS.IsMaster(); err != nil { return fmt.Errorf( "only the master instance is allowed to store machine info: %s", err) } counter := len(ipToMac) % m.etcdDS.leaseRange firstCandidateIP := dhcp4.IPAdd(m.etcdDS.leaseStart, counter) // kickstarted candidateIP := net.IPv4( firstCandidateIP[0], firstCandidateIP[1], firstCandidateIP[2], firstCandidateIP[3]) // copy for _, isAssigned := ipToMac[candidateIP.String()]; isAssigned; { candidateIP = dhcp4.IPAdd(candidateIP, 1) counter++ if counter == m.etcdDS.leaseRange { candidateIP = m.etcdDS.leaseStart counter = 0 } if firstCandidateIP.Equal(candidateIP) { break } } if _, isAssigned := ipToMac[candidateIP.String()]; isAssigned { return fmt.Errorf("no unassigned IP was found") } machine.IP = candidateIP } else { if m, isAssigned := ipToMac[machine.IP.String()]; isAssigned { return fmt.Errorf( "the requested IP(%s) is already assigned to another machine(%s)", machine.IP.String(), m.String()) } } jsonedStats, err := json.Marshal(*machine) if err != nil { return fmt.Errorf("error while marshaling the machine: %s", err) } err = m.selfSet("_machine", string(jsonedStats)) if err != nil { return fmt.Errorf("error while setting the marshaled machine: %s", err) } return nil }