DDS Domain Router Guide

The AstuteDDS Router (astutedds-router) bridges DDS topics between multiple domains, enabling cross-domain data distribution with automatic type compatibility checking and QoS mapping.

What is the AstuteDDS Router?

The AstuteDDS Router is a daemon application that:

  • Bridges Domains: Connects multiple DDS domains into a unified network
  • Routes Topics: Forwards messages from source topics to target topics
  • Type Checking: Validates type assignability before routing
  • QoS Mapping: Automatically maps reliability and durability policies
  • Security-Aware: Optional security-gated routing
  • Payload Processing: Supports filtering and transformation hooks
  • Runtime Status: Exports JSON status for monitoring

Architecture

graph LR subgraph Domain0["Domain 0"] P0["Participant 0"] T0["Topic A"] W0["Writer"] P0 --> T0 P0 --> W0 end subgraph Domain1["Domain 1"] P1["Participant 1"] T1["Topic A"] R1["Reader"] P1 --> T1 P1 --> R1 end subgraph Router["AstuteDDS Router"] R["Route: Domain0.A → Domain1.A"] end W0 -.publish.-> R R -.forward.-> R1

Configuration

The router is configured via YAML file (router_config.yaml):

# Global settings
status_file: "/tmp/astutedds-router-status.json"
status_interval_ms: 1000
security_enabled: false

# Domains to connect
domains:
  - domain_id: 0
    participant_id: 1
  - domain_id: 1
    participant_id: 2

# Routes: forward messages from source to target
routes:
  - source_domain: 0
    source_topic: "Circle"
    target_domain: 1
    target_topic: "Circle"
    type_name: "ShapesDemo::ShapeType"
    reliability: RELIABLE
    durability: TRANSIENT_LOCAL
    require_security: false

  - source_domain: 1
    source_topic: "Square"
    target_domain: 0
    target_topic: "Square"
    type_name: "ShapesDemo::ShapeType"
    reliability: BEST_EFFORT
    durability: VOLATILE
    require_security: false

Configuration Options

Global Section

Option Type Default Description
status_file string /tmp/astutedds-router-status.json Output path for JSON status
status_interval_ms integer 1000 How often to write status (ms)
security_enabled boolean false Enable security-gated routes

Domains Section

Option Type Required Description
domain_id integer Yes DDS domain number
participant_id integer Yes Participant ID within domain

Routes Section

Option Type Default Description
source_domain integer Source domain ID
source_topic string Source topic name
target_domain integer Target domain ID
target_topic string Target topic name
type_name string Data type name (for assignability checking)
reliability enum RELIABLE RELIABLE or BEST_EFFORT
durability enum TRANSIENT_LOCAL VOLATILE, TRANSIENT_LOCAL, TRANSIENT, PERSISTENT
require_security boolean false Require security for this route

Running the Router

Basic Usage

cd build
./bin/astutedds-router ../tools/router/router_config.yaml

With Custom Configuration

./bin/astutedds-router /etc/astutedds/router.yaml

With Logging

# Enable verbose logging
ASTUTEDDS_LOG_LEVEL=DEBUG ./bin/astutedds-router router_config.yaml

Monitoring Router Status

The router writes JSON status at status_file location:

watch -n 1 "cat /tmp/astutedds-router-status.json | jq ."

Status JSON structure:

{
  "timestamp": "2026-05-17T14:30:45Z",
  "uptime_seconds": 3600,
  "domains": [
    {
      "domain_id": 0,
      "participant_guid": "01:02:03:04-05:06:07:08-09:0a:0b:0c-00:00:03:c2",
      "discovered_writers": 5,
      "discovered_readers": 3
    },
    {
      "domain_id": 1,
      "participant_guid": "0d:0e:0f:10-11:12:13:14-15:16:17:18-00:00:03:c2",
      "discovered_writers": 3,
      "discovered_readers": 5
    }
  ],
  "routes": [
    {
      "source": "Domain 0 / Circle",
      "target": "Domain 1 / Circle",
      "messages_forwarded": 1250,
      "bytes_forwarded": 58750,
      "last_message_time": "2026-05-17T14:30:44Z",
      "active": true
    }
  ],
  "total_messages_forwarded": 2500,
  "errors": []
}

Example Configurations

Basic Bridge (Two Domains)

status_file: "/tmp/router-status.json"
status_interval_ms: 500

domains:
  - domain_id: 0
    participant_id: 1
  - domain_id: 1
    participant_id: 2

routes:
  - source_domain: 0
    source_topic: "Sensor"
    target_domain: 1
    target_topic: "Sensor"
    type_name: "SensorSystem::SensorReading"
    reliability: RELIABLE
    durability: TRANSIENT_LOCAL

Multi-Domain Hub

domains:
  - domain_id: 0
    participant_id: 10
  - domain_id: 1
    participant_id: 11
  - domain_id: 2
    participant_id: 12

routes:
  # Domain 0 ↔ Domain 1
  - source_domain: 0
    source_topic: "Telemetry"
    target_domain: 1
    target_topic: "Telemetry"
    type_name: "System::Telemetry"

  # Domain 1 ↔ Domain 2
  - source_domain: 1
    source_topic: "Commands"
    target_domain: 2
    target_topic: "Commands"
    type_name: "System::Command"

  # Domain 2 → Domain 0 (Status)
  - source_domain: 2
    source_topic: "Status"
    target_domain: 0
    target_topic: "Status"
    type_name: "System::Status"

Shapes Demo Bridge

Enable Shapes Demo to interoperate across domains:

