Carrier & Trunk Management
1. SIP Trunk Configuration
Wholesale trunks have two layers:
| Layer | Configuration Location | Description |
|---|---|---|
| SIP Trunk | config/trunks/*.toml or console | Signaling, codecs, max concurrency |
| Wholesale Trunk Config | Database wholesale_trunk_configs | Rate deck binding, circuit breaker, ringback tone |
1.1 Basic SIP Trunk
# config/trunks/carrier_a.toml
[[trunk]]
name = "carrier-a"
dest = "sip:10.0.1.100:5060"
backup_dest = "sip:10.0.1.101:5060" # Backup address
direction = "outbound"
codec = ["pcmu", "pcma", "g729"]
max_calls = 100
max_cps = 20
weight = 100
# Inbound authentication
[trunk.auth]
username = "myaccount"
password = "mypassword"
realm = "carrier-a.com"
# Outbound registration (if required by carrier)
[trunk.registrar]
enabled = true
username = "myaccount"
password = "mypassword"
expires = 3600
1.2 Inbound Trunk (Receiving Calls from Carriers)
[[trunk]]
name = "carrier-a-inbound"
direction = "inbound"
inbound_hosts = ["10.0.1.100", "10.0.1.101"] # Only allow these IPs
codec = ["pcmu", "pcma"]
max_calls = 200
1.3 Bidirectional Trunk
[[trunk]]
name = "carrier-b"
dest = "sip:10.0.2.50:5060"
direction = "bidirectional"
inbound_hosts = ["10.0.2.50"]
codec = ["pcmu", "pcma", "g722", "g729"]
max_calls = 500
2. Wholesale Trunk Configuration
Configure each trunk in the web console under Wholesale → Trunk Management:
| Setting | Description | Default |
|---|---|---|
| Buy Rate Deck | Cost rate for this trunk | None |
| Circuit Breaker Enabled | Whether to enable the tri-state circuit breaker | false |
| Ringback Tone Mode | early_media / local_ring / none | early_media |
| Number Rewriting | Number transformation before sending to this trunk | None |
| Tech Prefix | Prefix automatically prepended before dialing | None |
2.1 Number Rewriting Rules
Each trunk can have outbound number rewriting configured:
{
"caller_strip": 0,
"caller_prepend": "",
"callee_strip": 0,
"callee_prepend": "0",
"callee_regex": ""
}
Rewriting pipeline: Original Number → strip → prepend → regex
3. Trunk Health Checks
3.1 OPTIONS Probing
RustPBX core supports sending SIP OPTIONS to trunk destinations for reachability detection:
[[trunk]]
name = "carrier-a"
dest = "sip:10.0.1.100:5060"
[trunk.health_check]
enabled = true
interval_secs = 30
timeout_secs = 5
max_failures = 3
3.2 Wholesale Circuit Breaker
The Wholesale module provides a more powerful tri-state circuit breaker:
Closed ──(N consecutive failures)──► Open ──(wait cooldown)──► HalfOpen ──(probe succeeds)──► Closed
▲ │
└──────(probe fails)─────────────┘
| Parameter | Description | Default |
|---|---|---|
| failure_threshold | Consecutive failures to trigger circuit open | 5 |
| open_duration_secs | Duration the circuit stays open | 30 |
| half_open_probes | Number of probes in half-open state | 1 |
| failure_codes | SIP status codes considered failures | [503, 408, 504] |
View all trunk circuit breaker states, manually reset, or enable/disable in the console under Wholesale → Monitoring & Throttling.
4. Multi-Trunk Load Balancing
When multiple trunks share the same priority in a routing profile:
| Algorithm | Description |
|---|---|
| Weighted Round-Robin | Distributed by weight field (default) |
| LCR | When tenant lcr_enabled is on, trunks at the same priority are sorted by buy price ascending |
Configuration example — dual trunk at the same priority:
| Priority | Trunk | Weight | Description |
|---|---|---|---|
| 10 | carrier-a | 80 | Primary |
| 10 | carrier-b | 20 | Backup (20% traffic) |
| 20 | carrier-c | 100 | Full backup |