Pular para o conteúdo principal

Guia de Operações do OmniCHF

Índice

  1. Visão Geral do Componente
  2. Referências de Papel e Especificação 3GPP
  3. Endpoints SBI
  4. Referência de Configuração
  5. Procedimentos Chave
  6. Observabilidade
  7. Limitações Conhecidas
  8. Solução de Problemas

Visão Geral do Componente

OmniCHF implementa a função de rede de Função de Cobrança (CHF) definida na 3GPP TS 32.291. O CHF fornece cobrança online e offline convergente para sessões PDU 5G via o serviço Nchf_ConvergedCharging. Ele traduz solicitações de cobrança 5G em chamadas JSON-RPC SessionS CGRateS para autorização de crédito e gerenciamento de sessão, e gera Registros de Detalhes de Chamadas (CDRs) na liberação da sessão.

Ciclo de Vida da Sessão de Cobrança

Cada sessão PDU mapeia para uma sessão de cobrança, rastreada por um chargingDataRef (UUID). O estado da sessão é mantido em um Agente em memória e não é persistido. Um reinício perde todo o estado da sessão ativa.

EstadoGatilhoAção de armazenamento
CriadoPOST /chargingdataContexto criado, CGRateS InitiateSession chamado
AtualizadoPOST /chargingdata/:ref/updateContexto atualizado (uso acumulado, sequência incrementada)
LiberadoPOST /chargingdata/:ref/releaseCDR construído e registrado, CGRateS TerminateSession chamado, contexto excluído

Referências de Papel e Especificação 3GPP

ItemReferência
Definição de NF CHF3GPP TS 23.501 Seção 6.2.16
Serviço Nchf_ConvergedCharging3GPP TS 32.291
Procedimento de Criação de Dados de Cobrança3GPP TS 32.291 Seção 6.1.3.2.1
Procedimento de Atualização de Dados de Cobrança3GPP TS 32.291 Seção 6.1.3.2.2
Procedimento de Liberação de Dados de Cobrança3GPP TS 32.291 Seção 6.1.3.2.3
Modelo de dados ChargingDataRequest / Response3GPP TS 32.291 Seção 6.1.6
Formato CDR para sessões PDU 5G3GPP TS 32.290
Estrutura comum do SBI3GPP TS 29.500
Registro de NF com NRF3GPP TS 29.510

Endpoints SBI

Caminho base: /nchf-convergedcharging/v3

MétodoCaminhoDescriçãoSucessoErro
POST/chargingdataCriar uma sessão de cobrança (Solicitação inicial). Aloca um chargingDataRef, inicia uma sessão CGRateS e retorna unidades concedidas.201 Criado com cabeçalho Location500 Erro Interno do Servidor
POST/chargingdata/{chargingDataRef}/updateAtualizar uma sessão de cobrança (Solicitação intermediária). Relata o uso atual e solicita crédito adicional.200 OK404 Não Encontrado, 500 Erro Interno do Servidor
POST/chargingdata/{chargingDataRef}/releaseLiberar uma sessão de cobrança (Solicitação final). Relata o uso final, gera CDR, termina a sessão CGRateS.204 Sem Conteúdo404 Não Encontrado, 500 Erro Interno do Servidor

ChargingDataRequest — Campos Chave

CampoTipoUsado emDescrição
subscriberIdentifierstringCriar, Atualizar, LiberarSUPI (por exemplo, imsi-999700000000001). Usado como identificador de conta CGRateS.
nfConsumerIdentificationobjetoCriarInformações do consumidor NF. Fonte de fallback para SUPI se subscriberIdentifier estiver ausente.
pDUSessionChargingInformationobjetoCriar, Atualizar, LiberarDetalhes da sessão PDU: DNN, S-NSSAI, tipo RAT, QoS, ID e tipo da sessão PDU.
multipleUnitUsagearrayAtualizar, LiberarContêineres de uso relatados. O usedUnitContainer do primeiro elemento é usado para extração de volume e duração.
requestTypestringTodosINITIAL_REQUEST, UPDATE_REQUEST ou TERMINATION_REQUEST.

ChargingDataResponse — Campos Chave

