mesh

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: LGPL-2.1 Imports: 29 Imported by: 0

README

mod/mesh

mod/mesh owns the embedded Yggdrasil node. It creates the Ratatoskr-backed userspace network stack, exposes the node's .pk.ygg identity, and gives the rest of the runtime DialContext and listener access for mesh traffic.

Place in the runtime

flowchart TB
  config["ygg config"] --> mesh["mod/mesh"]
  mesh --> node["Ratatoskr node"]
  node --> listen["Yggdrasil HTTP listener"]
  node --> dial["brother/source dials"]
  server["mod/server"] --> listen
  source["mod/source"] --> dial

Responsibilities

  • Load or validate the node private key.
  • Start Ratatoskr with selectable or passive peer-manager configuration.
  • Configure scheduled refresh, outage recovery, low-peer recovery, and reprobe holdoff.
  • Expose the node address, host, and listener state to server and view context.
  • Provide mesh dialing for .pk.ygg targets.
  • Publish Ratatoskr NodeInfo sigils for service discovery and node identity.
  • Publish bounded peer aggregates and credential-redacted peer details for telemetry.
  • Close the embedded node cleanly during runtime shutdown.

NodeInfo sigils

Ratatoskr publishes Yggdrasil NodeInfo through small named blocks called sigils. mod/mesh builds those blocks once during node startup and passes them to the embedded Ratatoskr node. Every sigil is public: any mesh peer that can read NodeInfo can see the same data.

flowchart TB
  config["stconf.ConfigObj"] --> build["buildSigils"]
  target["target build metadata"] --> custom["yggvault sigil"]
  build --> custom
  build --> services["services sigil"]
  build --> info["info sigil"]
  build --> inet["inet sigil, public domains only"]
  custom --> nodeInfo["Yggdrasil NodeInfo"]
  services --> nodeInfo
  info --> nodeInfo
  inet --> nodeInfo

The mesh layer publishes these sigils:

Sigil Source Purpose
yggvault Generated target build metadata Project-owned build fingerprint for yggvault peers and diagnostics.
services Fixed mesh HTTP port Advertises http:80 for the Yggdrasil entry.
info info.* config plus derived fallback name Publishes the public node card also returned by /info.
inet web.server.domain Advertises the public web domain only when it is not local, private, or loopback.

The yggvault sigil is the custom, project-owned sigil. It uses the top-level NodeInfo key yggvault and carries only build identity. The values below show the stable shape; the generated values differ for every build:

{
  "yggvault": {
    "version": "vX.Y.Z",
    "hash": "<generated source hash>",
    "date": "YYYY-MM-DD"
  }
}

Those values come from generated target metadata, not from operator config. A peer can use the block to identify that the remote node claims to run yggvault, show the advertised build version, compare deployment hashes, or apply peer-specific diagnostics. It is not an authorization mechanism, a release-integrity proof, or a substitute for archive hashes. Treat it as public self-description attached to the Yggdrasil node identity.

mod/mesh/yggvault implements the Ratatoskr sigils.Interface: it can render the block, merge it into a NodeInfo copy, parse the block from another node, and match only when version, hash, and date are present as strings. Its public constructor accepts explicit build fields instead of importing generated target metadata, and Parse accepts foreign NodeInfo for diagnostics and discovery. The parser keeps unknown sibling NodeInfo keys out of the returned fragment, so callers can reason about the yggvault block without accidentally depending on unrelated sigils.

Contracts

  • If ygg.pem_key is empty, mesh is disabled and .pk.ygg dials must fail explicitly.
  • Yggdrasil addresses are IPv6 and must be bracketed in URLs.
  • Mesh links are treated as constrained links: all dials and requests need deadlines, bounded retries, and bounded response sizes.
  • The package should use the Ratatoskr root API unless a lower-level package genuinely needs a core contract.
  • NodeInfo sigils must not contain secrets, credentials, private upstream URLs, or operator-only diagnostics.
  • The yggvault sigil must stay backward-compatible: peers should be able to detect the block by top-level key and read version, hash, and date as strings.
  • mod/mesh/yggvault is the public sigil contract. Runtime wiring may feed it generated build metadata, but the package itself must stay usable without importing generated target code.
  • Mesh snapshots and peer-list reads must not overlap node teardown. Shutdown marks the mesh as closing, drains active snapshot readers, and only then closes the resolver and node.
  • Peer URIs exposed in internal metrics must have userinfo credentials removed, and the peer list must stay bounded.

