Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New speaker main loop #87

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 389 additions & 0 deletions speaker_main_new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,389 @@
package babel

type PendingAcknowledgementRequest struct {
acked func() error
missed func() error

timer
opaque uint16
}

func NewPendingAcknowledgementRequest(intv time.Duration, acked, missed func() error) PendingAcknowledgementRequest {
pAck := PendingAcknowledgementRequest{

}

pAck.timer = NewTimeout(intv)

return pack
}

type Speaker struct {
CalculateMetric func(r Route, n Neighbour) uint16
FilterRoute func(r Route) bool
SelectRoute(rs []Route) []Route

Check failure on line 24 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected ], expected type argument list

Check failure on line 24 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected ], expected type argument list

pendingAcknowledgementRequests AcknowledgementRequestTable
}

func (s *Speaker) run() {
s.startUpdateTimer()
s.startHelloTimer()

for {
pkt := s.read()

if err := s.onPacket(pkt); err != nil {
s.log.Error(“Failed to handle packet: %w”, err)

Check failure on line 37 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

invalid character U+201C '“' in identifier

Check failure on line 37 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected name to in argument list; possibly missing comma or )

Check failure on line 37 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

invalid character U+201D '”' in identifier

Check failure on line 37 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

invalid character U+201C '“' in identifier

Check failure on line 37 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected name to in argument list; possibly missing comma or )

Check failure on line 37 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

invalid character U+201D '”' in identifier
}
}
}