CampoTipoPresenteDescrição
invocationSequenceNumberintegerCriar, AtualizarNúmero de sequência para esta resposta. Codificado como 1 na Criação (veja CHF-M1). Incrementado em cada Atualização.
invocationResultobjetoCriar, AtualizarSempre {"resultCode": "SUCCESS"} no caminho feliz.
sessionIdstringCriar, AtualizarO chargingDataRef (UUID) alocado para esta sessão.
multipleUnitInformationarrayCriar, AtualizarUnidades concedidas. Contém uma entrada com resultCode, grantedUnit (totalVolume, time) e ratingGroup (codificado como 1, veja CHF-L2).

Referência de Configuração

Todos os parâmetros são definidos via o ambiente da aplicação (tipicamente config/runtime.exs).

config :omnichf,
sbi_scheme: "http",
sbi_addr: "127.0.0.14",
sbi_port: 7777,
nrf_uri: "http://127.0.0.10:7777",
mcc: "999",
mnc: "70",
heartbeat_interval: 10_000,
cgrates_enabled: false,
cgrates_url: "http://localhost:2080/jsonrpc",
cgrates_tenant: "cgrates.org",
cgrates_timeout: 5000

Tabela de Parâmetros

ParâmetroPadrãoTipoDescrição
sbi_scheme"http"stringEsquema de transporte para o ouvinte SBI.
sbi_addr"127.0.0.14"stringEndereço IP ao qual o servidor HTTP SBI se vincula.
sbi_port7777integerPorta TCP na qual o servidor HTTP SBI escuta.
nrf_uri"http://127.0.0.10:7777"stringURI base do NRF usado para registro de NF e heartbeat.
mcc"999"stringCódigo do País Móvel. Usado no perfil NF enviado ao NRF e no nome da rede de serviço.
mnc"70"stringCódigo da Rede Móvel. Usado no perfil NF enviado ao NRF e no nome da rede de serviço.
heartbeat_interval10_000integer (ms)Intervalo entre solicitações de heartbeat do NRF.
cgrates_enabledfalsebooleanInterruptor mestre para integração CGRateS. Quando false, todas as chamadas CGRateS são ignoradas e uma concessão padrão de 86.400 unidades é retornada. Defina como true em produção quando uma instância CGRateS estiver disponível.
cgrates_url"http://localhost:2080/jsonrpc"stringURL do endpoint JSON-RPC para a instância CGRateS. Usado apenas quando cgrates_enabled é true.
cgrates_tenant"cgrates.org"stringNome do inquilino CGRateS. Passado em todas as chamadas da API SessionS como o campo Tenant. Deve corresponder ao inquilino configurado no CGRateS.
cgrates_timeout5000integer (ms)Tempo limite da solicitação HTTP para chamadas JSON-RPC do CGRateS. Chamadas de verificação de saúde usam min(cgrates_timeout, 3000) para evitar bloquear o endpoint de saúde.

Notas de Integração do CGRateS

Quando cgrates_enabled é false, o OmniCHF opera em modo de bypass: todas as solicitações de cobrança são aceitas e concedidas 86.400 unidades (tempo ou volume) sem qualquer classificação ou autorização. Isso é adequado para testes em laboratório e integração quando o CGRateS não está disponível.

A comunicação com o CGRateS utiliza o cliente HTTP embutido :httpc do Erlang (veja a limitação CHF-M5). Este cliente não suporta pooling de conexão. Sob alta carga, cada solicitação CGRateS abre e fecha uma nova conexão HTTP, o que pode se tornar um gargalo.


Procedimentos Chave

Criar Sessão de Cobrança (Inicial)

Atualizar Sessão de Cobrança (Intermediária)

Liberar Sessão de Cobrança (Final)

Mapeamento de Eventos do CGRateS

OmniCHF mapeia campos de cobrança 5G para campos de eventos SessionS do CGRateS da seguinte forma:

Campo CGRateSFonteNotas
AccountsubscriberIdentifier (SUPI)Reverte para nfConsumerIdentification.supi
SubjectsubscriberIdentifier (SUPI)O mesmo que Account
DestinationpduSessionInformation.dnnId ou .dnnNome da Rede de Dados
ToRpduSessionInformation.pduTypeSempre *data para sessões PDU
RequestTyperequestTypeSempre mapeado para *prepaid
UsageusedUnitContainer.totalVolume ou soma de uplink+downlink ou timeO primeiro valor não zero vence
OriginIDchargingDataRefUUID único por sessão
OriginHostestático "OmniCHF"
SUPIsubscriberIdentifierCampo de extensão 5G
DNNpduSessionInformation.dnnIdCampo de extensão 5G
S-NSSAI_SSTpduSessionInformation.sNSSAI.sstCampo de extensão 5G
S-NSSAI_SDpduSessionInformation.sNSSAI.sdCampo de extensão 5G
5QIpduSessionInformation.qoSInformation.5qICampo de extensão 5G
RATTypepduSessionInformation.ratTypePadrão: "NR"
PDUSessionIDpduSessionInformation.pduSessionIDCampo de extensão 5G
PDUSessionTypepduSessionInformation.pduTypePadrão: "IPV4"

