diff --git a/src/yggdrasil/peer.go b/src/yggdrasil/peer.go index 1d1b8054..b3629311 100644 --- a/src/yggdrasil/peer.go +++ b/src/yggdrasil/peer.go @@ -243,8 +243,25 @@ func (p *peer) _handleTraffic(packet []byte) { // Drop traffic if the peer isn't in the switch return } - _, coords := wire_getTrafficOffsetAndCoords(packet) - next := p.table.lookup(coords) + obs, coords := wire_getTrafficOffsetAndCoords(packet) + offset, _ := wire_decode_uint64(obs) + ports := p.table.getPorts(coords) + if offset == 0 { + offset = p.table.getOffset(ports) + } + var next switchPort + if offset == 0 { + // Greedy routing, find the best next hop + next = p.table.lookup(ports) + } else { + // Source routing, read next hop from coords and update offset/obs + if int(offset) < len(ports) { + next = ports[offset] + offset += 1 + // FIXME this breaks if offset is > 127, it's just for testing + wire_put_uint64(offset, obs[:0]) + } + } if nPeer, isIn := p.ports[next]; isIn { nPeer.sendPacketFrom(p, packet) } diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 2f4f3194..4873d8b4 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -631,13 +631,11 @@ func (t *switchTable) start() error { return nil } -func (t *lookupTable) lookup(coords []byte) switchPort { - var offset int +func (t *lookupTable) lookup(ports []switchPort) switchPort { here := &t._start - for offset < len(coords) { - port, l := wire_decode_uint64(coords[offset:]) - offset += l - if next, ok := here.next[switchPort(port)]; ok { + for idx := range ports { + port := ports[idx] + if next, ok := here.next[port]; ok { here = next } else { break @@ -645,3 +643,43 @@ func (t *lookupTable) lookup(coords []byte) switchPort { } return here.port } + +func (t *lookupTable) getPorts(coords []byte) []switchPort { + var ports []switchPort + var offset int + for offset < len(coords) { + port, l := wire_decode_uint64(coords[offset:]) + offset += l + ports = append(ports, switchPort(port)) + } + return ports +} + +func (t *lookupTable) isDescendant(ports []switchPort) bool { + // Note that this returns true for anyone in the subtree that starts at us + // That includes ourself, so we are our own descendant by this logic... + if len(t.self.coords) >= len(ports) { + // Our coords are longer, so they can't be our descendant + return false + } + for idx := range t.self.coords { + if ports[idx] != t.self.coords[idx] { + return false + } + } + return true +} + +func (t *lookupTable) getOffset(ports []switchPort) uint64 { + // If they're our descendant, this returns the length of our coords, used as an offset for source routing + // If they're not our descendant, this returns 0 + var offset uint64 + for idx := range t.self.coords { + if idx < len(ports) && ports[idx] == t.self.coords[idx] { + offset += 1 + } else { + return 0 + } + } + return offset +}