General description

Soft-Router is the SSG routing function that builds and maintains its own routing table. It is implemented on top of standard Linux mechanisms (kernel route table, network namespace) and a third-party routing daemon (BIRD, FRR, etc.) that handles dynamic routing protocols, while SSG uses the table built by the daemon to route subscriber traffic. In addition to basic routing, Soft-Router supports VRF Lite — isolation of routing tables for different subscriber groups or services within a single device.

SSG itself does not build the routing table. It delegates this work to proven specialized tools; the internal router architecture example uses the BIRD routing daemon. The routing daemon processes the required routing protocols (BGP, OSPF, etc.), uses them to build a common routing table and loads it into the operating system kernel. SSG routes packets according to this table. In other words, building the routing table and processing traffic according to it are separated.

Instead of BIRD, you can use another routing daemon that builds a routing table in the Linux kernel — see Supported routing daemons.
SSG reads the routing table only through the standard Linux interface, so it is compatible with any routing daemon.

Internal architecture

Since BIRD builds the routing table in the OS kernel, the BIRD routing daemon runs in a separate net namespace (router netns in the internal router architecture diagram) so that the Linux server itself does not apply these rules. Routing protocol packets arrive at the SSG in/out devices as part of the general traffic. For each in/out device involved in routing, a veth pair of "shadow" interfaces is created: a TAP interface on the SSG side (for example, bng-w) and a peer interface (for example, rib-w) — a regular system interface in the routing daemon netns.

System requirements are described in Hardware requirements and performance.

Data from the kernel route table is read (rtnetlink) into the router RIB (Routing Information Base). RIB is a prefix tree that is convenient to modify on kernel route table change events (deleting/adding entries). RIB is handled by a separate router thread, because RIB does not support multithreaded access.

Synchronization is performed in at least two passes: it is considered successful if two consecutive reads of the Linux route table return the same number of entries. fastDPI keeps reading the route table until this condition is met; however, if four consecutive attempts fail, fastDPI builds its RIB/FIB from the last attempt and schedules a new synchronization after a short time (2 seconds).

fastDPI worker threads use the FIB (Forwarding Information Base). This structure is designed for multithreaded lookup (LPM — longest prefix match), but not for modification (deleting/adding entries). A FIB can only be built from scratch from the RIB and then used for LPM. Therefore, SSG has two FIBs — the current one (used for routing by the worker threads right now) and the "future" one. Every router_fib_refresh seconds, SSG checks whether the RIB has changed since the current FIB was built. If it has, SSG builds a new FIB (in the router thread) in place of the "future" one and then immediately switches the current FIB to the new one. This way, the worker threads see all changes made to the routing table.

Supported routing daemons

The routing daemon (BIRD, FRR, etc.) and SSG settings must be consistent: the routing daemon must create a kernel route table with the number set by the router_kernel_table parameter.

Supported routing daemons:

  1. BIRD. BIRD version 2 and higher is supported. Version 1 is not supported.
    Configuration example
    Official documentation
VAS Experts technical support specialists can help you install and configure BIRD.

LAG support

The router supports link aggregation (LAG).

With aggregated links, packets that must be diverted to the TAP interface can arrive at any device in the LAG. To avoid creating essentially identical TAP interfaces for every device in the LAG, the router takes into account which devices belong to the LAG and diverts traffic of the specified subnets to the TAP (to the BIRD daemon) from all of them.

Each LAG is defined by a separate section in fastdpi.conf that lists all devices included in the LAG. We recommend using active LAG (with LACP); use "transparent" LAG without LACP only for SSG redundancy where acceptable (for example, for filtering). Example of an active LAG towards inet:

in_dev=01-00.0:02-00.0
out_dev=01-00.1:02-00.1

lag {
    name=inet
    lacp=2
    short_timeout=on
    device=01-00.1
    device=02-00.1
}

router_device {
    device=01-00.1
    tap=bng-w
    peer=rib-w
    subnet=10.0.10.0/26
}

Where:

  • in_dev, out_dev — input and output devices combined into the LAG.
  • lag — description of the LAG towards inet:
    • name — optional LAG name, used only for log output;
    • lacp — LACP processing mode:
      • 0 — LACP processing is disabled: SSG does not hold the LAG and passes traffic "transparently" (default);
      • 1 — passive mode: SSG does not send periodic LACPDUs but responds to incoming ones;
      • 2 — active mode: SSG sends periodic LACPDUs. Recommended value, used in the example;
    • short_timeout — LACP timeout: on — short, off — long;
    • device — a device included in the LAG. Each device is set by a separate device parameter.
  • router_device — router interface description:
    • device — device name from out_dev. The veth pair of TAP interfaces is created only for this device, not for every device in the LAG;
    • tap — TAP interface name for the device. Default — dpi + device name;
    • peer — name of the peer TAP interface in the netns. Default — rib + device name;
    • subnet — a subnet diverted from the general traffic to the TAP interface. If there are several subnets, each is set by a separate subnet parameter.

If the router works both towards inet and towards subs (for example, BGP on the inet side and OSPF towards subs), a separate router_device section is set for the LAG of each direction. Active LAG configuration is described in detail in Configuring on-stick and LAG/LACP.

