netboot/pixiecore/pixicorev6.go
2018-02-05 12:33:17 -08:00

103 lines
2.2 KiB
Go

package pixiecore
import (
"go.universe.tf/netboot/dhcp6"
"sync"
"fmt"
"time"
"encoding/binary"
"net"
)
type ServerV6 struct {
Address string
Port string
Duid []byte
IPxeUrl string
HttpbootUrl string
errs chan error
eventsMu sync.Mutex
events map[string][]machineEvent
Log func(subsystem, msg string)
Debug func(subsystem, msg string)
}
func NewServerV6() *ServerV6 {
log := func(subsystem, msg string) { fmt.Printf("[%s] %s", subsystem, msg) }
ret := &ServerV6{
Port: "547",
Log: log,
Debug: log,
}
return ret
}
func (s *ServerV6) Serve() error {
s.log("dhcp", "starting...")
dhcp, err := dhcp6.NewConn(s.Address, s.Port)
if err != nil {
return err
}
s.log("dhcp", "new connection...")
s.events = make(map[string][]machineEvent)
// 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.debug("Init", "Starting Pixiecore goroutines")
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
}