Campos CDR

Os CDRs são construídos na liberação da sessão e emitidos para o log da aplicação no nível INFO. O mapa CDR contém:

CampoFonte
record_typeEstático: "5G_PDU_SESSION"
supiContexto de cobrança
dnnpduSessionInformation.dnnId ou .dnn
snssai{sst, sd} de pduSessionInformation.sNSSAI
qos_5qipduSessionInformation.qoSInformation.5qI
rat_typepduSessionInformation.ratType
pdu_session_idContexto de cobrança
pdu_session_typepduSessionInformation.pduType
volume_uplinkusedUnitContainer.uplinkVolume
volume_downlinkusedUnitContainer.downlinkVolume
volume_totalusedUnitContainer.totalVolume (ou uplink+downlink)
durationusedUnitContainer.time (ou diferença de relógio se zero)
start_timeTimestamp created_at da sessão
end_timeRelógio de parede no momento da liberação
charging_data_refUUID da sessão

Observabilidade

Eventos de Telemetria

EventoMedidasTagsDescrição
[:omnichf, :charging, :initial]countsupiDisparado em cada solicitação de Criação
[:omnichf, :charging, :update]countrefDisparado em cada solicitação de Atualização
[:omnichf, :charging, :release]countrefDisparado em cada solicitação de Liberação
[:omnichf, :charging, :creates]countresult (success/failure)Resultado da operação de Criação
[:omnichf, :charging, :updates]countresultResultado da operação de Atualização
[:omnichf, :charging, :releases]countresultResultado da operação de Liberação
[:omnichf, :cgrates, :request]count, duration_msoperation, resultPor chamada JSON-RPC do CGRateS
[:omnichf, :cgrates, :health]status (1/0)Saúde da conectividade do CGRateS
[:omnichf, :sessions, :active]countMedida: sessões de cobrança ativas
[:omni5g, :nrf, :registration]status (1/0)nf_typeStatus de registro do NRF

Métricas do Prometheus

Métricas de Cobrança

MétricaTipoTagsDescrição
omni_chf.charging.initial.countcontadorsupiCriações de sessão de cobrança
omni_chf.charging.update.countcontadorrefAtualizações de sessão de cobrança
omni_chf.charging.release.countcontadorrefLiberações de sessão de cobrança
omni_chf.charging.creates.totalcontadorresultTotal de criações de sessão de cobrança
omni_chf.charging.updates.totalcontadorresultTotal de atualizações de sessão de cobrança
omni_chf.charging.releases.totalcontadorresultTotal de liberações de sessão de cobrança
omni_chf.sessions.active.countmedidor--Número de sessões de cobrança ativas

Métricas do CGRateS

MétricaTipoTagsDescrição
omni_chf.cgrates.calls.countcontadormethod, resultChamadas JSON-RPC do CGRateS
omni_chf.cgrates.latency.millisecondsmedidor--Latência da chamada CGRateS
omni_chf.cgrates.healthmedidor--Saúde da conectividade do CGRateS (1=ativo, 0=inativo)
omni_chf.cgrates.requests.totalcontadoroperation, resultTotal de solicitações JSON-RPC do CGRateS
omni_chf.cgrates.request.duration_msdistribuiçãooperationDuração da solicitação CGRateS em ms (baldes: 5, 10, 25, 50, 100, 250, 500, 1000, 2500)

Métricas do NRF

MétricaTipoTagsDescrição
omni_chf.nrf.registration.statusmedidornf_typeStatus de registro do NRF (1=registrado, 0=não registrado)

Métricas da VM BEAM