Important files

  • obj.go: mesh object and public methods.
  • host.go: host derivation from Yggdrasil keys.
  • dial.go: Yggdrasil dial and listener adapters.
  • sigils.go: NodeInfo sigil construction and public identity validation.
  • validate.go: peer-manager validation and selectable-capacity checks.
  • metrics.go: aggregate snapshot and bounded, credential-redacted peer details.
  • yggvault/: small adapter package for Yggdrasil-specific runtime wiring.

Operational notes

The mesh entry is an additional transport for the same service, not a separate data plane. It should behave like the web entry except for listener identity, route labels, and Yggdrasil-specific dialing constraints. Brother RPC availability is controlled by the server config, not by mod/mesh.

passive: true keeps every configured peer and disables latency selection and health recovery. In selection mode, min_peers is an early-recovery threshold, not a desired steady-state count; it must stay below the selectable peer capacity. A non-zero refresh_interval below one minute is raised to the one-minute anti-storm floor at startup.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDisabled means a ygg operation was requested with empty yggdrasil.pem_key.
	ErrDisabled = errors.New("yggdrasil mesh is disabled (yggdrasil.pem_key is empty)")
)

Functions

func GenerateKey

func GenerateKey() ([]byte, string, error)

GenerateKey creates a random node private key and returns its PKCS#8 PEM plus ygg host. One random ed25519 key is already unique enough; the full node identity keeps the whole key through host and certificate.

func HostFromKey

func HostFromKey(pemPath string) (string, error)

HostFromKey derives the ygg host directly from a PEM key without starting a node. Rebuild-cache/self-test uses it to rebuild host-sensitive artifacts under the same entry host as serving, without network boot.

func ResolveName

func ResolveName(configured string, domain string, host string) string

ResolveName returns final info.Name: configured value, normalized domain or ygg host, then stable target.Name fallback. The result is always valid for the info sigil.

func ValidateInfoConfig

func ValidateInfoConfig(info stconf.InfoObj) error

ValidateInfoConfig checks the identity card by ratatoskr info-sigil rules, including field and value limits. Empty Name is allowed because runtime supplies a default.

func ValidateYggConfig added in v0.4.0

func ValidateYggConfig(yg stconf.YggObj) error

ValidateYggConfig checks ygg.peers against ratatoskr peermgr rules so that --validate-config rejects configurations node startup would reject. Pre-existing deployments must keep starting: checks on fields that existed before v1 stay warn-or-clamp at runtime, hard errors apply only to the new fields and to configurations the library itself would reject. A disabled mesh (empty pem_key) skips the checks entirely because the peer list is inert. Invalid or duplicate URIs follow the library contract: they are dropped with startup warnings, and only a list with no usable candidate fails, because node startup would fail on it anyway.

func WriteKeyFile

func WriteKeyFile(filePath string, pemBytes []byte) error

WriteKeyFile writes a private key PEM with secret permissions: 0o600, explicit Chmod, and O_NOFOLLOW. The caller decides whether the file may already exist or be overwritten.

Types

type NodeInterface

type NodeInterface interface {
	DialContext(ctx context.Context, network, address string) (net.Conn, error)
	ListenerFor(transport TransportType) (net.Listener, error)
	Host() string
	Address() net.IP
	OwnsHost(host string) bool
	Enabled() bool
	PeerList() ([]PeerSnapshotObj, bool)
	Close(ctx context.Context) error
}

NodeInterface is the ygg node transport boundary and the only contract for source/server.

type Obj

type Obj struct {
	// contains filtered or unexported fields
}

Obj owns the node. In disabled mode node==nil and enabled==false.

func New

func New(configObj *stconf.ConfigObj, logArr ...zerolog.Logger) (*Obj, error)

