Ro/Gy Interface¶
The Ro and Gy interfaces are Diameter-based protocols used for online charging in telecommunications networks. While technically distinct, they serve similar purposes and are often discussed together due to their common functionality in real-time charging scenarios.
Overview¶
- Ro Interface: Used for online charging between the Online Charging System (OCS) and network elements
- Gy Interface: The 3GPP standardized version of Ro, specifically for packet-switched domain charging
Protocol Details¶
Message Types¶
- Credit-Control-Request (CCR)
- Initial-Request (CCR-I)
- Update-Request (CCR-U)
-
Termination-Request (CCR-T)
-
Credit-Control-Answer (CCA)
- Initial-Answer (CCA-I)
- Update-Answer (CCA-U)
- Termination-Answer (CCA-T)
Common AVPs¶
COMMON_AVPS = {
'Session-Id': 263,
'Origin-Host': 264,
'Origin-Realm': 296,
'Destination-Realm': 283,
'Auth-Application-Id': 258,
'Service-Context-Id': 461,
'CC-Request-Type': 416,
'CC-Request-Number': 415,
'Requested-Action': 436,
'Subscription-Id': 443
}
Implementation Examples¶
Initialize Ro/Gy Client¶
from diameter.client import DiameterClient
from diameter.avp import AVP
class RoGyClient(DiameterClient):
def __init__(self, host, port, realm):
super().__init__(host, port)
self.realm = realm
self.application_id = 4 # Diameter Credit Control Application
async def send_initial_request(self, session_id, subscription_id):
request = self.create_ccr(
session_id=session_id,
request_type='INITIAL_REQUEST',
subscription_id=subscription_id
)
return await self.send_request(request)
def create_ccr(self, session_id, request_type, subscription_id):
avps = [
AVP('Session-Id', session_id),
AVP('Origin-Host', self.host),
AVP('Origin-Realm', self.realm),
AVP('Destination-Realm', 'charging.example.com'),
AVP('Auth-Application-Id', self.application_id),
AVP('Service-Context-Id', '[email protected]'),
AVP('CC-Request-Type', request_type),
AVP('CC-Request-Number', self.get_request_number()),
AVP('Subscription-Id', subscription_id)
]
return self.create_request('Credit-Control-Request', avps)
Handle Credit Control Session¶
async def handle_voice_call_session(client, subscription_id):
try:
# Start session
session_id = f"voice.{uuid.uuid4()}"
initial_response = await client.send_initial_request(
session_id=session_id,
subscription_id=subscription_id
)
if initial_response.result_code == 2001: # DIAMETER_SUCCESS
granted_units = initial_response.get_avp('Granted-Service-Unit')
# Monitor usage
while usage < granted_units:
# Update request when threshold reached
update_response = await client.send_update_request(
session_id=session_id,
used_units=usage
)
if update_response.result_code != 2001:
raise ChargingError("Credit authorization failed")
# Terminate session
await client.send_termination_request(
session_id=session_id,
used_units=total_usage
)
except Exception as e:
logger.error(f"Charging session error: {str(e)}")
raise
Vendor Integration¶
Nokia OCS Integration¶
nokia_ocs:
host: ocs.nokia.example.com
port: 3868
realm: nokia.charging.example.com
watchdog_interval: 30
connection_timeout: 5
retry_count: 3
tls:
enabled: true
cert_file: /etc/diameter/certs/client.pem
key_file: /etc/diameter/certs/client.key
ca_file: /etc/diameter/certs/ca.pem
Ericsson OCS Integration¶
ericsson_ocs:
host: ocs.ericsson.example.com
port: 3868
realm: ericsson.charging.example.com
vendor_id: 193
product_name: "Ericsson Charging System"
features:
- concurrent_sessions
- quota_management
- tariff_switching
Error Handling¶
Common Error Codes¶
Result Code | Name | Description | Resolution |
---|---|---|---|
4010 | DIAMETER_END_USER_SERVICE_DENIED | User has insufficient credit | Notify user to recharge |
4012 | DIAMETER_CREDIT_LIMIT_REACHED | Credit limit exceeded | Implement graceful service termination |
5030 | DIAMETER_USER_UNKNOWN | Unknown subscriber | Verify subscription details |
5031 | DIAMETER_RATING_FAILED | Rating engine error | Retry with exponential backoff |
Error Handling Example¶
class ChargingError(Exception):
def __init__(self, message, result_code=None):
super().__init__(message)
self.result_code = result_code
async def handle_charging_error(error, session_id):
if isinstance(error, ChargingError):
if error.result_code == 4010:
await notify_user_service_denied(session_id)
elif error.result_code == 4012:
await graceful_termination(session_id)
else:
await default_error_handling(session_id, error)
logger.error(f"Charging error in session {session_id}: {str(error)}")
metrics.increment('charging_errors', tags={'type': error.__class__.__name__})
Monitoring¶
Key Metrics¶
- Session Metrics
- Active sessions count
- Session establishment rate
- Session duration distribution
-
Session termination reasons
-
Performance Metrics
- Request latency
- Request/Response rates
- Error rates by type
- Quota consumption rate
Prometheus Metrics Example¶
from prometheus_client import Counter, Histogram, Gauge
CHARGING_METRICS = {
'requests_total': Counter(
'diameter_charging_requests_total',
'Total number of charging requests',
['request_type', 'result']
),
'request_duration': Histogram(
'diameter_charging_request_duration_seconds',
'Charging request duration',
['request_type']
),
'active_sessions': Gauge(
'diameter_charging_active_sessions',
'Number of active charging sessions'
)
}
async def track_charging_metrics(request_type, start_time, result):
duration = time.time() - start_time
CHARGING_METRICS['request_duration'].labels(request_type).observe(duration)
CHARGING_METRICS['requests_total'].labels(request_type, result).inc()
Configuration Examples¶
Basic Configuration¶
ro_gy:
enabled: true
host: charging.example.com
port: 3868
realm: charging.example.com
application_id: 4
vendor_id: 10415
product_name: "Example Charging Client"
connection:
retry_count: 3
timeout: 5
keepalive: 30
Advanced Configuration¶
ro_gy:
enabled: true
host: charging.example.com
port: 3868
realm: charging.example.com
application_id: 4
vendor_id: 10415
product_name: "Example Charging Client"
connection:
retry_count: 3
timeout: 5
keepalive: 30
max_pending_requests: 10000
security:
tls_enabled: true
cert_file: /etc/diameter/certs/client.pem
key_file: /etc/diameter/certs/client.key
ca_file: /etc/diameter/certs/ca.pem
session:
idle_timeout: 1800
max_duration: 86400
quota_threshold: 0.8
failover:
enabled: true
alternate_hosts:
- host: charging2.example.com
port: 3868
- host: charging3.example.com
port: 3868
monitoring:
metrics_enabled: true
prometheus_port: 9090
log_level: INFO
Best Practices¶
- Session Management
- Implement proper session cleanup
- Handle session state transitions atomically
-
Store session data in persistent storage
-
Error Handling
- Implement exponential backoff for retries
- Handle network timeouts gracefully
-
Maintain fallback charging mechanisms
-
Performance
- Use connection pooling
- Implement request throttling
-
Cache frequently used AVPs
-
Security
- Always use TLS for production
- Implement proper certificate management
-
Regular security audits
-
Monitoring
- Monitor session states
- Track quota consumption
- Set up alerts for error thresholds