mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 14:26:57 +01:00
multiport: make a lane a session on the tunnel, not a tunnel
Lanes used to be separate HostInfos, each with its own handshake, its own half-established states, its own lifetime and its own slot bookkeeping. That bought nothing: a lane is the same tunnel over a different underlay 5-tuple. Derive lane sessions instead. Noise leaves us with A.eKey == B.dKey, so both sides HKDF-expand the same two keys with the same per-lane label and land on a matched pair without exchanging anything. Lanes now cost no handshake, have no half-established state, and die exactly when their base tunnel does. Which lane a packet belongs to rides the low byte of the nebula header's Reserved field, inside the AEAD's associated data. Receiving on a lane needs no permission, since the session exists the moment the base handshake completes. Sending on one needs proof the new 5-tuple works, so a lane stays down until a probe on it is acked and falls back to the base tunnel the moment it stops being acked. Probing is demand-driven off the connection manager's per-tunnel traffic tick: a peer we exchange a trickle with never costs more than its base tunnel, however many lanes are configured. The ack rides the base session on purpose, so a broken reverse lane can't fail a working one. Because the data now rides lane counters, the rehandshake, exhaustion and swap-primary checks take the max counter across the base session and its lanes; otherwise the base counter would sit near zero while a lane ran its keys past the nonce ceiling. Removes OutboundLaneTimer, EnsureLanes, startLaneHandshake, completeLane, completeLaneResponder, makeLaneTrafficDecision and the lane fields on HostInfo. Handshake payload field 3 (the per-lane handshake index) is permanently reserved; peers advertise a TxLanes count instead.
This commit is contained in:
1 parent
8b914e67f4
commit
fb20de39b2
19 files changed
+1223
-1273
No files matched your search
+35
-11
@@ -67,9 +67,16 @@ type ControlHostInfo struct {
|
||||
CurrentRemote netip.AddrPort `json:"currentRemote"`
|
||||
CurrentRelaysToMe []netip.Addr `json:"currentRelaysToMe"`
|
||||
CurrentRelaysThroughMe []netip.Addr `json:"currentRelaysThroughMe"`
|
||||
IsLane bool `json:"isLane,omitempty"`
|
||||
LaneIndex uint16 `json:"laneIndex,omitempty"`
|
||||
SockIdx int `json:"sockIdx,omitempty"`
|
||||
Lanes []ControlLane `json:"lanes,omitempty"`
|
||||
}
|
||||
|
||||
// ControlLane reports one multiport lane of a tunnel. Only lanes we may send on
|
||||
// are listed; receive-only lanes have no state worth showing.
|
||||
type ControlLane struct {
|
||||
Index uint8 `json:"index"`
|
||||
Up bool `json:"up"`
|
||||
Remote netip.AddrPort `json:"remote,omitempty"`
|
||||
MessageCounter uint64 `json:"messageCounter"`
|
||||
}
|
||||
|
||||
// Start actually runs nebula, this is a nonblocking call.
|
||||
@@ -365,11 +372,6 @@ func (c *Control) CloseAllTunnels(excludeLighthouses bool) (closed int) {
|
||||
// Grab the hostMap lock to access the Hosts map
|
||||
c.f.hostMap.Lock()
|
||||
for _, relayHost := range c.f.hostMap.Indexes {
|
||||
// Lanes ride along with their base tunnel's shutdown cascade; closing
|
||||
// them individually would race the cascade's identity-checked deletes.
|
||||
if relayHost.isLane() {
|
||||
continue
|
||||
}
|
||||
if _, ok := relayingHosts[relayHost.vpnAddrs[0]]; !ok {
|
||||
hostInfos = append(hostInfos, relayHost)
|
||||
}
|
||||
@@ -398,9 +400,7 @@ func copyHostInfo(h *HostInfo, preferredRanges []netip.Prefix) ControlHostInfo {
|
||||
CurrentRelaysToMe: h.relayState.CopyRelayIps(),
|
||||
CurrentRelaysThroughMe: h.relayState.CopyRelayForIps(),
|
||||
CurrentRemote: h.GetRemote(),
|
||||
IsLane: h.isLane(),
|
||||
LaneIndex: h.laneIndex,
|
||||
SockIdx: h.sockIdx,
|
||||
Lanes: copyLanes(h),
|
||||
}
|
||||
|
||||
for i, a := range h.vpnAddrs {
|
||||
@@ -418,6 +418,30 @@ func copyHostInfo(h *HostInfo, preferredRanges []netip.Prefix) ControlHostInfo {
|
||||
return chi
|
||||
}
|
||||
|
||||
// copyLanes snapshots the sendable multiport lanes of a tunnel, or nil when it
|
||||
// has none. txAddr is the lane's gate as well as its destination, so a nil load
|
||||
// is exactly "this lane is down and its routine is riding the base tunnel".
|
||||
func copyLanes(h *HostInfo) []ControlLane {
|
||||
ls := h.lanes
|
||||
if ls == nil || ls.txLanes < 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lanes := make([]ControlLane, 0, ls.txLanes-1)
|
||||
for s := 1; s < ls.txLanes; s++ {
|
||||
l := ControlLane{Index: uint8(s)}
|
||||
if addr := ls.txAddr[s].Load(); addr != nil {
|
||||
l.Up = true
|
||||
l.Remote = *addr
|
||||
}
|
||||
if cs := ls.sessions[s]; cs != nil {
|
||||
l.MessageCounter = cs.messageCounter.Load()
|
||||
}
|
||||
lanes = append(lanes, l)
|
||||
}
|
||||
return lanes
|
||||
}
|
||||
|
||||
func listHostMapHosts(hl controlHostLister) []ControlHostInfo {
|
||||
hosts := make([]ControlHostInfo, 0)
|
||||
pr := hl.GetPreferredRanges()
|
||||
|
||||
Reference in new issue
Block a user