MétricaTipoDescrição
beam.memory.totalmedidorTotal de memória BEAM em bytes
beam.memory.processesmedidorMemória usada por processos Erlang
beam.memory.processes_usedmedidorMemória realmente usada por processos
beam.memory.systemmedidorMemória do sistema
beam.memory.atommedidorTotal de memória de átomos
beam.memory.atom_usedmedidorMemória de átomos usada
beam.memory.binarymedidorMemória binária
beam.memory.codemedidorMemória de código
beam.memory.etsmedidorMemória da tabela ETS
beam.processes.countmedidorNúmero de processos Erlang
beam.ports.countmedidorNúmero de portas Erlang
beam.atom.countmedidorNúmero de átomos
beam.vm.uptimemedidorTempo de atividade da VM em segundos

Padrões de Log

NívelPadrãoSignificado
infoCHF Create: ref=<UUID> supi=<SUPI> pdu_session=<N>Criação bem-sucedida iniciada
infoCHF Update: ref=<UUID>Solicitação de atualização recebida
infoCHF Release: ref=<UUID>Solicitação de liberação recebida
infoCHF CDR: %{...}CDR emitido na liberação
infoInitiating CGRateS session for <ref>, account: &lt;SUPI>CGRateS InitiateSession enviado
infoCGRateS authorized &lt;N> units for session <ref>Crédito concedido
infoCGRateS session <ref> terminated successfullyCGRateS TerminateSession OK
warningCGRateS integration disabled, returning default authorizationModo de bypass ativo
warningCHF Update: unknown ref=&lt;UUID>Atualização para sessão inexistente
warningCHF Release: unknown ref=&lt;UUID>Liberação para sessão inexistente
errorCHF Create failed: <reason>Falha na operação de criação
errorCHF Update failed: <reason>Falha na operação de atualização
errorCGRateS InitiateSession failed for <ref>: <reason>Erro do CGRateS na criação
errorCGRateS HTTP error <status>: <body>Não-200 do CGRateS
errorCGRateS HTTP request failed: <reason>Erro de rede para o CGRateS

Limitações Conhecidas

IDSeveridadeDescrição
CHF-M1MédioinvocationSequenceNumber é codificado como 1 na resposta de Criação (Inicial). De acordo com a TS 32.291, o número de sequência deve começar em 1 e ser incrementado nas respostas subsequentes, o que acontece na Atualização. O problema é que, se um consumidor enviar uma Criação com um invocationSequenceNumber na solicitação, esse valor não é inspecionado ou validado.
CHF-M3MédioinvocationTimeStamp está ausente do ChargingDataResponse. De acordo com a TS 32.291, este campo é obrigatório no corpo da resposta. Consumidores rigorosos que exigem este campo receberão uma resposta incompleta.
CHF-M5MédioO cliente CGRateS usa o cliente HTTP :httpc do Erlang em vez do Finch. :httpc não suporta pooling de conexão; cada chamada JSON-RPC abre e fecha uma conexão TCP. Sob carga (muitas sessões de cobrança simultâneas), a latência da chamada CGRateS aumentará e a sobrecarga de configuração da conexão se tornará significativa. Monitore omni_chf.cgrates.request.duration_ms.
CHF-L1BaixoNenhum campo triggers é incluído no ChargingDataResponse. De acordo com a TS 32.291, os gatilhos podem instruir o SMF a enviar uma atualização intermediária em eventos específicos (limite de volume, limite de tempo, mudança de QoS). Sem gatilhos, o SMF usa sua própria política local para determinar quando enviar atualizações.
CHF-L2BaixoratingGroup em multipleUnitInformation é codificado como 1. Implementações reais normalmente têm vários grupos de classificação por sessão PDU (um por fluxo de dados de serviço). Todo uso é atribuído ao grupo de classificação 1, independentemente dos valores de ratingGroup nos multipleUnitUsage da solicitação.
CHF-L3BaixoNenhum chargingId no formato 3GPP é gerado. De acordo com a TS 32.290, os registros de cobrança devem carregar um chargingId que correlacione com o ID da sessão PDU atribuído pelo SMF. O UUID charging_data_ref é usado em vez disso, o que pode causar problemas de correlação em sistemas de faturamento downstream que esperam o formato chargingId 3GPP.
CHF-L4BaixoO registro CDR está faltando os campos chargingID e recordingEntity exigidos pela TS 32.290. Sistemas de mediação ou faturamento downstream que esperam esses campos precisarão tolerar sua ausência ou ser configurados para tratá-los como opcionais.
CHF-L5BaixoA cobrança offline e a saída de arquivo CDR não estão implementadas. Os CDRs são emitidos apenas para o log da aplicação via Logger.info. Não há saída de CDR baseada em arquivo, nenhuma codificação ASN.1 e nenhuma transferência para um gateway de domínio de faturamento. Para cobrança offline em produção, um coletor de logs (por exemplo, Fluentd, Vector) deve coletar as linhas de log CDR do CHF e transformá-las para o sistema de faturamento.

