Skip to content

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

  1. Credit-Control-Request (CCR)
  2. Initial-Request (CCR-I)
  3. Update-Request (CCR-U)
  4. Termination-Request (CCR-T)

  5. Credit-Control-Answer (CCA)

  6. Initial-Answer (CCA-I)
  7. Update-Answer (CCA-U)
  8. 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

  1. Session Metrics
  2. Active sessions count
  3. Session establishment rate
  4. Session duration distribution
  5. Session termination reasons

  6. Performance Metrics

  7. Request latency
  8. Request/Response rates
  9. Error rates by type
  10. 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

  1. Session Management
  2. Implement proper session cleanup
  3. Handle session state transitions atomically
  4. Store session data in persistent storage

  5. Error Handling

  6. Implement exponential backoff for retries
  7. Handle network timeouts gracefully
  8. Maintain fallback charging mechanisms

  9. Performance

  10. Use connection pooling
  11. Implement request throttling
  12. Cache frequently used AVPs

  13. Security

  14. Always use TLS for production
  15. Implement proper certificate management
  16. Regular security audits

  17. Monitoring

  18. Monitor session states
  19. Track quota consumption
  20. Set up alerts for error thresholds