Search documentation of macula

# macula_route_packet (macula v4.4.1)

View Source

Egress routing for macula-net packets.

Per the macula-net spec (PLAN_MACULA_NET.md §5.2), this slice owns the egress flow:

IPv6 packet from TUN → look up dst → encapsulate → send to station

Two modes:

`static`
  Phase 1 default. Caller pre-populates an ETS table of `{Address, StationId, SendFun}`. Used by tests and the smoke / netns demos. Selected when `configure/1` receives `stations`.
`dht`
  Phase 2. On miss in `macula_cache_route`, calls `macula_resolve_address:resolve/3` for the destination, caches the answer (TTL = record's `expires_at`), and dials the resolved host via the configured `connect_fn`. Selected when `configure/1` receives `resolver`.

CBOR encoding uses `macula_cbor_nif:pack/1`.

# Summary

## Types

connect_fun/0
own_address/0
resolver/0
send_fun/0
station_entry/0

## Functions

configure(_)

Install routing. Two shapes

dispatch(Packet)

Egress dispatch. Takes a raw IPv6 packet, looks up its destination, wraps it in a macula-net envelope, sends to the hosting station. In dht mode performs a DHT resolve on cache miss and dials the resolved host via the configured `connect_fn`.

dispatch_envelope(CborEnvelope, Dst)

Forward a pre-built macula-net envelope toward `Dst`.

encapsulate(Payload, Src, Dst)

Build a macula-net envelope around an IPv6 packet. Public so other layers (e.g. daemon attachment) can craft envelopes directly.

lookup(Address)

Look up the route for `Address`.

mode()
routes()

Return the configured static stations (diagnostics; empty in dht mode).

# Types

# connect_fun/0

    -type connect_fun() ::
              fun((StationId :: binary(), Host :: binary() | string(), Port :: 1..65535) ->
                      ok | {error, term()}).

# own_address/0

    -type own_address() :: <<_:128>>.

# resolver/0

    -type resolver() ::
              #{realm_pubkey := <<_:256>>,
                find_fn := macula_resolve_address:find_fn(),
                connect_fn := connect_fun(),
                send_fn := send_fun()}.

# send_fun/0

    -type send_fun() :: fun((StationId :: binary(), CborEnvelope :: binary()) -> ok | {error, term()}).

# station_entry/0

    -type station_entry() :: #{address := <<_:128>>, station := binary(), send := send_fun()}.

# Functions

# configure(_)

    -spec configure(#{own_address := own_address(), stations => [station_entry()], resolver => resolver()}) ->
                       ok.

Install routing. Two shapes:

Static: `#{own_address, stations}` — Phase 1 / tests. DHT: `#{own_address, resolver}` — Phase 2.

Idempotent. Calling again replaces the previous configuration.

# dispatch(Packet)

    -spec dispatch(Packet :: binary()) ->
                      {ok, StationId :: binary()} | {error, no_route | malformed_packet | term()}.

Egress dispatch. Takes a raw IPv6 packet, looks up its destination, wraps it in a macula-net envelope, sends to the hosting station. In dht mode performs a DHT resolve on cache miss and dials the resolved host via the configured `connect_fn`.

# dispatch_envelope(CborEnvelope, Dst)

    -spec dispatch_envelope(CborEnvelope :: binary(), Dst :: <<_:128>>) ->
                               {ok, StationId :: binary()} | {error, term()}.

Forward a pre-built macula-net envelope toward `Dst`.

Same lookup + resolve + connect + send pipeline as `dispatch/1`, but skips the IPv6-to-CBOR encapsulation step. Used by `macula_host_attach_controller` when a hosted daemon emits a data envelope whose `dst` is neither hosted on the same station nor the station's own address — the host station forwards the same bytes onward, preserving the envelope's `src` so the routing is transparent at L3.

# encapsulate(Payload, Src, Dst)

    -spec encapsulate(Payload :: binary(), Src :: <<_:128>>, Dst :: <<_:128>>) -> binary().

Build a macula-net envelope around an IPv6 packet. Public so other layers (e.g. daemon attachment) can craft envelopes directly.

# lookup(Address)

    -spec lookup(<<_:128>>) -> {ok, #{station := binary(), send := send_fun()}} | not_found.

Look up the route for `Address`.

In static mode this is the synchronous lookup of Phase 1. In dht mode the lookup is cache-only — a cold miss returns `not_found` rather than triggering a DHT call (use `dispatch/1` for the full resolve+connect+send path).

# mode()

    -spec mode() -> static | dht | undefined.

# routes()

    -spec routes() -> [#{address := <<_:128>>, station := binary()}].

Return the configured static stations (diagnostics; empty in dht mode).