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
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-inspectto 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_msto 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
- DDS Concepts — Understanding DDS domains
- QoS Usage — Configure Quality of Service
- X-Types — Type assignability rules
- Shapes Demo — Test router with interactive demo