New starts a node when pem_key is set and returns a disabled Obj when it is empty. The node lifetime is owned by Close, never by a caller context: tying it to the signal context would begin mesh self-shutdown at SIGTERM, before the HTTP listeners drain ygg requests. With a logger, ratatoskr events go through the shared pipeline; otherwise library noise is discarded.

func (*Obj) Address

func (obj *Obj) Address() net.IP

Address returns the node ygg IPv6 address, nil on disabled Obj.

func (*Obj) Close

func (obj *Obj) Close(ctx context.Context) error

Close stops the resolver, then the node, within ctx budget; it is idempotent and concurrent-safe, and disabled mode is a no-op. Teardown runs once; every caller observes the same result through closeDone. The node bounds its own teardown by the configured CloseTimeout and finishes it in the background when that budget expires, so an early ctx exit never strands shutdown.

func (*Obj) DialContext

func (obj *Obj) DialContext(ctx context.Context, network, address string) (net.Conn, error)

DialContext resolves host (<hex>.pk.ygg or IPv6 literal) into a 200::/7 transport address and opens a connection through the node netstack. It can be used as http.Transport.DialContext and net/rpc dialer.

func (*Obj) Enabled

func (obj *Obj) Enabled() bool

Enabled reports whether the node is running.

func (*Obj) Host

func (obj *Obj) Host() string

Host returns the node ygg host (<hex>.pk.ygg), empty on disabled Obj.

func (*Obj) ListenerFor

func (obj *Obj) ListenerFor(transport TransportType) (net.Listener, error)

ListenerFor returns the ygg-entry listener on the node address, port 80.

func (*Obj) OwnsHost

func (obj *Obj) OwnsHost(host string) bool

OwnsHost reports whether host belongs to the ygg naming scheme. This is a static naming fact and remains true for disabled nodes; reachability is gated separately by Enabled.

func (*Obj) PeerList added in v0.4.0

func (obj *Obj) PeerList() ([]PeerSnapshotObj, bool)

PeerList returns the detailed peer list: credential-redacted, deterministically sorted, and capped at cPeerListMax entries. Results are cached for the telemetry snapshot interval, so request pressure costs at most one live node read per interval. Callers must treat the returned slice as read-only. ok is false on a disabled or closing node.

func (*Obj) RegisterMetrics added in v0.4.0

func (obj *Obj) RegisterMetrics(meterObj metric.Meter) error

RegisterMetrics publishes flat ygg aggregates; a disabled node registers nothing. Per-peer series stay out of the exposition on purpose: inbound peers are foreign input and would grow label cardinality without bound. Traffic sums are gauges, not counters, because a disconnected peer drops out of the sum and makes it non-monotonic.

func (*Obj) Snapshot added in v0.4.0

func (obj *Obj) Snapshot() (SnapshotObj, bool)

Snapshot returns cheap peer aggregates; ok is false on a disabled or closing node. It runs every telemetry collect interval, so it sums counters without building per-peer DTOs. The snapMu read lock pairs with the Close write barrier: the library does not guard node state reads after Close, so no snapshot may overlap node teardown.

type PeerSnapshotObj added in v0.4.0

type PeerSnapshotObj struct {
	URI           string
	Up            bool
	Inbound       bool
	PublicKey     string
	LatencyNanos  int64
	Cost          uint64
	RXBytes       uint64
	TXBytes       uint64
	UptimeSeconds float64
	LastError     string
	LastErrorTime time.Time
}

PeerSnapshotObj is one peer connection at snapshot time.

type SnapshotObj added in v0.4.0

type SnapshotObj struct {
	PeersKnown       int
	PeersUp          int
	PeersInbound     int
	ActiveSelected   int
	RXBytes          uint64
	TXBytes          uint64
	BestLatencyNanos int64
	// NoReachableNotifications counts observed isolation notifications. The library delivers them
	// best-effort into a capacity-one channel, so rapid bursts coalesce: treat it as a lower bound.
	NoReachableNotifications uint64
}

SnapshotObj carries the cheap ygg aggregates for the metrics group.

type TransportType

type TransportType uint8

TransportType identifies which listener mod/server requests.

const (
	// TransportYgg is the ygg-entry listener, the only mesh transport.
	TransportYgg TransportType = iota + 1
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL