Route

The Route class represents a single kernel routing table entry. It exposes the route’s key fields (destination, prefix, interface index) as immutable properties, and mutable fields (gateway, metric, type, scope, protocol) that are updated in place by RouteManager when the kernel notifies a change.

Routes are managed by RouteManager and are represented as shared pointers.


Obtaining a Route

Routes cannot be created directly. Use RouteManager to look them up or enumerate them:

// libjoin.
#include <join/routemanager.hpp>
#include <join/route.hpp>

using namespace join;

RouteManager& manager = RouteManager::instance();

// Look up by interface index, destination, prefix
Route::Ptr route = manager.findByIndex(2, IpAddress("10.0.0.0"), 8);
if (!route)
{
    // Route not found
}

Key properties (immutable)

The following fields form the unique identity of a route and never change after creation:

uint32_t         idx    = route->index();   // output interface index
const IpAddress& dest   = route->dest();    // destination network address
uint32_t         prefix = route->prefix();  // prefix length

Mutable properties

These fields reflect the current kernel state and are updated automatically when the kernel notifies a change:

IpAddress gw      = route->gateway();   // next-hop address (wildcard if on-link)
uint32_t  metric  = route->metric();    // route metric / priority
uint8_t   type    = route->type();      // RTN_UNICAST, RTN_BLACKHOLE, …
uint8_t   scope   = route->scope();     // RT_SCOPE_UNIVERSE, RT_SCOPE_LINK, …
uint8_t   proto   = route->protocol();  // RTPROT_STATIC, RTPROT_KERNEL, …

Type checks

if (route->isUnicast())     { /* RTN_UNICAST — normal forwarding */ }
if (route->isBlackhole())   { /* RTN_BLACKHOLE — silently drop */ }
if (route->isUnreachable()) { /* RTN_UNREACHABLE — ICMP unreachable */ }
if (route->isProhibit())    { /* RTN_PROHIBIT — ICMP prohibited */ }
if (route->isLocal())       { /* RTN_LOCAL — local delivery */ }

Scope checks

if (route->isScopeUniverse()) { /* RT_SCOPE_UNIVERSE */ }
if (route->isScopeLink())     { /* RT_SCOPE_LINK */ }
if (route->isScopeHost())     { /* RT_SCOPE_HOST */ }

Protocol checks

if (route->isStatic()) { /* added by user — RTPROT_STATIC */ }
if (route->isKernel()) { /* added by kernel — RTPROT_KERNEL */ }
if (route->isDhcp())   { /* added by DHCP client — RTPROT_DHCP */ }
if (route->isBoot())   { /* added at boot — RTPROT_BOOT */ }

Modifying a route

Update gateway and metric

set() replaces the route in the kernel table (RTM_NEWROUTE with NLM_F_REPLACE):

IpAddress newGateway("192.168.1.254");
uint32_t  newMetric = 200;

// Asynchronous
route->set(newGateway, newMetric);

// Synchronous
if (route->set(newGateway, newMetric, true) == -1)
{
    std::cerr << "Failed: " << lastError.message() << "\n";
}

Remove a route

// Asynchronous
route->remove();

// Synchronous
if (route->remove(true) == -1)
{
    std::cerr << "Failed: " << lastError.message() << "\n";
}

⚠️ After a successful remove(), the Route::Ptr may still be held by the caller but the entry is erased from RouteManager’s cache. Do not reuse the pointer to re-add the route — call RouteManager::addRoute() instead.


Comparison operators

Two Route::Ptr values are compared by (index, destination, prefix):

if (routeA == routeB) { /* same routing entry */ }
if (routeA <  routeB) { /* ordering: index → dest → prefix */ }

Return values

set() and remove() return:

  • 0 on success
  • -1 on failure (check lastError for details)

Summary

PropertyImmutableThread-safe read
index()✅✅
dest()✅✅
prefix()✅✅
gateway()✅ (mutex)
metric()✅ (mutex)
type()✅ (mutex)
scope()✅ (mutex)
protocol()✅ (mutex)