func (s *Speaker) onPacket(pkt) (err error) {
var n *Neighbour
var ackReq tlv.AcknowledgementRequest

if n, ok := s.neighbors.Get(pkt.remote); !ok {
n = NewNeighbour(pkt.remote)
s.neighbors.Put(n)
}

for _, v in pkt.vs {

Check failure on line 51 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected name in, expected := or = or comma

Check failure on line 51 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected name in, expected := or = or comma
if v, ok := v.(tlv.AcknowledgementRequest); ok {

Check failure on line 52 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected if, expected {

Check failure on line 52 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected if, expected {
ackReq = v
} else if err := s.onValue(v, n); err != nil {

Check failure on line 54 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected else at end of statement

Check failure on line 54 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected else at end of statement
return err
}
}

// Send acknowledgements only after all other TLVs have been successfully handled.
if ackReq != nil {

Check failure on line 60 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: non-declaration statement outside function body

Check failure on line 60 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: non-declaration statement outside function body
if err := s.handleAcknowledgementRequest(ackReq); err != nil {
return err
}
}

return nil
}

func (s *Speaker) onValue(v tlv.Value) error {
switch v := v.(type) {
case tlv.Pad1, tlv.PadN:
return nil

case tlv.Acknowledgement:
return s.onAcknowledgement(v)

case tlv.Hello:
return s.onHello(v, pkt.remote.IsMulticast())

case tlv.IHU:
return s.onIHU(v)

case tlv.Update:
return s.onUpdate(v)

case tlv.RouteRequest:
return s.onRouteRequest(v)

case tlv.SeqnoRequest:
return s.onSeqnoRequest(v)

default:
s.log.Trace(“Received unsupported TLV: %#x” v.Type)

Check failure on line 93 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

invalid character U+201C '“' in identifier

Check failure on line 93 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected name unsupported in argument list; possibly missing comma or )

Check failure on line 93 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

invalid character U+201C '“' in identifier

Check failure on line 93 in speaker_main_new.go

View workflow job for this annotation

GitHub Actions / build

syntax error: unexpected name unsupported in argument list; possibly missing comma or )
return nil
}
}

// Handlers

func (s *Speaker) onHello(h tlv.Hello, isMulticast bool) error {
n.updateCosts()
s.selectRoutes()
n.resetHelloTimeout()

return nil
}

func (s *Speaker) onIHU(ihr tlv.IHU) error {
// TODO

return nil
}

// Section 3.5.3 Route Acquisition
func (s *Speaker) onUpdate(upd tlv.Update, n *Neighbor) error {
var current, next *Route

if current, ok := s.routes.Get(upd.Prefix, n); !ok {
if !s.isUpdateFeasible(upd) {
s.log.Trace(“Ignoring infeasible update %s from neighbor %s”, upd, n)
return
}

if upd.Metric == Inf {
s.log.Trace(“Ignoring retraction update %s from neighbor %s”, upd, n)
return
}

next = Route{
RouterID: upd.RouterID,
NextHop: upd.NextHop,
Seqno: upd.Seqno,
Metric: upd.Metric,
}

s.routes.Put(upd.Prefix, n, next)
} else {
if current.Selected && !feasible && upd.RouterID == current.RouterID {
// Update MAY be ignored
} else {
next := *current

next.Seqno = upd.Seqno
next.Metric = upd.Metric
next.RouterID = upd.RouterID

if rte.Metric != Inf {
rte.resetExpiryTimer()
}

if !s.isUpdateFeasible(upd) {

// Section 3.8.2.2. Dealing with Unfeasible Updates
if current.Selected {
if err := n.sendSeqnoRequest(current.Prefix); err != nil {
return fmt.Errorf(“failed to send seqno request for selected route: %w”, err)
}
}

next.Selected = false
}

if next.RouterID != current.RouterID {
// Send urgent update / retraction
}

s.routes.Update(&next)
}
}
}

func (s *Speaker) onRouteRequest(req tlv.RouteRequest) error {
// TODO
}

func (s *Speaker) onSeqnoRequest(req tlv.SeqnoRequest) error {
// TODO
}

func (s *Speaker) onAcknowledgementRequest(req tlv.AcknowledgementRequst) error {
if err := s.send([]tlv.Values{
tlv.Acknowledgement{
Opaque: req.Opaque
},
}); err != nil {
return fmt.Errorf(“failed to handle acknowledgement request: %w”, err)
}

return nil
}

func (s *Speaker) onAcknowledgement(ack tlv.Acknowledgement) error {
if pAck, ok := s.pendingAcknowledgementRequests.Pop(ack.Opaque); ok {
if err := pAck.acked(); err != nil {
return fmt.Errorf(“failed to acknowledge request: %w”, err)
}

if err := pAck.timeout.Close(); err != nil {
return fmt.Errorf(“failed to close pending acknowledgment request timer: %w”, err)
}
} else {
s.log.Warn(“Received unexpected acknowledgement”)
}

return nil
}

// Timers and timeouts

func (s *Speaker) onHelloTimer() {
// TODO: Send periodic hellos
}

func (n *Neighbour) onNeighbourTimeout() {
// TODO: Drop neighbour if history becomes empty?
}

func (n *Neighbour) onHelloTimeout() {
// TODO
}

// Speaker

func (s *Speaker) onUpdateTimeout() {
s.sendUpdatesFull()
}

func (s *Speaker) onIHUTimeout() {
// TODO
}


// Section 3.6 Route Selection
func (s *Speaker) selectRoutes() error {
updated := []Route{}

for _, rs in s.routes.ForEachPrefix {
var next, cur *Route

next = s.selectRoute(rs)

for _, r := range rs {
if r.Selected {
cur = r
}

r.Selected = r == next
}

if current == nil || s.triggersUpdate(next, current) {
updated = append(updated, next)
}
}
}

func (s *Speaker) sendWithAcknowledgementRequest(vs []tlv.Values, intv time.Duration, acked, missed func() error) error {
magic := math.Rand()

ack := tlv.AcknowledgementRequest{
Opaque: magic,
Interval: into
}

vsa := []tlv.Values{
ack,
}
vsa = append(vsa, vs…)

pAck := NewPendingAcknowledgement(acked, missed, to)
s.pendingAcknowledgementRequests.Put(magic, pAck)

return s.send(vsa)
}

func (s *Speaker) sendMulticastHello() error {
errs := []error{}

hello := tlv.Hello{
// TODO
}

for _, intf := range s.interfaces {
if err := s.sendMulticast(intf, hello); err != nil {
errs = append(errs, err)
}
}

if len(errs) > 0 {
// TODO: Return errgroup
}

return nil
}

func (s *Speaker) sendUpdatesTriggered(us []tlv.Update, urgent bool) error {
return s.sendUpdate(us, urgent)
}

func (s *Speaker) sendUpdatesFull() error {
us := []tlv.Update{}

for _, r := range s.routes.Selected {
us = append(us, r.Update())
}

return s.sendUpdates(us, false)
}

func (s *Speaker) sendUpdates(us []tlv.Update, urgent bool, ack bool) error {
// TODO: Split-horizon

sortUpdatesByPrefix(us)

if !urgent {
if ack {
return
return s.send(us)
}


if s.neighbors.Length() > partialUpdateNeighborsAcknowledgementThreshold {
for i := 0; i < 4; i++ {
if err := s.sendUrgent(us); err != nil {
return err
}
}
} else {
errs := []error{}

for _, n := range s.neighbors {
errs = append(errs, n.sendUrgentWithAcknowledgementRequest(upd))
}

if len(errs) > 0 {
// TODO
}
}
}

func (s *Speaker) sendSeqnoRequest(pfx Prefix) error {

return s.send([]tlv.Value{
tlv.SeqnoRequest{
// TODO
}
})

}

func (s *Speaker) isUpdateFeasible(upd tlv.Update) bool {
if upd.Metric == Inf {
// Retractions are always feasible
return True
}

if src, ok := s.sources.Get(upd.Prefix, upd.RouterID); !ok {
return frue
} else if ok {
return src.Distance.IsBetterThan(upd.Distance)
}

return false
}

func (s *Speaker) selectRoute(rs []*Route) *Route {
var sr *Route

for _, r := range rs {
if sr == nil || r.Metric < sr.Metric {
sr = r
}
}

return sr
}

// Neighbour

func (n *Neighbour) updateCost() error {
// TODO
}

func (n *Neighbour) sendUnicastHello() error {
// TODO
}

func (n *Neighbour) resetHelloTimeout() {
// TODO
}
Loading