domains:
  - domain_id: 0
    participant_id: 1
  - domain_id: 1
    participant_id: 2

routes:
  - source_domain: 0
    source_topic: "Circle"
    target_domain: 1
    target_topic: "Circle"
    type_name: "ShapesDemo::ShapeType"
    reliability: BEST_EFFORT
    durability: VOLATILE

  - source_domain: 0
    source_topic: "Square"
    target_domain: 1
    target_topic: "Square"
    type_name: "ShapesDemo::ShapeType"
    reliability: BEST_EFFORT
    durability: VOLATILE

  - source_domain: 0
    source_topic: "Triangle"
    target_domain: 1
    target_topic: "Triangle"
    type_name: "ShapesDemo::ShapeType"
    reliability: BEST_EFFORT
    durability: VOLATILE

Type Compatibility Checking

The router validates type assignability before routing to prevent incompatible data:

routes:
  - source_domain: 0
    source_topic: "Data"
    target_domain: 1
    target_topic: "Data"
    type_name: "MyModule::MyType"  # Type name for validation
    reliability: RELIABLE

Type checking supports: - Primitive types (int, float, string, etc.) - Struct evolution (IDL @optional fields) - Type inheritance - Sequence and union types

QoS Mapping

Router automatically maps QoS policies:

Writer Policy Route Config Reader Policy Result
RELIABLE RELIABLE RELIABLE ✅ Compatible
BEST_EFFORT RELIABLE RELIABLE ⚠️ May miss samples
RELIABLE BEST_EFFORT BEST_EFFORT ✅ Compatible
PERSISTENT TRANSIENT_LOCAL TRANSIENT_LOCAL ✅ Compatible

Configure mapping in route:

routes:
  - source_domain: 0
    source_topic: "Commands"
    target_domain: 1
    target_topic: "Commands"
    type_name: "System::Command"
    reliability: RELIABLE          # Map to RELIABLE
    durability: TRANSIENT_LOCAL    # Map to TRANSIENT_LOCAL

Security-Gated Routes

Require DDS Security for sensitive routes:

# Enable security globally
security_enabled: true

routes:
  - source_domain: 0
    source_topic: "SecureData"
    target_domain: 1
    target_topic: "SecureData"
    type_name: "Security::SecureType"
    reliability: RELIABLE
    require_security: true  # This route requires authentication/encryption

Payload Filtering and Transformation

The router supports optional filtering/transformation hooks for custom processing:

routes:
  - source_domain: 0
    source_topic: "RawSensor"
    target_domain: 1
    target_topic: "ProcessedSensor"
    type_name: "Sensor::RawReading"
    filter_expression: "temperature > 20.0"  # Future: content filtering
    transform: "scale_temperature"           # Future: transformation hook

Currently filters are informational; transformation API coming in M6.

Troubleshooting

Router fails to start

  • Check YAML syntax: yamllint router_config.yaml
  • Verify domain IDs are valid (0-232)
  • Ensure participant IDs don't conflict

Routes not forwarding messages

  • Confirm both source and target topics exist with compatible types
  • Check astutedds-inspect to verify discovery
  • Review router status JSON for errors

Type mismatch errors

[ERROR] Route Circle: Type incompatibility detected
  • Verify type names are spelled correctly
  • Ensure IDL definitions are compatible
  • Check assignability rules in X-Types spec

High message latency

  • Lower status_interval_ms to reduce writer overhead
  • Use BEST_EFFORT reliability for real-time data
  • Consider using separate router instances per domain pair

Integration with monitoring

systemd Service

[Unit]
Description=AstuteDDS Router
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/astutedds-router /etc/astutedds/router.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Docker

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y astutedds-router
COPY router.yaml /etc/astutedds/
CMD ["astutedds-router", "/etc/astutedds/router.yaml"]

Prometheus Metrics

The router writes JSON status that can be parsed by monitoring tools:

# Extract metrics
curl http://localhost:8080/metrics  # Future: built-in Prometheus endpoint

Performance Tuning

  • Minimize routes: Each route consumes resources
  • Batch writes: Use coherent changes when possible
  • Increase history: Balance memory vs. durability
  • Tune status interval: Don't write status too frequently

Complete Example Walkthrough

Step 1: Create Configuration

cat > router.yaml << 'EOF'
status_file: "/tmp/router-status.json"
status_interval_ms: 1000

domains:
  - domain_id: 0
    participant_id: 1
  - domain_id: 1
    participant_id: 2

routes:
  - source_domain: 0
    source_topic: "Circle"
    target_domain: 1
    target_topic: "Circle"
    type_name: "ShapesDemo::ShapeType"
    reliability: BEST_EFFORT
    durability: VOLATILE
EOF

Step 2: Start Router

cd build
./bin/astutedds-router ../router.yaml &

Step 3: Start Shapes Demo on Domain 0

# Terminal 1
./bin/shapes_demo --domain 0
# Click "Publish" → select "Circle" → color "BLUE"

Step 4: Start Shapes Demo on Domain 1

# Terminal 2
./bin/shapes_demo --domain 1
# Click "Subscribe"
# You should see the BLUE circle from Domain 0 moving on the canvas

Step 5: Monitor Router

# Terminal 3
watch -n 1 "cat /tmp/router-status.json | jq .routes"

You should see messages being forwarded.

API Reference

  • Router configuration: tools/router/router_config.yaml
  • Router implementation: tools/router/router.hpp / router.cpp
  • Config loader: tools/router/config_loader.hpp
  • YAML parser: tools/router/yaml_minimal.hpp (portable, no external deps)

Further Reading