pamoja.routing

Idiomatic mesh-routing facade.

Flooding always works but costs every node airtime and power on every packet. Once a mesh has settled, most traffic goes to a few known places, and a node that remembers the way can forward to one neighbour instead of shouting at the whole network. Routing is that optimisation, and it falls back to flooding rather than failing whenever it does not know the way.

 1"""Idiomatic mesh-routing facade.
 2
 3Flooding always works but costs every node airtime and power on every packet.
 4Once a mesh has settled, most traffic goes to a few known places, and a node that
 5remembers the way can forward to one neighbour instead of shouting at the whole
 6network. Routing is that optimisation, and it falls back to flooding rather than
 7failing whenever it does not know the way.
 8"""
 9
10from __future__ import annotations
11
12import enum
13
14from pamoja._native import ForwardDecision, Route, Router
15from pamoja._native import routing_default_capacity as _default_capacity
16
17__all__ = [
18    "DEFAULT_CAPACITY",
19    "ForwardAction",
20    "ForwardDecision",
21    "Route",
22    "Router",
23    "router",
24]
25
26#: A routing table size for a caller with no reason to choose one.
27DEFAULT_CAPACITY = _default_capacity()
28
29
30class ForwardAction(str, enum.Enum):
31    """What to do with a packet bound for a given node."""
32
33    #: The packet is for this node; hand it to the application.
34    DELIVER = "Deliver"
35    #: A route is known; unicast the packet to the next hop reported alongside.
36    RELAY = "Relay"
37    #: No route is known; fall back to flooding the packet.
38    FLOOD = "Flood"
39
40
41def router(address: int, capacity: int = DEFAULT_CAPACITY) -> Router:
42    """Create an empty routing table for a node.
43
44    :param address: The address of this node, which is what a routing decision
45        recognises as a local delivery.
46    :param capacity: How many routes to make room for. A capacity of zero floods
47        every unknown destination, which is the behaviour with no table at all.
48    :returns: The routing table, ready to learn from the traffic the node hears.
49    """
50    return Router(address, capacity)
DEFAULT_CAPACITY = 64
class ForwardAction(builtins.str, enum.Enum):
31class ForwardAction(str, enum.Enum):
32    """What to do with a packet bound for a given node."""
33
34    #: The packet is for this node; hand it to the application.
35    DELIVER = "Deliver"
36    #: A route is known; unicast the packet to the next hop reported alongside.
37    RELAY = "Relay"
38    #: No route is known; fall back to flooding the packet.
39    FLOOD = "Flood"

What to do with a packet bound for a given node.

DELIVER = <ForwardAction.DELIVER: 'Deliver'>
RELAY = <ForwardAction.RELAY: 'Relay'>
FLOOD = <ForwardAction.FLOOD: 'Flood'>
class ForwardDecision:

A routing decision, and the neighbour it names when there is one.

next_hop

The neighbour to unicast to, or None unless the action is Relay.

action

What to do with the packet: Deliver, Relay, or Flood.

class Route:

A learned way to reach one node.

next_hop

The neighbour to send a packet to on the way there.

dst

The node this route reaches.

cost

What the route costs, usually in hops.

class Router:

One node routing table, learned from the traffic the node hears.

def observe(self, /, origin, via, cost):

Learns a route from a packet that arrived, reporting whether it changed the table.

def next_hop(self, /, dst):

The neighbour to send a packet to on the way to dst, or None.

def cost(self, /, dst):

What the known route to dst costs, or None when none is known.

def route(self, /, dst):

The whole route to dst, or None when none is known.

def forward(self, /, dst):

Decides what to do with a packet bound for dst.

def forget(self, /, dst):

Forgets the route to dst, for example after it stops answering.

capacity

How many routes the table can hold.

address

The address this router answers for.

def router(address: int, capacity: int = 64) -> Router:
42def router(address: int, capacity: int = DEFAULT_CAPACITY) -> Router:
43    """Create an empty routing table for a node.
44
45    :param address: The address of this node, which is what a routing decision
46        recognises as a local delivery.
47    :param capacity: How many routes to make room for. A capacity of zero floods
48        every unknown destination, which is the behaviour with no table at all.
49    :returns: The routing table, ready to learn from the traffic the node hears.
50    """
51    return Router(address, capacity)

Create an empty routing table for a node.

Parameters
  • address: The address of this node, which is what a routing decision recognises as a local delivery.
  • capacity: How many routes to make room for. A capacity of zero floods every unknown destination, which is the behaviour with no table at all. :returns: The routing table, ready to learn from the traffic the node hears.