Solução de Problemas

404 na Atualização ou Liberação

O chargingDataRef não corresponde a nenhuma sessão ativa em memória. Causas:

  1. OmniCHF reiniciado entre Criação e Atualização/Liberar — todo o estado da sessão está em memória e é perdido no reinício.
  2. O SMF enviou o chargingDataRef errado no caminho.
  3. Uma Liberação foi enviada anteriormente para esta sessão, o que excluiu o contexto.

Verifique os logs para CHF Update: unknown ref= ou CHF Release: unknown ref= para confirmar.

500 na Criação com CGRateS habilitado

A chamada CGRateS falhou. Verifique:

  1. O cgrates_url está apontando para uma instância CGRateS acessível?
  2. O cgrates_tenant está correto? Nomes de inquilinos incompatíveis fazem com que o CGRateS retorne uma resposta de erro.
  3. Verifique a métrica omni_chf.cgrates.health (1=ativo, 0=inativo).
  4. Revise os logs para CGRateS InitiateSession failed for <ref>: <reason> — a razão será uma das: {:cgrates_error, message}, {:http_error, status}, ou {:http_error, reason}.
  5. Verifique se o serviço SessionSv1 do CGRateS está habilitado na configuração do CGRateS.

Verificação de saúde do CGRateS falhando, mas o daemon está em execução

A verificação de saúde (via SessionSv1.GetActiveSessions) usa um tempo limite de 3 segundos. Se o CGRateS estiver lento para responder, a verificação de saúde pode falhar enquanto o serviço está tecnicamente disponível. Verifique cgrates_timeout — o limite é min(cgrates_timeout, 3000). Também confirme se o cgrates_url usa HTTP (não HTTPS) a menos que TLS esteja configurado.

CDRs não aparecendo ou incompletos

Os CDRs são escritos no log da aplicação no nível INFO (veja a limitação CHF-L5). Para capturar CDRs:

  1. Certifique-se de que o nível de log da aplicação esteja definido como info ou inferior.
  2. Filtre as linhas de log contendo "CHF CDR:" para processamento posterior.
  3. Observe que os CDRs estão faltando chargingID, recordingEntity (CHF-L4), e terão ratingGroup: 1 para todos os fluxos de dados de serviço (CHF-L2).

Alta latência de chamadas do CGRateS

Como o CGRateS usa :httpc sem pooling de conexão (CHF-M5), a latência aumenta sob carga. Para diagnosticar:

  1. Verifique o histograma omni_chf.cgrates.request.duration_ms para latência p99.
  2. Se a latência for alta sob carga concorrente, reduza o número de sessões de cobrança concorrentes ou considere implantar o OmniCHF atrás de um balanceador de carga com várias instâncias.
  3. Como uma solução alternativa, defina cgrates_timeout para um valor inferior ao tempo de resposta esperado do CGRateS para evitar que chamadas lentas do CGRateS bloqueiem o pool de processos Elixir.

Contagem de sessões ativas não diminuindo após liberações

Se omni_chf.sessions.active.count permanecer elevado após as sessões terem sido liberadas:

  1. Verifique as respostas 404 nas chamadas de Liberação — se o SMF receber 404, pode não tentar novamente e o SMF considera a sessão liberada enquanto o OmniCHF pode ainda ter o contexto.
  2. No caso inverso, se o OmniCHF reiniciou e perdeu o estado da sessão, os contextos se foram, mas o SMF pode ainda enviar solicitações de Atualização/Liberar que resultam em 404. Este é o comportamento esperado.

Registro do NRF não mantido

Verifique a métrica omni_chf.nrf.registration.status. Se estiver em 0:

  1. Verifique se o nrf_uri está correto e se o NRF é acessível a partir do sbi_addr do OmniCHF.
  2. Verifique se mcc e mnc correspondem à configuração PLMN do NRF.
  3. Revise os logs da aplicação na inicialização para erros de registro do NRF.