The lag sections in fastdpi.conf are cold parameters: changing the LAG description requires a fastDPI restart.

ARP management

NeighborDB is a nexthop database maintained by fastDPI itself: it sends ARP requests to resolve nexthop MAC addresses and updates the ARP cache for these nexthops. The following options control updates:

  • router_neighbor_lifetime — lifetime of an ARP cache entry, in seconds.
    After this time, the entry must be refreshed by sending an ARP request (ICMPv6 NDP for IPv6).
    Default: 300 seconds.
  • router_neighbor_refresh_timeout — time to wait for a response to an ARP request, in seconds.
    Default: 3 seconds.
  • router_neighbor_refresh_attempt — number of failed refresh attempts after which an ARP cache entry is marked Unreachable; in other words, how many consecutive ARP Requests must go unanswered for the entry to become unreachable.
    Default: 10 attempts.
  • router_neighbor_unreachable_refresh — after an entry becomes Unreachable, fastDPI periodically tries to revive it by sending ARP Requests. This option sets that period in seconds.
    Default: 30 seconds.

A nexthop entry consists of:

  • nexthop IP;
  • Mandatory — name of the port used to reach this nexthop (for LAG — one of the ports in the LAG);
  • Optional — VLAN
  • Optional — nexthop MAC address. Entries with an explicitly set nexthop MAC address are static ARP cache records — ARP requests are never sent for them.

NeighborDB (IPv4 and IPv6) is stored in SDR in the router.mdb file. SDR (System Data Repository) is a storage similar to UDR, but it holds system settings. The SDR directory is set by the sdr_path parameter, default — /var/db/dpisdr.

NeighborDB is managed (entries added/modified/deleted) with CLI commands:

  • router neighbor dump — outputs the full list of all loaded entries and their internal state
  • router neighbor dump db — outputs a dump of the router.mdb database.
  • router neighbor add — adds a new entry (new nexthop) to NeighborDB.
  • router neighbor update — modifies an existing NeighborDB entry
  • router neighbor delete — deletes a NeighborDB entry
  • router neighbor refresh — forces a refresh (sends an ARP Request) of the MAC address of a specific nexthop IP, of all nexthops in the specified VRF, or of the entire NeighborDB
  • router neighbor purge — deletes all NeighborDB entries (full NeighborDB cleanup).
The syntax of the commands above is available with:
fdpi_cli <command> ?

Example output of the router neighbor add command:

[root@dpi ~]# fdpi_cli router neighbor add 192.168.70.2 dev=00:17.0 vlan=111
  IP=192.168.70.2
  MAC=<n/a> device='00-17.0'
  Placement in neighbor cache: index=3 gen=95
  State: [0]Initial, remaining refresh probe count=0
  Next refresh: 2026/11/11 13:08:58, -00:00:00.106 (10026508443332220 ticks)

Example output of the router neighbor dump command:

[root@dpi ~]# fdpi_cli router neighbor dump

Rec#0
  IP=192.168.70.2
  MAC=<n/a> device='00-17.0'
  Placement in neighbor cache: index=3 gen=95
  State: [1]Refreshing, remaining refresh probe count=6
  Next refresh: 2026/11/11 13:09:11, +00:00:00.699 (10026532995292063 ticks)

----------
TOTAL: 1 recs

ARP cache priority

With NeighborDB, fastDPI has two independent sources of ARP cache entries:

  • [previous] the OS network stack in the netns. fastDPI intercepts the interaction with neighbors and fills its ARP cache for nexthops accordingly. ARP requests are sent by Soft-Router or any other service that requests neighbor data.
  • [new] NeighborDB: fastDPI itself keeps the entries up to date by sending ARP Requests in time. NeighborDB entries have higher priority than entries obtained from the OS network stack.

Address announcement specifics

Subscriber announcements and NAT pool

NAT pools are announced only in the default VRF.

Subscriber address announcement is enabled by a parameter in fastdpi.conf:

router_subs_announce=6

The parameter is a bit mask. Values:

  • 0x00001 — announce the subscriber address towards subs
  • 0x00002 — announce the subscriber address towards inet (if NAT is not enabled for the subscriber)
  • 0x00004 — announce NAT subnets towards inet
  • 0x00008 — announce subscriber gateways (the direction is set by flags 0x00001, 0x00002)
  • 0x10000 — withdraw the announcement of an L3 subscriber on acct idle (acct session closed by idle timeout)

Default: 0 — announce nothing

Flags are added together. Possible router_subs_announce values:

