Carrier & Trunk Management

1. SIP Trunk Configuration

Wholesale trunks have two layers:

LayerConfiguration LocationDescription
SIP Trunkconfig/trunks/*.toml or consoleSignaling, codecs, max concurrency
Wholesale Trunk ConfigDatabase wholesale_trunk_configsRate 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:

SettingDescriptionDefault
Buy Rate DeckCost rate for this trunkNone
Circuit Breaker EnabledWhether to enable the tri-state circuit breakerfalse
Ringback Tone Modeearly_media / local_ring / noneearly_media
Number RewritingNumber transformation before sending to this trunkNone
Tech PrefixPrefix automatically prepended before dialingNone

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)─────────────┘
ParameterDescriptionDefault
failure_thresholdConsecutive failures to trigger circuit open5
open_duration_secsDuration the circuit stays open30
half_open_probesNumber of probes in half-open state1
failure_codesSIP 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:

AlgorithmDescription
Weighted Round-RobinDistributed by weight field (default)
LCRWhen tenant lcr_enabled is on, trunks at the same priority are sorted by buy price ascending

Configuration example — dual trunk at the same priority:

PriorityTrunkWeightDescription
10carrier-a80Primary
10carrier-b20Backup (20% traffic)
20carrier-c100Full backup