在线计费系统 (OCS) 集成
全面指南,介绍 OmniTAS 如何通过 Diameter Ro 接口与在线计费系统集成,包括实时信用控制、AVP 提取和 FreeSWITCH 变量映射。
目录
架构概述
OmniTAS 根据 3GPP TS 32.299 实现 Diameter Ro 接口以进行实时在线计费。该系统通过在呼叫建立之前向 OCS 请求信用来授权呼叫,在呼叫过程中监控信用,并在终止时报告最终使用情况。
关键组件
信用控制请求 (CCR):
- CCR-Initial (类型 1): 在呼叫建立之前发送以请求初始信用授权
- CCR-Update (类型 2): 在活动呼叫期间发送以进行重新授权或临时更新
- CCR-Terminate (类型 3): 在呼叫终止时发送以报告最终使用情况
信用控制应答 (CCA):
- 包含授予的服务单元(以秒为单位的时间配额)
- 包含供应商特定的 AVPs 以及附加的计费数据
- 提供路由信息、被收费方详细信息和服务标识符
信用控制流程
呼叫授权序列
信用耗尽处理
OmniTAS 支持多种处理信用耗尽的机制,自动集成计划挂断和信用耗尽公告。
动态重新调度的计划挂断
当 schedule_hangup_auth 启用时,OmniTAS 会调度一个 FreeSWITCH 定时器,当授予的信用到期时自动终止呼叫。每次通过 CCR-Update 响应授予新信用时,该定时器会 动态重新调度。
工作原理:
缓冲逻辑:
OmniTAS 在授予的信用到期 之前 发送 CCR-Update 消息,以确保持续服务。缓冲时间可以通过 ccr_update_buffer_seconds 配置(默认:2 秒)。
示例时间线:
- T+0s: 呼叫接听,OCS 授予 10s,定时器计划在 T+10s
- T+8s: 发送 CCR-U(10s - 2s 缓冲)
- T+8.1s: OCS 授予 10s,定时器重新调度到 T+18.1s(从现在起 10s)
- T+16.1s: 发送 CCR-U
- T+16.2s: OCS 授予 10s,定时器重新调度到 T+26.2s
- 呼叫在 OCS 持续授予信用时继续进行
需要关注的日志:
[OCS HANGUP RESCHEDULE] 找到 UUID <uuid> 的呼叫 <id> - 将定时器重新调度到从现在起 10s
[SCHED TRANSFER] 在 10s 内调度转接到 credit_exhausted 拨号计划 <uuid>
[OCS HANGUP RESCHEDULE] 成功重新调度呼叫 <id> 的定时器 (UUID: <uuid>)
集成:schedule_hangup_auth + credit_exhaustion_announcement
当 两个 功能都启用时,OmniTAS 自动使用计划 转接 而不是直接挂断,允许呼叫者在呼叫终止之前听到公告。
未配置公告时:
config :tas, :online_charging,
schedule_hangup_auth: true,
credit_exhaustion_announcement: nil
→ 使用 sched_hangup - 当信用到期时直接挂断
配置公告时:
config :tas, :online_charging,
schedule_hangup_auth: true,
credit_exhaustion_announcement: "${base_dir}/sounds/en/us/callie/misc/8000/credit_exhausted.wav"
→ 使用 sched_transfer - 转接到 credit_exhausted 拨号计划,播放公告后挂断
转接工作原理:
- OmniTAS ���置
tas_call_reason=credit_exhausted通道变量 - 调度转接到
credit_exhausted扩展,在ims_as拨号计划上下文中 - 当定时器触发时:
- FreeSWITCH 将 A-leg 转接到 credit_exhausted 拨号计划
- 桥接自动断开,B-leg 收到 BYE
- 拨号计划向 A-leg 播放公告
- 呼叫在公告后终止
好处:
- 呼叫者听到专业公告,而不是突然断开
- B-leg(被叫方)听不到公告
- CCR-T 仍然发送实际使用情况
- 公告路径:必须相对于 FreeSWITCH 基目录(使用
${base_dir}变量)
CCR-Update 中的即时信用耗尽
如果 OCS 在 CCR-Update 中 拒绝信用 或返回 零秒,OmniTAS 会立即触发信用耗尽处理,覆盖任何计划的定时器。
OCS 响应场景:
处理的错误代码:
| OCS 响应 | 动作 | 日志 |
|---|---|---|
{:ok, 0} (零秒) | 立即信用耗尽挂断 | 信用耗尽(分配零秒) - 触发立即挂断 |
{:error, 4012} (CREDIT_LIMIT_REACHED) | 立即信用耗尽挂断 | 信用耗尽(4012 CREDIT_LIMIT_REACHED) - 触发立即挂断 |
{:error, 4010} (END_USER_SERVICE_DENIED) | 立即信用耗尽挂断 | 服务拒绝(4010 END_USER_SERVICE_DENIED) - 触发立即挂断 |
{:error, reason} (其他错误) | 停止周期性 CCR 作业,计划的定时器触发 | 周期性 CCR 失败,错误 <reason> - 停止作业 |
{:ok, N} 其中 N > 0 | 重新调度定时器到 +N 秒 | 周期性 CCA 分配 Ns,将在 (N-buffer)s 内发送下一个 CCR-U |
优先级: 立即信用耗尽处理 优先 于计划定时器。如果 OCS 在 T+8s 拒绝信用,但定时器计划在 T+10s,则在 T+8s 立即挂断,计划的定时器变得无关紧要。
中途信用拒绝的示例时间线:
T+0s: 呼叫接听
T+0.1s: OCS 授予 10s → 定时器计划在 T+10.1s
T+8s: 发送 CCR-U(缓冲 = 2s)
T+8.1s: OCS 返回 0 秒 → 立即转接到 credit_exhausted 拨号计划
T+8.2s: 向呼叫者播放公告
T+10s: 呼叫终止(计划的定时器无关紧要)
立即信用耗尽的日志:
[warning] 信用耗尽(分配零秒) - 触发立即挂断
[warning] 正在挂断呼叫 <id> (UUID: <uuid>),由于信用耗尽
[info] 信用耗尽公告配置: "${base_dir}/sounds/..."
[info] 在挂断之前播放公告: ...
[info] 为 <uuid> 设置 tas_call_reason=credit_exhausted
[info] 转接到信用耗尽拨号计划: uuid_transfer <uuid> credit_exhausted XML ims_as
总结:信用耗尽机制
OmniTAS 提供两种互补机制:
-
计划定时器 (
schedule_hangup_auth):- 当授予的信用到期时自动挂断/转接
- 在每个 CCR-U 响应时动态重新调度
- 使用缓冲逻辑在到期之前发送 CCR-U
- 与公告功能集成
-
即时耗尽处理:
- 当 OCS 在 CCR-U 中拒绝信用时触发
- 覆盖计划定时器
- 支持公告播放
- 处理特定的 Diameter 错误代码
这两种机制都遵循 credit_exhaustion_announcement 配置,并将在配置时在终止呼叫之前播放配置的音��。
AVP 解析和变量映射
概述
OmniTAS 自动从信用控制应答消息中提取属性值对 (AVPs),并将其作为通道变量提供给 FreeSWITCH。这使得拨号计划逻辑可以使用 OCS 提供的数据进行路由决策、计费目的或呼叫处理。
支持的 AVP 类型:
- 简单值 (UTF8String, Unsigned32, Integer32)
- 带有嵌套结构的分组 AVPs
- 供应商特定的 AVPs (例如,3GPP 服务信息)
变量命名约定:
AVPs 被扁平化为点符号通道变量,前缀为 CCA:
CCA.<AVP-名称>.<嵌套-AVP-名称>.<值-AVP-名称> = "值"
常见 AVP 映射
服务信息 AVP (3GPP)
服务信息分组 AVP (AVP 代码 873, 供应商 ID 10415) 包含 IMS 特定的计费详细信息:
示例 OCS 响应:
服务信息
├── IMS-信息
│ ├── 运营商选择路由信息: "1408"
│ └── 节点功能: 6
└── 替代收费方地址: "NickTest"
生成的 FreeSWITCH 变量:
CCA.Service-Information.Carrier-Select-Routing-Information = "1408"
CCA.Service-Information.Alternate-Charged-Party-Address = "NickTest"
在拨号计划中访问: 变量使用点符号和连字符,如上所示:
<action application="log" data="INFO 运营商: ${CCA.Service-Information.Carrier-Select-Routing-Information}"/>
使用 uuid_dump 查看:
在 FreeSWITCH 控制台或 ESL 中,变量以 variable_ 前缀出现:
variable_CCA.Service-Information.Carrier-Select-Routing-Information: 1408
variable_CCA.Service-Information.Alternate-Charged-Party-Address: NickTest
注意: FreeSWITCH 保留变量名称中的点和连字符。变量在所有拨号计划上下文和应用程序中都可以使用。
授予服务单元 AVP
时间配额被提取并可用:
OCS 响应:
授予服务单元
└── CC-时间: 600
变量:
allocated_time = 600
AVP 处理逻辑
处理规则:
- 分组 AVPs 增加变量名称层次,但没有值本身
- 简单 AVPs 被映射到具有其完整��路径的变量
- 供应商特定的 AVPs 与标准 AVPs 处理相同
- 未知 AVPs 安全跳过而不产生错误
示例:多层嵌套
OCS CCA 结构:
服务信息 (分组)
├── IMS-信息 (分组)
│ ├── 节点功能: 6
│ ├── 节点角色: 1
│ ├── 呼叫方地址: "tel:+313380000000670"
│ └── 时间戳 (分组)
│ ├── SIP-请求时间戳: "2026-01-24T22:40:18Z"
│ └── SIP-响应时间戳: "2026-01-24T22:40:18Z"
└── IN-信息 (分组)
└── 实际被叫号码: "24724741234"
生成的 FreeSWITCH 变量:
CCA.Service-Information.IMS-Information.Node-Functionality = "6"
CCA.Service-Information.IMS-Information.Role-Of-Node = "1"
CCA.Service-Information.IMS-Information.Calling-Party-Address = "tel:+313380000000670"
CCA.Service-Information.IMS-Information.Time-Stamps.SIP-Request-Timestamp = "2026-01-24T22:40:18Z"
CCA.Service-Information.IMS-Information.Time-Stamps.SIP-Response-Timestamp = "2026-01-24T22:40:18Z"
CCA.Service-Information.IN-Information.Real-Called-Number = "24724741234"
配置
在线计费参数
| 参数 | 类型 | 必需 | 默认 | 描述 |
|---|---|---|---|---|
enabled | 布尔值 | 否 | false | 启用在线计费集成。当为 false 时,所有呼叫绕过 OCS 授权。 |
periodic_ccr_time_seconds | 整数 | 否 | 60 | 在活动呼叫期间 CCR-Update 消息之间的间隔(以秒为单位)。当启用 schedule_hangup_auth 时不使用(基于授予信用的动态定时)。推荐范围:30-300 秒用于传统模式。 |
ccr_update_buffer_seconds | 整数 | 否 | 2 | 在发送 CCR-Update 时,信用到期前的安全缓冲(以秒为单位)。OmniTAS 在 (allocated_time - buffer) 时发送 CCR-U,以确保在到期之前延长信用。推荐:2-5 秒。 |
schedule_hangup_auth | 布尔值 | 否 | false | 启用当授予的信用到期时自动挂断/转接呼叫。当为 true 时,OmniTAS 根据每个 CCA 的 allocated_time 调度 FreeSWITCH 定时器,并在每个 CCR-U 响应时动态重新调度。与 credit_exhaustion_announcement 一起工作。 |
credit_exhaustion_announcement | 字符串 | 否 | nil | 信用耗尽公告的音频文件路径。当与 schedule_hangup_auth 一起配置时,使用计划 转接 在挂断之前播放公告。当单独配置(不与 schedule_hangup_auth 一起)时,仅在立即信用耗尽时播放公告。路径必须使用 FreeSWITCH 变量:"${base_dir}/sounds/..."。设置为 nil 以直接挂断而不播放公告。 |
skipped_regex | 列表[字符串] | 否 | [] | 绕过 OCS 的目标号码的正则表达式模式列表。对紧急号码(例如,"^911$","^000$")很有用。 |
Diameter 连接参数
| 参数 | 类型 | 必需 | 默认 | 描述 |
|---|---|---|---|---|
origin_host | 字符串 | 是 | - | OmniTAS Diameter 身份 (FQDN)。在您的 Diameter 网络中必须唯一。例如:"tas01.epc.mnc123.mcc456.3gppnetwork.org"。 |
origin_realm | 字符串 | 是 | - | OmniTAS Diameter 领域。用于路由决策。例如:"epc.mnc123.mcc456.3gppnetwork.org"。 |
destination_realm | 字符串 | 是 | - | OCS Diameter 领域。请求路由到该领域中的对等方。 |
destination_host | 字符串 | 否 | nil | 特定 OCS Diameter 身份。当为 nil 时,仅基于 destination_realm 进行路由。当需要直接路由到特定 OCS 实例时使用。 |
配置示例
config :tas, :online_charging,
# 启用在线计费
enabled: true,
# 每 60 秒发送一次 CCR-Update
periodic_ccr_time_seconds: 60,
# 根据授予的信用调度挂断
schedule_hangup_auth: true,
# 在信用耗尽挂断之前播放公告
credit_exhaustion_announcement: "ivr/ivr-account_balance_low.wav",
# 跳过紧急呼叫和语音信箱的 OCS
skipped_regex: [
"^911$", # 紧急(美国)
"^000$", # 紧急(澳大利亚)
"^\*86$" # 语音信箱访问
]
config :tas, :diameter,
# 服务身份
origin_host: "tas01.epc.mnc380.mcc313.3gppnetwork.org",
origin_realm: "epc.mnc380.mcc313.3gppnetwork.org",
# OCS 路由
destination_realm: "epc.mnc380.mcc313.3gppnetwork.org",
destination_host: nil # 基于领域的路由
工作原理:
当接收到呼叫时:
- 检查目标号码是否与
skipped_regex模式匹配 - 如果匹配,呼叫绕过 OCS(对紧急服务很有用)
- 如果不匹配,CCR-Initial 在
destination_realm发送到 OCS - 解析 CCA 响应以获取授予的单位和 AVPs
- 将 AVPs 映射到 FreeSWITCH 变量(见 AVP 映射)
- 呼叫继续进行,
allocated_time和 AVP 数据可用 - 在呼叫期间每
periodic_ccr_time_seconds发送 CCR-Update - 如果启用
schedule_hangup_auth,当信用到期时自动挂断 - 在呼叫完成时发送 CCR-Terminate
用例:
- 基本 OCS: 启用默认设置以进行标准信用控制
- 高价值呼叫: 将
periodic_ccr_time_seconds减少到 30s 以进行频繁的重新认证 - 预付费服务: 启用
schedule_hangup_auth并设置credit_exhaustion_announcement - 紧急合规性: 将紧急号码添加到
skipped_regex以确保始终连接
FreeSWITCH 集成
在拨号计划中访问 AVP 变量
从 CCA 消息中提取的 AVP 数据可作为通道变量在 FreeSWITCH 拨号计划中使用:
<extension name="Route_with_OCS_Data">
<condition field="destination_number" expression="^(.+)$">
<!-- 访问来自 OCS 的运营商路由信息 -->
<action application="log"
data="INFO 运营商代码: ${CCA.Service-Information.Carrier-Select-Routing-Information}"/>
<!-- 访问来自 OCS 的被收费方 -->
<action application="log"
data="INFO 被收费方: ${CCA.Service-Information.Alternate-Charged-Party-Address}"/>
<!-- 访问授予的时间 -->
<action application="log"
data="INFO 分配时间: ${allocated_time} 秒"/>
<!-- 根据运营商代码路由 -->
<action application="set"
data="carrier_code=${CCA.Service-Information.Carrier-Select-Routing-Information}"/>
<action application="bridge"
data="sofia/external/$1@carrier-${carrier_code}.sip.example.com"/>
</condition>
</extension>
变量可用性
时机:
- 变量在 FreeSWITCH 呼叫设置 之前 设置
- 在整个呼叫持续期间可用
- 在呼叫转接和更新之间保持
范围:
- 通道范围(特定于单个呼叫腿)
- 不会被桥接/转接的腿继承
- 在所有拨号计划应用程序中安全使用
示例用例
1. 基于 OCS 数据的运营商选择
使用 OCS 提供的运营商代码路由呼叫:
<extension name="Carrier_Selection">
<condition field="${CCA.Service-Information.Carrier-Select-Routing-Information}" expression="^(.+)$">
<action application="bridge"
data="sofia/external/${destination_number}@carrier-$1.example.com"/>
</condition>
<!-- 如果未指定运营商则回退 -->
<condition field="${CCA.Service-Information.Carrier-Select-Routing-Information}" expression="^$">
<action application="bridge"
data="sofia/external/${destination_number}@default-carrier.example.com"/>
</condition>
</extension>
工作原理: OCS 在服务信息 AVP 中返回运营商代码 "1408"。FreeSWITCH 根据此数据将呼叫路由到 carrier-1408.example.com 网关。
2. 替代计费方
根据 OCS 响应将计费路由到不同方:
<extension name="Alternate_Billing">
<condition field="${CCA.Service-Information.Alternate-Charged-Party-Address}" expression="^(.+)$">
<!-- 记录计费方以用于 CDR -->
<action application="set"
data="billed_party=$1"/>
<action application="export"
data="billed_party=$1"/>
<!-- 包含在 SIP 头中 -->
<action application="set"
data="sip_h_X-Billed-Party=$1"/>
<action application="bridge"
data="sofia/external/${destination_number}@trunk.example.com"/>
</condition>
</extension>
工作原理: OCS 指定替代收费方(例如,公司账户)。OmniTAS 从 AVP 中提取 "NickTest",并使其可用于拨号计划以进行 CDR 记录和 SIP 头插入。
3. 有时间限制的呼叫与警告
在信用到期之前提供警告:
<extension name="Credit_Warnings">
<condition field="destination_number" expression="^(.+)$">
<!-- 在挂断前 30 秒调度警告 -->
<action application="set"
data="warning_time=${expr(${allocated_time} - 30)}"/>
<action application="sched_hangup"
data="+${allocated_time} ALLOTTED_TIMEOUT"/>
<action application="sched_broadcast"
data="+${warning_time} playback::ivr/ivr-account_balance_low.wav"/>
<action application="bridge"
data="sofia/external/$1@trunk.example.com"/>
</condition>
</extension>
工作原理: 使用来自 OCS 的 allocated_time 来调度自动挂断,并在断开连接前 30 秒播放警告公告。
Diameter 消息
CCR-Initial (请求类型 1)
在呼叫设置之前发送以请求授权和初始信用分配。
发送的关键 AVPs:
| AVP | 代码 | 类型 | 描述 |
|---|---|---|---|
| Session-Id | 263 | UTF8String | 唯一会话标识符:<origin_host>;<timestamp>;<random> |
| Auth-Application-Id | 258 | Unsigned32 | 值 4 用于 Diameter 信用控制应用程序,见 RFC 4006 |
| Service-Context-Id | 461 | UTF8String | "000.000.12.32260@3gpp.org" 用于 IMS 计费,见 TS 32.299 |
| CC-Request-Type | 416 | 枚举 | 值 1 (INITIAL_REQUEST) |
| CC-Request-Number | 415 | Unsigned32 | 序列号,从 1 开始 |
| Subscription-Id | 443 | 分组 | 订阅者 MSISDN 或 IMSI |
| Requested-Service-Unit | 437 | 分组 | 请求的信用(时间或单位) |
| Service-Information | 873 | 分组 | IMS 特定的呼叫详细信息(呼叫方/被叫方、时间戳) |
示例 CCR-I:
Session-Id: "tas01.example.org;1769294418268;8a078232"
Auth-Application-Id: 4
CC-Request-Type: 1 (INITIAL_REQUEST)
CC-Request-Number: 1
Subscription-Id:
- Subscription-ID-Type: 0 (END_USER_E164)
Subscription-ID-Data: "313380000000670"
Requested-Service-Unit:
- CC-Time: 0 (请求最大可用)
Service-Information:
- IMS-Information:
- Calling-Party-Address: "tel:+313380000000670"
- Called-Party-Address: "tel:+24724741234"
- Node-Functionality: 6 (AS)
CCA (信用控制应答)
来自 OCS 的响应,包含授权决定和授予的信用。
接收的关键 AVPs:
| AVP | 代码 | 类型 | 描述 |
|---|---|---|---|
| Result-Code | 268 | Unsigned32 | 2001 表示成功。有关错误值,请参见 结果代码。 |
| Granted-Service-Unit | 431 | 分组 | 分配的信用(以秒为单位的时间) |
| Service-Information | 873 | 分组 | 附加的计费数据(运营商信息、收费方等) |
示例 CCA 及 AVPs:
Session-Id: "tas01.example.org;1769294418268;8a078232"
Result-Code: 2001 (DIAMETER_SUCCESS)
CC-Request-Type: 1
CC-Request-Number: 1
Granted-Service-Unit:
- CC-Time: 600 (授予 10 分钟)
Service-Information:
- IMS-Information:
- Carrier-Select-Routing-Information: "1408"
- Alternate-Charged-Party-Address: "NickTest"
生成的变量:
allocated_time = 600
CCA.Service-Information.Carrier-Select-Routing-Information = "1408"
CCA.Service-Information.Alternate-Charged-Party-Address = "NickTest"
CCR-Update (请求类型 2)
在活动呼叫期间发送,用于周期性重新授权或临时使用报告。
发送时机:
- 每
periodic_ccr_time_seconds(默认:60s) - 在呼叫接听时(从设置转为活动)
- 当显式触发时(例如,服务变更)
与 CCR-I 的关键区别:
CC-Request-Type:2(UPDATE_REQUEST)CC-Request-Number: 随每次更新递增Used-Service-Unit: 报告自上次请求以来的使用情况Requested-Service-Unit: 请求额外的信用
CCR-Terminate (请求类型 3)
在呼叫终止时发送,报告最终使用情况。
关键 AVPs:
CC-Request-Type:3(TERMINATION_REQUEST)Used-Service-Unit: 总呼叫持续时间Termination-Cause: 会话结束的原因
结果代码
| 代码 | 名称 | 描述 | OmniTAS 动作 |
|---|---|---|---|
| 2001 | DIAMETER_SUCCESS | 请求批准 | 解析 AVPs,设置呼叫 |
| 4010 | DIAMETER_END_USER_SERVICE_DENIED | 服务拒绝给订阅者 | 拒绝呼叫,返回 CALL_REJECTED |
| 4012 | DIAMETER_CREDIT_LIMIT_REACHED | 信用不足 | 拒绝呼叫,返回 OUTGOING_CALL_BARRED |
| 5003 | DIAMETER_AUTHORIZATION_REJECTED | OCS 策略拒绝 | 拒绝呼叫,记录错误 |
| 5xxx | 永久性故障 | OCS 配置或系统错误 | 拒绝呼叫,记录错误 |
参考: RFC 6733 §7.1 和 3GPP TS 32.299
指标
Diameter 请求指标
指标: diameter_requests_total
类型: 计数器
描述: 应用程序和请求类型发送的总 Diameter 请求
标签:
application- Diameter 应用程序:ro(在线计费)command- 请求类型:ccrstatus- 结果:success,error,timeout
示例查询:
# CCR 成功率
sum(rate(diameter_requests_total{application="ro",command="ccr",status="success"}[5m]))
/ sum(rate(diameter_requests_total{application="ro",command="ccr"}[5m]))
# CCR 超时率
rate(diameter_requests_total{application="ro",command="ccr",status="timeout"}[5m])
Diameter 响应指标
指标: diameter_responses_total
类型: 计数器
描述: 根据结果代码接收的 Diameter 响应
标签:
application-rocommand-ccrresult_code- Diameter 结果代码 (2001, 4012, 等)
示例查询:
# 按结果代码的响应
sum by (result_code) (rate(diameter_responses_total{application="ro"}[5m]))
# 信用限制拒绝 (4012)
rate(diameter_responses_total{application="ro",result_code="4012"}[5m])
OCS 授权指标
指标: ocs_authorizations_total
类型: 计数器
描述: OCS 授权尝试和结果
标签:
result-success,nocredit,timeout,errorskipped-true如果通过正则表达式绕过,false否则
示例查询:
# 授权成功率(不包括跳过的)
sum(rate(ocs_authorizations_total{result="success",skipped="false"}[5m]))
/ sum(rate(ocs_authorizations_total{skipped="false"}[5m]))
# 无信用拒绝
rate(ocs_authorizations_total{result="nocredit"}[5m])
Diameter 持续时间指标
指标: diameter_request_duration_seconds
类型: 直方图
描述: Diameter 请求的往返时间
标签:
application-rocommand-ccrstatus-success,error,timeout
示例查询:
# CCR 延迟的第 95 百分位
histogram_quantile(0.95,
sum(rate(diameter_request_duration_seconds_bucket{application="ro"}[5m])) by (le)
)
# 按状态的平均延迟
avg(rate(diameter_request_duration_seconds_sum{application="ro"}[5m]))
by (status)
/ avg(rate(diameter_request_duration_seconds_count{application="ro"}[5m]))
by (status)
故障排除
FreeSWITCH 中未找到 AVP 变量
症状:
- FreeSWITCH 拨号计划无法访问
${CCA.Service-Information.*}变量 - 变量显示为空或未定义
可���原因:
- OCS 在 CCA 中未返回服务信息 AVPs
- AVP 解析因意外结构失败
- 变量未导出到 FreeSWITCH 通道
解决方案:
-
验证 OCS 响应包含 AVPs
检查 OmniTAS 日志中的 CCA 消息:
[debug] 信用控制应答: {:diameter_packet, ...}
[debug] 解析的 AVP 变量: %{
"CCA.Service-Information.Carrier-Select-Routing-Information" => "1408",
"CCA.Service-Information.Alternate-Charged-Party-Address" => "NickTest"
}如果 "解析的 AVP 变量" 为空
%{},则 OCS 未返回预期的 AVPs。 -
检查 AVP 解析错误
查找日志中的警告:
[warning] 收到另一种类型的回复: {...}这表明 AVP 结构与预期格式不匹配。检查 Diameter 数据包结构。
-
验证 FreeSWITCH 变量导出
在 FreeSWITCH 控制台或 ESL 中:
freeswitch> uuid_dump <call-uuid>查找带有
variable_前缀和CCA.的变量:variable_CCA.Service-Information.Carrier-Select-Routing-Information: 1408
variable_CCA.Service-Information.Alternate-Charged-Party-Address: NickTest
variable_CCA.Auth-Application-Id: 4
variable_CCA.Result-Code: 2001注意: FreeSWITCH 保留变量名称中的点和连字符。它们在拨号计划中正常工作:
<action application="log" data="运营商: ${CCA.Service-Information.Carrier-Select-Routing-Information}"/>
呼叫被拒绝,错误为 "unhandled"
症状:
- 日志显示:
[warning] 无法授权呼叫: :unhandled - 有效的 CCA 响应 (结果代码 2001) 被拒绝
- 尽管 OCS 批准,呼叫仍然失败
可能原因:
- CCA 消息结构与预期模式不匹配
- 供应商特定的 AVPs 在意外位置
- AVP 位置索引不匹配
解决方案:
这是最近版本修复的已知问题。确保您正在运行当前版本。
以前的行为: 模式匹配要求:
- 授予服务单元 AVP 必须在位置 7
- 空的供应商特定 AVP 列表
[]
当前行为: 模式匹配接受:
- 授予服务单元 AVP 在任何位置
- 非空的供应商特定 AVP 列表
如果问题仍然存在:
- 捕获 CCA 数据包结构的日志
- 检查 AVPs 是否符合预期的 Diameter 格式
- 验证结果代码为 2001
OCS 所有请求超时
症状:
- 所有 CCR 请求超时
- 日志显示:
[debug] 收到授权响应: {:error, :timeout} - 5 秒内未收到 CCA
可能原因:
- 与 OCS/DRA 的网络连接问题
- 防火墙阻止 Diameter 端口 (3868)
destination_realm或destination_host不正确- OCS 未对请求做出响应
解决方案:
-
验证网络连接
测试与 OCS 的 TCP 连接:
telnet ocs.example.com 3868应成功连接。如果连接被拒绝或超时,请检查防火墙规则。
-
检查 Diameter 配置
验证
destination_realm是否与 OCS 配置匹配:config :tas, :diameter,
destination_realm: "epc.mnc380.mcc313.3gppnetwork.org" # 必须与 OCS 领域匹配 -
查看 OCS 日志
检查 OCS 是否接收到 CCR 消息。如果 OCS 收到请求但未响应:
- 验证 OmniTAS 的
origin_host是否被 OCS 识别 - 检查 OCS 对等方配置是否允许来自 OmniTAS 的连接
- 验证服务上下文 ID 和应用程序 ID 是否与 OCS 预期匹配
- 验证 OmniTAS 的
信用耗尽未挂断呼叫
症状:
- 呼叫继续超出授予的信用时间
- 当
allocated_time到期时未自动挂断 schedule_hangup_auth启用但未生效
可能原因:
- FreeSWITCH 计划挂断未配置
schedule_hangup_auth为false- 呼叫状态未正确跟踪
解决方案:
-
验证配置
确保启用
schedule_hangup_auth:config :tas, :online_charging,
schedule_hangup_auth: true -
检查 FreeSWITCH ESL 连接
验证 OmniTAS 是否可以向 FreeSWITCH 发送命令:
[debug] 调度挂断响应: {:ok, "+OK"}如果出现错误或没有响应,请检查 FreeSWITCH 事件套接字配置。
-
监控呼叫状态
检查呼叫 UUID 是否在呼叫状态中跟踪:
[debug] 为呼叫设置计划挂断,600 秒后如果未找到 UUID,呼叫状态跟踪可能存在问题。
跳过的正则表达式未绕过 OCS
症状:
- 紧急呼叫 (911, 000) 仍然通过 OCS 授权
- 匹配
skipped_regex模式的号码未被绕过 - 紧急呼叫延迟
可能原因:
- 正则表达式模式语法错误
- 目标号码格式不匹配
- 正则表达式未正确转义
解决方案:
-
验证正则表达式模式
测试正则表达式编译:
Regex.compile("^911$") # 应返回 {:ok, ~r/^911$/}常见错误:
- 缺少锚点:使用
^911$而不是911 - 转义:使用
\*表示字面星号,而不是\*
- 缺少锚点:使用
-
检查号码格式
验证目标号码格式是否与模式匹配:
[debug] 检查拨打的号码 "911" 是否匹配跳过的正则表达式...如果号码格式为 "+1911",但模式为
"^911$",则不会匹配。 -
示例模式
config :tas, :online_charging,
skipped_regex: [
"^911$", # 美国紧急
"^000$", # 澳大利亚紧急
"^112$", # 国际紧急
"^\*86$", # 语音信箱(转义星号)
"^1?800\d{7}$" # 免费电话
]
参考
3GPP 规范
| 规范 | 标题 | 相关章节 |
|---|---|---|
| TS 32.299 | Diameter 计费应用 | §6.3 (Ro 接口), §7.2 (AVP 定义) |
| TS 32.240 | 计费架构和原则 | §5 (在线计费) |
| TS 29.229 | Cx 和 Dx 接口 | 服务信息 AVP 在 IMS 中的使用 |
IETF RFCs
| RFC | 标题 | 相关章节 |
|---|---|---|
| RFC 6733 | Diameter 基础协议 | §3 (协议概述), §7 (错误处理) |
| RFC 4006 | Diameter 信用控制应用 | §8 (信用控制消息) |
AVP 代码参考
在 OCS 集成中使用的常见 AVPs:
| AVP 名称 | 代码 | 供应商 ID | 类型 | 描述 |
|---|---|---|---|---|
| Session-Id | 263 | 0 | UTF8String | 唯一会话标识符 |
| Auth-Application-Id | 258 | 0 | Unsigned32 | Diameter 应用程序 ID (4 ��� CC) |
| CC-Request-Type | 416 | 0 | 枚举 | 1=初始,2=更新,3=终止 |
| CC-Request-Number | 415 | 0 | Unsigned32 | 序列号 |
| Result-Code | 268 | 0 | Unsigned32 | 请求结果 (2001=成功) |
| Granted-Service-Unit | 431 | 0 | 分组 | 分配的信用 |
| CC-Time | 420 | 0 | Unsigned32 | 以秒为单位的时间配额 |
| Service-Information | 873 | 10415 | 分组 | 3GPP 特定的服务数据 |
| IMS-Information | 876 | 10415 | 分组 | IMS 计费信息 |
| Carrier-Select-Routing-Information | 2023 | 10415 | UTF8String | 运营商路由代码 |
| Alternate-Charged-Party-Address | 1280 | 10415 | UTF8String | 计费方标识符 |
供应商 ID 10415 = 3GPP
FreeSWITCH 通道变量
所有提取的 AVP 数据作为 FreeSWITCH 通道变量可用:
| 变量名称 | 来源 | 示例值 | 描述 |
|---|---|---|---|
${allocated_time} | 授予服务单元 / CC-时间 | 600 | 以秒为单位的分配时间 |
${CCA.Session-Id} | Session-Id AVP | omni-as01.epc...;1769299669873;325e2f2e | Diameter 会话标识符 |
${CCA.Result-Code} | Result-Code AVP | 2001 | CCA 结果 (2001 = 成功) |
${CCA.Auth-Application-Id} | Auth-Application-Id AVP | 4 | Diameter 应用程序 (4 = CC) |
${CCA.CC-Request-Type} | CC-Request-Type AVP | 1 | 请求类型 (1=初始) |
${CCA.CC-Request-Number} | CC-Request-Number AVP | 1 | 序列号 |
${CCA.CC-Time} | CC-时间 AVP(如果存在) | 600 | 授予的时间配额 |
${CCA.Origin-Host} | Origin-Host AVP | ocs01.epc.mnc380.mcc313.3gppnetwork.org | OCS 主机标识符 |
${CCA.Origin-Realm} | Origin-Realm AVP | epc.mnc380.mcc313.3gppnetwork.org | OCS 领域 |
${CCA.Service-Information.Carrier-Select-Routing-Information} | Service-Information → Carrier-Select-Routing-Information | 1408 | 来自 OCS 的运营商路由代码 |
${CCA.Service-Information.Alternate-Charged-Party-Address} | Service-Information → Alternate-Charged-Party-Address | NickTest | 替代计费方 |
变量格式:
- 所有 CCA AVPs 使用前缀
CCA. - 嵌套 AVPs 使用点符号表示:
CCA.Parent.Child - 变量名称中的点和连字符被保留
- 在 uuid_dump 中,变量以
variable_前缀出现
示例 uuid_dump 输出:
variable_allocated_time: 600
variable_CCA.Service-Information.Carrier-Select-Routing-Information: 1408
variable_CCA.Service-Information.Alternate-Charged-Party-Address: NickTest
variable_CCA.Result-Code: 2001