Value (hex) Value (dec) Flags What is announced Note
0x00000 0 — nothing is announced
0x00001 1 0x00001 subscriber address towards subs
0x00002 2 0x00002 subscriber address towards inet (if NAT is not enabled for the subscriber)
0x00003 3 0x00001 + 0x00002 subscriber address towards subs and inet
0x00004 4 0x00004 NAT subnets towards inet
0x00005 5 0x00001 + 0x00004 subscriber address towards subs + NAT subnets towards inet
0x00006 6 0x00002 + 0x00004 subscriber address towards inet + NAT subnets towards inet
0x00007 7 0x00001 + 0x00002 + 0x00004 subscriber address towards subs and inet + NAT subnets towards inet
0x00008 8 0x00008 subscriber gateways (the direction is set by flags 0x00001, 0x00002) not used
0x00009 9 0x00001 + 0x00008 subscriber address and subscriber gateways towards subs
0x0000a 10 0x00002 + 0x00008 subscriber address and subscriber gateways towards inet
0x0000b 11 0x00001 + 0x00002 + 0x00008 subscriber address and subscriber gateways towards subs and inet
0x0000c 12 0x00004 + 0x00008 NAT subnets towards inet + subscriber gateways (the direction is set by flags 0x00001, 0x00002) not used
0x0000d 13 0x00001 + 0x00004 + 0x00008 subscriber address towards subs + NAT subnets towards inet + subscriber gateways towards subs
0x0000e 14 0x00002 + 0x00004 + 0x00008 subscriber address towards inet + NAT subnets towards inet + subscriber gateways towards inet
0x0000f 15 0x00001 + 0x00002 + 0x00004 + 0x00008 subscriber address towards subs and inet + NAT subnets towards inet + subscriber gateways towards subs and inet

To also withdraw the announcement of an L3 subscriber when its acct session is closed by idle timeout, add the 0x10000 flag (65536) to a value from the table. For example, router_subs_announce=0x10006 (65542) — announce the subscriber address and NAT subnets towards inet and withdraw the subscriber announcement on idle timeout. The values 0x10000, 0x10008 and 0x1000c are not used.

Public CIDR for NAT Service Announcement

NAT public address subnets are announced only towards inet when SSG starts and when NAT profiles are added/removed/modified.

Announcement of Public IP addresses after authorization

Subscriber addresses can be announced both towards inet and towards subs. However, if the subscriber IP address is in the private address range and service 11 is assigned to it, the subscriber address is not announced towards inet, so define private address ranges carefully.

The announcement is made to the BIRD routing table for all TAP devices of the allowed direction; BIRD then picks up the changes and announces them via the relevant protocols according to its configuration.

If nat_exclude_private=1 is set in fastdpi.conf (do not apply NAT to "private IP → private IP" packets), SSG will announce the private address of a subscriber with NAT enabled towards inet, because the upstream router must know the route to the subscriber's private IP address.

Announcement of L3 subscriber addresses

Algorithm for announcing IP addresses of L3 subscribers:

  • by default, the address is announced on successful authorization (accept) and is NOT announced on failed authorization (reject)
  • the fastdpi.conf parameter auth_announce_reject globally allows announcements for reject. Possible values:
    • 1 — announce unauthorized (Reject) subscribers
    • 0 — do not announce unauthorized (Reject) subscribers (default)
  • RADIUS attribute VasExperts-Route-Announce: value 0 — do not announce the subscriber address, value 1 — announce it. This attribute takes precedence over auth_announce_reject.

So, the following algorithm decides whether to announce the subscriber IP address:

  • if the VasExperts-Route-Announce attribute is explicitly set in the RADIUS response (Accept or Reject), the address is announced for VasExperts-Route-Announce=1 and is NOT announced for VasExperts-Route-Announce=0
  • if the RADIUS response contains no VasExperts-Route-Announce attribute:
    • For Access-Accept (successful authorization), the subscriber IP address is announced
    • For Access-Reject (failed authorization), the IP address is announced only if the fastdpi.conf parameter auth_announce_reject=1
This algorithm is applied when the router announcement function is called; whether the subscriber IP address is announced and in which direction is controlled by the router fastdpi.conf parameter router_subs_announce.

This algorithm also applies to ARP authorization and GTP authorization, that is, to all authorization types where the subscriber IP address is known when authorization is called and cannot change.

For other L2 authorization types (DHCP, PPP — all types where the IP address is explicitly assigned), the VasExperts-Route-Announce attribute is ignored and the address is announced once it is assigned to the subscriber.

Multi-path routing (ECMP) support

SSG supports Equal-cost multi-path routing (ECMP).

SSG balances traffic (round-robin) at the flow level across all routes of a multi-path. Flow-level balancing means that a flow is bound to one of the multi-path routes, and the selected route does not change until the flow ends (unless the multi-path set changes due to external events from the routing daemon).

When sending traffic over the selected route, SSG uses the tx device associated with that route.

NUMA-aware route selection

On dual-CPU servers, SSG can take the system NUMA topology into account when selecting a route from a multi-path. This requires two conditions:

  • the numa=on parameter is set in fastdpi.conf;
  • the system has more than one NUMA node (the number of NUMA nodes is determined by DPDK during initialization).

In this case, priority is given to the route via a tx device that belongs to the same NUMA node as the rx port that received the packet. If the multi-path has no such route, the route is selected without regard to NUMA.

Configuration

No configuration is required in SSG to enable multi-path. ECMP support is enabled in the routing daemon configuration. For example, in BIRD, ECMP is enabled with merge paths yes in the kernel protocol, see the BIRD documentation.

Was this information helpful?