glider/service/dhcpd/pool.go

89 lines
1.7 KiB
Go
Raw Normal View History

2020-09-28 00:49:58 +08:00
package dhcpd
import (
"bytes"
"errors"
2020-09-29 00:38:35 +08:00
"math/rand"
2020-09-28 00:49:58 +08:00
"net"
"time"
)
2020-10-03 20:51:27 +08:00
// Pool is a dhcp pool.
2020-09-28 00:49:58 +08:00
type Pool struct {
items []*item
}
// NewPool returns a new dhcp ip pool.
func NewPool(lease time.Duration, start, end net.IP) (*Pool, error) {
2020-10-01 19:29:53 +08:00
if start == nil || end == nil {
return nil, errors.New("start ip or end ip is wrong/nil, please check your config")
}
s, e := ip2num(start.To4()), ip2num(end.To4())
2020-10-01 19:29:53 +08:00
if e < s {
return nil, errors.New("start ip larger than end ip")
}
items := make([]*item, 0, e-s+1)
for n := s; n <= e; n++ {
items = append(items, &item{lease: lease, ip: num2ip(n)})
2020-09-28 00:49:58 +08:00
}
2020-09-29 00:38:35 +08:00
rand.Seed(time.Now().Unix())
return &Pool{items: items}, nil
2020-09-28 00:49:58 +08:00
}
2020-10-03 20:51:27 +08:00
// AssignIP assigns an ip to mac from dhco pool.
2020-09-28 00:49:58 +08:00
func (p *Pool) AssignIP(mac net.HardwareAddr) (net.IP, error) {
var ip net.IP
for _, item := range p.items {
2020-09-29 00:38:35 +08:00
if bytes.Equal(mac, item.mac) {
2020-09-28 00:49:58 +08:00
return item.ip, nil
}
}
2020-09-29 00:38:35 +08:00
idx := rand.Intn(len(p.items))
for _, item := range p.items[idx:] {
if ip = item.take(mac); ip != nil {
return ip, nil
}
}
2020-09-28 00:49:58 +08:00
for _, item := range p.items {
if ip = item.take(mac); ip != nil {
return ip, nil
}
}
return nil, errors.New("no more ip can be assigned")
}
type item struct {
2020-09-29 00:38:35 +08:00
taken bool
ip net.IP
lease time.Duration
mac net.HardwareAddr
2020-09-28 00:49:58 +08:00
}
func (i *item) take(addr net.HardwareAddr) net.IP {
2020-09-29 00:38:35 +08:00
if !i.taken {
2020-09-28 00:49:58 +08:00
i.taken = true
go func() {
timer := time.NewTimer(i.lease)
<-timer.C
2020-09-29 00:38:35 +08:00
i.mac = nil
2020-09-28 00:49:58 +08:00
i.taken = false
}()
2020-09-29 00:38:35 +08:00
i.mac = addr
2020-09-28 00:49:58 +08:00
return i.ip
}
2020-09-29 00:38:35 +08:00
return nil
2020-09-28 00:49:58 +08:00
}
func ip2num(ip net.IP) uint32 {
n := uint32(ip[0])<<24 + uint32(ip[1])<<16
return n + uint32(ip[2])<<8 + uint32(ip[3])
}
func num2ip(n uint32) net.IP {
return []byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)}
}