Haiku BNetworkRoute: Inspecting Default and Connected Routes
Inspect Haiku IPv4 and IPv6 route-table entries with BNetworkRoute, filter by interface, interpret gateways and masks, and avoid stale snapshots.
BNetworkRoute represents a route entry and provides static methods to query routes known to Haiku’s networking stack. It is useful for diagnostics and network settings interfaces that need to inspect default routes, gateways, destination networks, masks, source addresses, flags, and MTU. The class is a representation and query API; changing fields on a BNetworkRoute object does not itself install or replace a route in the kernel.
That distinction prevents a dangerous category error. A method named SetGateway() changes the object’s in-memory route description. The public class does not expose a commit or add-route method. An application that needs to change system configuration should use the supported network settings/service workflow for its target Haiku version, not assume that mutating a C++ object edits the routing table.
Query with an address family and interface scope
GetRoutes() accepts an address family, an optional interface name, and optional filter flags, filling a BObjectList<BNetworkRoute, true>. The true template argument means the list is configured to own its items; keep its destruction behavior consistent with the API’s ownership contract. Use separate queries for IPv4 and IPv6 when the diagnostic needs both. AF_UNSPEC behavior should not be assumed unless the overload documentation states it.
Use the interface-scoped overload when comparing two adapters. A route table is a current snapshot, not a subscription. A VPN may add or remove routes, DHCP can update the default gateway, and a device can disappear between query and display. Refresh on relevant network notifications and before performing a consequential action.
GetDefaultRoute() returns a BNetworkRoute for a given family and optional interface name. GetDefaultGateway() returns only the gateway address for the selected default route. A successful gateway lookup does not explain every destination’s path; more-specific routes can take precedence. Show the interface and family alongside the default so a user does not confuse one adapter’s gateway with the system-wide path.
Interpret fields as a route tuple
A route combines a destination, mask, optional gateway, optional source, flags, address family, and MTU. A missing gateway can describe a directly connected route rather than a broken object. A mask and destination should be interpreted together; displaying one without the other can mislead. The source address may be relevant to route selection, but it is not proof that an outbound packet used that route.
The class exposes pointers to internal sockaddr values through methods such as Destination(), Gateway(), Mask(), and Source(). These pointers are owned by the BNetworkRoute instance and may be null when the field is absent. Copy the data you need before the route object is destroyed. Do not store a pointer in a UI model after its owning list is cleared.
For user-facing output, convert addresses using the Network Kit’s address helpers or a family-aware formatter. IPv4 and IPv6 have different text forms, and link-layer addresses are different again. Avoid treating sockaddr as a flat in_addr without checking the family and structure length.
When comparing two entries, retain the full tuple and the interface scope. A destination and mask define the network range represented by the entry; a host-specific route can be more specific than a default route. Do not sort the rows by gateway text and present that order as the kernel’s route-selection result. The public query returns route entries, while packet selection can depend on the complete stack state and more-specific entries.
If a UI needs to explain which route could match an address, implement that as a separate, tested diagnostic calculation. Validate family compatibility first, apply the address mask using the correct IPv4 or IPv6 width, and show when the calculation is only an approximation of stack behavior. Better still, use the operating system’s actual lookup or a bounded connection probe when an authoritative answer is required. BNetworkRoute does not expose a method that predicts success for a future socket.
Default route is not a connectivity test
The presence of a default route means the routing table has a candidate path for otherwise unmatched traffic. It does not prove that the gateway responds, DNS works, the network is authenticated, or an application can reach a remote service. A route can exist while the cable is unplugged or the access point is unreachable. Conversely, a host may reach a directly connected local peer without a default route.
Separate diagnostics into layers: interface presence and link state, address configuration, route lookup, name resolution, and application-level request. BNetworkRoute answers a routing-table question. It cannot prove the next hop’s health or the destination’s availability. For a useful report, capture route fields and then perform a bounded connectivity check appropriate to the destination.
Filter and MTU considerations
The filtered GetRoutes() overload accepts route flags. Read the public route.h definitions and API docs for the meaning of each flag; do not hardcode numeric values from a different OS. Filtered views are useful for separating default routes or route classes, but they can hide entries if the wrong mask is used. Preserve the unfiltered result for debugging when a filtered query unexpectedly returns nothing.
The MTU field is a route property exposed by the API. Do not infer an end-to-end path MTU solely from a route entry. Tunnels, encapsulation, interfaces, and remote links can impose additional constraints. Treat MTU as configuration evidence and use the appropriate network diagnostics to investigate fragmentation or path-MTU issues.
A read-only diagnostic example
This excerpt queries default IPv4 routes and reports whether the default route exists:
BNetworkRoute route;
status_t status = BNetworkRoute::GetDefaultRoute(AF_INET, NULL, route);
if (status != B_OK) {
ReportNoDefaultRoute(status);
return;
}
const sockaddr* gateway = route.Gateway();
const sockaddr* destination = route.Destination();
// Format each non-null sockaddr using its address family.
The example is read-only. A caller must check status and null field pointers, and should format IPv4/IPv6 structures correctly. It does not test gateway reachability or cause traffic to use the route.
Lifetime, refresh, and diagnostic race handling
Treat GetRoutes() output as a snapshot. The route can disappear after the query, so a later socket operation may select a different path. Do not promise “traffic will use this route” based on a displayed row. When an operation fails, capture the route table close to the failure time and include the interface state and timestamp.
If using BNetworkRoute::Adopt(), the source object becomes uninitialized according to the API contract. Do not continue reading fields from the adopted-from object. Prefer clear ownership and avoid using the move-like operation unless it provides a measured benefit; the BObjectList ownership model often makes ordinary lifetime management simpler.
Do not mutate the route entry returned by RouteEntry() and expect the kernel to see it. If a program needs to make a settings change, call the documented system configuration API and then re-query to verify the new route. Record both the intended configuration request and the observed route snapshot.
Keep route collection and rendering separated. Gather a compact copy of each route’s addresses, family, flags, interface scope, and MTU on a worker or model thread; then publish an immutable snapshot to the UI. This prevents a table from retaining pointers into objects that a later refresh destroys. If two refreshes overlap, tag each with a generation and discard an older completion so a slow earlier query cannot replace fresher state.
For a diagnostic capture, preserve the query inputs as well as the results: address family, interface filter, flag filter, status, and timestamp. Two route tables are not comparable if one query filtered default routes and the other did not. When an expected route is missing, first repeat an unfiltered query and verify the interface name and family before concluding that the route was never installed.
Validation checklist
Test no route, one default route, multiple interface routes, IPv4 only, IPv6 only, a VPN route, a directly connected route with no gateway, and a route update while the UI is open. Confirm filtering by interface and flags returns expected entries. Remove an interface between enumeration and display and verify no stale sockaddr* survives.
Compare GetDefaultRoute() with GetDefaultGateway() and confirm both are scoped to the same family and interface. Verify the displayed gateway is not treated as a ping result. Test a host that has a route but no upstream connectivity and a host that has only local connectivity. Check address formatting for every family the app supports.
Capture address family, interface name, route flags, destination/mask, gateway, source, MTU, query status, and collection time. This makes route issues reproducible without overstating what the snapshot proves.
BNetworkRoute is a precise read-side API for route diagnostics. Its strongest use is explaining what the current stack knows about candidate paths while remaining honest about what a routing table cannot prove. Keep the data read-only, family-aware, and freshly reconciled.
Related:
- Haiku Network Interfaces: Enumerating State Without Guessing
- Inside Haiku’s Network Stack: Interfaces, Protocol Modules, and Userland Services
Sources: