Preview — /tmp/sv-test/splicevpn/linkmanager/linkmanager.go

/tmp/sv-test/splicevpn/linkmanager/linkmanager.go

// Package linkmanager is the Phase-2 home for link bonding — combining multiple
// internet connections for more bandwidth, redundancy, or both. It is intentionally
// a stub: the MVP runs a single WireGuard path. This file fixes the interface so the
// bonding work slots in without disturbing the control plane.
//
// Design sketch
// -------------
// WireGuard is single-path, so bonding can't live "inside" one tunnel. The plan:
//
//  1. Detect the available WANs (default routes / interfaces with distinct gateways).
//  2. Bring up one WireGuard path PER WAN to the same peer/hub (distinct ListenPorts,
//     bound to each WAN's source address).
//  3. Put a multipath SCHEDULER above them that sprays/duplicates packets across paths
//     per the chosen Mode:
//     - Aggregate  : stripe packets across paths -> higher combined throughput
//     - Redundant  : duplicate across paths, de-dup at the far end -> seamless failover
//     - Both       : stripe, but mirror a flow onto a second path when one degrades
//  4. Reorder/de-dup at the receiver (sequence numbers + a small jitter buffer).
//
// This is genuinely hard (MPTCP-class problems: reordering, congestion control per
// path, asymmetric latency). It is deliberately out of MVP scope.
package linkmanager

import "context"

// Mode is the bonding behaviour, derived from the agent's "speed/resilience/both" profile.
type Mode int

const (
	ModeAggregate Mode = iota // maximise combined bandwidth
	ModeRedundant             // maximise resilience (duplicate + failover)
	ModeBoth                  // balance of the two
)

// Link is one underlying internet path (one WAN).
type Link struct {
	Iface    string // e.g. "eth0", "wwan0"
	SourceIP string // local source address to bind this path to
	Gateway  string // next hop for this WAN
	ProbeRTT int    // last measured RTT (ms); 0 = unknown
	Up       bool
}

// Bonder schedules traffic across multiple Links. The MVP provides a single-link
// no-op implementation; Phase 2 provides the real multipath scheduler.
type Bonder interface {
	// Discover enumerates the usable WANs on this host.
	Discover(ctx context.Context) ([]Link, error)
	// Bind establishes one transport path per link for the given mode.
	Bind(ctx context.Context, links []Link, mode Mode) error
	// Stats reports per-link health for the scheduler and the dashboard.
	Stats() []Link
	// Close tears down all paths.
	Close() error
}

// SingleLink is the MVP behaviour: no bonding, just the OS default route.
type SingleLink struct{}

func (SingleLink) Discover(context.Context) ([]Link, error) { return nil, nil }
func (SingleLink) Bind(context.Context, []Link, Mode) error { return nil }
func (SingleLink) Stats() []Link                            { return nil }
func (SingleLink) Close() error                             { return nil }