netboot/pixiecore/pixicorev6.go

103 lines
2.2 KiB
Go

package pixiecore
import (
"encoding/binary"
"fmt"
"net"
"time"
"go.universe.tf/netboot/dhcp6"
)
// ServerV6 boots machines using a Booter.
type ServerV6 struct {
Address string
Port string
Duid []byte
BootConfig dhcp6.BootConfiguration
PacketBuilder *dhcp6.PacketBuilder
AddressPool dhcp6.AddressPool
errs chan error
Log func(subsystem, msg string)
Debug func(subsystem, msg string)
}
// NewServerV6 returns a new ServerV6.
func NewServerV6() *ServerV6 {
ret := &ServerV6{
Port: "547",
}
return ret
}
// Serve listens for machines attempting to boot, and responds to
// their DHCPv6 requests.
func (s *ServerV6) Serve() error {
s.log("dhcp", "starting...")
dhcp, err := dhcp6.NewConn(s.Address, s.Port)
if err != nil {
return err
}
s.debug("dhcp", "new connection...")
// 5 buffer slots, one for each goroutine, plus one for
// Shutdown(). We only ever pull the first error out, but shutdown
// will likely generate some spurious errors from the other
// goroutines, and we want them to be able to dump them without
// blocking.
s.errs = make(chan error, 6)
s.setDUID(dhcp.SourceHardwareAddress())
go func() { s.errs <- s.serveDHCP(dhcp) }()
// Wait for either a fatal error, or Shutdown().
err = <-s.errs
dhcp.Close()
s.log("dhcp", "stopped...")
return err
}
// Shutdown causes Serve() to exit, cleaning up behind itself.
func (s *ServerV6) Shutdown() {
select {
case s.errs <- nil:
default:
}
}
func (s *ServerV6) log(subsystem, format string, args ...interface{}) {
if s.Log == nil {
return
}
s.Log(subsystem, fmt.Sprintf(format, args...))
}
func (s *ServerV6) debug(subsystem, format string, args ...interface{}) {
if s.Debug == nil {
return
}
s.Debug(subsystem, fmt.Sprintf(format, args...))
}
func (s *ServerV6) setDUID(addr net.HardwareAddr) {
duid := make([]byte, len(addr)+8) // see rfc3315, section 9.2, DUID-LT
copy(duid[0:], []byte{0, 1}) //fixed, x0001
copy(duid[2:], []byte{0, 1}) //hw type ethernet, x0001
utcLoc, _ := time.LoadLocation("UTC")
sinceJanFirst2000 := time.Since(time.Date(2000, time.January, 1, 0, 0, 0, 0, utcLoc))
binary.BigEndian.PutUint32(duid[4:], uint32(sinceJanFirst2000.Seconds()))
copy(duid[8:], addr)
s.Duid = duid
}