Пример #1
0
// 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
}
Пример #2
0
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
}
Пример #3
0
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
}
Пример #4
0
// 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
}
Пример #5
0
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
}
Пример #6
0
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
}
Пример #7
0
// 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
}
Пример #8
0
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
}