简介:本资源为3GPP TS 32.260 IMS计费技术规范的中文版文档,面向从事移动通信核心网计费系统研发、测试与运维的工程师,以及需要理解IMS计费机制的通信专业学生与研究人员。该规范聚焦IP多媒体子系统(IMS)的计费管理,覆盖GSM、UMTS、LTE等多代移动通信技术下的计费场景,是理解现代移动网络计费体系的核心参考资料。资源包内共1个PDF文件,大小约2.65MB,内容完整涵盖前言、范围、参考文献、定义符号与缩写、架构注意事项等章节,并深入展开高级IMS架构、离线计费架构、在线计费架构及融合计费架构等关键模块。读者可从中系统掌握计费数据记录(CDR)、计费触发点、在线与离线计费系统、计费策略与规则功能(CPRF)以及Diameter、Gx等接口协议的核心知识,对保障运营商计费准确性与互操作性具有重要参考价值。目前已有195人学习下载,建议结合英文原版对照研读,以全面把握技术细节。
1. 从一条话单说起:IMS 计费为什么绕不开 TS 32.260
你大概率是在排查一张 IMS 话单对不上账的时候,才第一次听说 3GPP TS 32.260 这个名字。VoLTE 通话结束,PGW-C 和 S-CSCF 各自吐出一条 CDR,运营商侧账单却差了那么几秒、几 KB,或者干脆少了一条记录。翻规范才发现,问题不在设备厂商实现,而在 IMS 计费架构本身——谁生成、谁传递、谁合并、谁最终出单,这套规则全写在 TS 32.260 里。
这份规范全称是 IMS charging,属于 3GPP TS 32 系列计费规范族的一员,和 TS 32.250(电路域计费)、TS 32.251(分组域计费)、TS 32.240(计费架构总纲)是兄弟关系。它定义的是 IMS 域内各个网元(S-CSCF、P-CSCF、I-CSCF、MRFC、MGCF、AS 等)如何生成计费信息、如何通过 Rf 接口送往 CDF、离线计费与在线计费(Ro 接口)分别怎么走、多网元场景下如何做 CDR 关联。
中文版行标的意义在于:英文原版里那些 "charging correlation"、"ICID"、"Access-Network-Charging-Identifier" 的措辞,在工程落地时经常被理解偏。中文版把术语锚定下来,做需求评审、写测试用例、和核心网厂商对齐接口时,少一层翻译损耗。适合谁读?IMS 核心网运维、计费系统开发、话单稽核、以及做 VoLTE/VoNR 测试的工程师。如果你只关心"通话能不能通",这份规范可以先放一放;一旦涉及"通话怎么算钱",它就是绕不过去的底座。
2. TS 32.260 的计费架构:ICID 是怎么把多个网元串成一条链的
IMS 计费最核心的难点不是单个网元怎么出话单,而是一次会话经过五六个网元,怎么保证这些话单能被拼回同一次通话。TS 32.260 给出的答案是 ICID(IMS Charging Identifier,IMS 计费标识)加 Access-Network-Charging-Identifier 的组合。理解这套机制,后面看任何字段都不会迷路。
2.1 离线计费与在线计费的边界在哪
离线计费走 Rf 接口,网元把计费事件通过 ACR(Accounting Request)发给 CDF(Charging Data Function),CDF 落成 CDR,再由 CGF(Charging Gateway Function)做格式转换和合并,最终送到 BD(Billing Domain)。整个过程是"先服务、后出单",用户通话时并不感知。
在线计费走 Ro 接口,网元在会话建立前就要向 OCS(Online Charging System)申请配额,OCS 返回 Granted-Service-Unit,网元用完再申请,余额不足直接拒绝会话。VoLTE 预付费用户走的就是这条路。
两者的分界点在网元配置:S-CSCF 上如果同时配了 Rf 和 Ro 地址,通常按用户签约类型决定走哪条。工程上最容易翻车的是同一用户两条链路都触发,导致重复计费。规范里明确要求网元根据用户 Profile 二选一,但厂商实现里这个判断逻辑经常有 bug。
2.2 ICID 的生成规则与传递路径
ICID 是一个全局唯一的字符串,由会话发起侧的第一个 IMS 网元生成。以 VoLTE 主叫为例,P-CSCF 收到 SIP INVITE 后生成 ICID,写入 P-Charging-Vector 头域,后续所有网元从 SIP 消息里读取这个头域,把 ICID 抄进自己的 CDR。
P-Charging-Vector: icid-value="abc123def456"; icid-generated-at=p-cscf.example.com这条头域是整条计费链的"身份证"。S-CSCF、MRFC、MGCF 出的 CDR 里都会带同一个 icid-value,后处理系统靠它做关联。如果某个网元没透传这个头域,它的话单就成了孤儿单,对账时永远拼不上。
注意:ICID 的格式在 TS 32.260 里没有强制规定具体编码,只要求全局唯一。实际部署中常见的是"主机名+时间戳+随机数"的拼接,长度控制在 64 字符以内,避免某些老设备截断。
2.3 多网元 CDR 关联的字段对照
不同网元出的 CDR 字段名不一样,但有几个关键字段是关联的锚点。下面这张表是我在实际对账时整理的对照关系,字段名以规范定义为准,厂商实现可能有细微差异。
| 关联锚点 | P-CSCF CDR | S-CSCF CDR | MRFC CDR | MGCF CDR |
|---|---|---|---|---|
| 会话标识 | ICID | ICID | ICID | ICID |
| 主叫标识 | Calling-Party-Address | Calling-Party-Address | — | Calling-Party-Address |
| 被叫标识 | Called-Party-Address | Called-Party-Address | — | Called-Party-Address |
| 接入网计费标识 | Access-Network-Charging-Identifier | 透传 | — | — |
| 时间戳 | Event-Timestamp | Event-Timestamp | Event-Timestamp | Event-Timestamp |
| 节点地址 | P-CSCF-Address | S-CSCF-Address | MRFC-Address | MGCF-Address |
关联逻辑是:先按 ICID 分组,组内再按时间戳排序,用 Calling/Called-Party-Address 做二次校验。如果 ICID 缺失,退而求其次用"主被叫+时间窗口"做模糊匹配,但误关联率会明显上升。
2.4 一次 VoLTE 通话的计费消息流
把上面的概念串起来,一次标准 VoLTE 通话的离线计费流程大致是这样:
- 主叫 UE 发 INVITE,P-CSCF 生成 ICID,写入 P-Charging-Vector,同时向 CDF 发 ACR START。
- INVITE 转发到 S-CSCF,S-CSCF 读取 ICID,向 CDF 发自己的 ACR START。
- 如果涉及 MRF 放音或会议,MRFC 也生成带同一 ICID 的 ACR。
- 通话结束,各网元依次发 ACR STOP,CDF 收齐后合并成一条完整 CDR。
- CGF 做 CDR 去重和格式转换,送 BD 出单。
这里的关键是ACR START 和 ACR STOP 必须成对。如果网元异常重启,只发了 START 没发 STOP,CDF 会挂一条"未关闭"的记录,通常靠超时机制兜底,但超时时间设多长是个权衡——太短会误关正常长通话,太长会让异常单堆积。
3. 中文版行标怎么用:从术语对照到接口字段落地
拿到中文版 TS 32.260 之后,很多人第一反应是"逐字读一遍",结果读到第三章就放弃了。这份规范的正确用法是当字典查,而不是当教材读。下面说几个我实际工作中高频使用的场景。
3.1 术语对照:英文原版和中文版的锚点
中文版最大的价值是把关键术语固定下来。做需求文档、接口规范、测试用例时,团队内部必须用同一套词,否则"计费标识"和"计费 ID"混用,评审时就要吵架。下面是我整理的常用术语对照,以中文版行标为准。
| 英文术语 | 中文行标译法 | 工程口语 |
|---|---|---|
| IMS Charging Identifier | IMS 计费标识 | ICID |
| Charging Data Function | 计费数据功能 | CDF |
| Charging Gateway Function | 计费网关功能 | CGF |
| Accounting Request | 计费请求 | ACR |
| Access-Network-Charging-Identifier | 接入网计费标识 | ANC-ID |
| Inter-Operator Tariff | 运营商间费率 | IOT |
| Granted-Service-Unit | 授权服务单元 | GSU |
提示:中文版行标里有些译法比较生硬,比如"计费数据功能"读起来像在说一个功能模块,实际指的是一个网元实体。团队内部沟通时,建议中文术语用于正式文档,口语继续用英文缩写,避免歧义。
3.2 Rf 接口 ACR 消息的字段拆解
Rf 接口基于 Diameter 协议,ACR 消息里承载的计费信息以 AVPs(Attribute-Value Pairs)形式组织。TS 32.260 定义了 IMS 特有的 AVPs,下面挑几个最容易出问题的说。
# 用 tshark 抓 Rf 接口 Diameter 消息的典型命令 tshark -i eth0 -f "tcp port 3868" -Y "diameter.cmd.code == 271" \ -T fields -e diameter.Session-Id -e diameter.Origin-Host \ -e diameter.IMS-Charging-Identifier -e diameter.Access-Network-Charging-Identifier这条命令抓的是 ACR(Command Code 271),输出 Session-Id、源主机、ICID 和 ANC-ID。排查计费问题时,第一步就是确认这几个字段有没有值、值对不对。
- Session-Id:Diameter 会话标识,和 ICID 不是一回事。Session-Id 标识的是 Rf 接口上的一次 Diameter 会话,ICID 标识的是 IMS 层的一次业务会话。一个 ICID 可能对应多个 Session-Id(比如中间 CDF 切换)。
- IMS-Charging-Identifier:就是 ICID,必须和 SIP 头域里的 icid-value 一致。不一致说明网元透传逻辑有问题。
- Access-Network-Charging-Identifier:接入网侧(比如 eNodeB/gNodeB)生成的计费标识,用于和无线侧话单关联。这个字段在 P-CSCF 的 ACR 里有,S-CSCF 通常只透传。
3.3 在线计费 Ro 接口的 CCR 交互
在线计费走 Ro 接口,消息是 CCR(Credit-Control-Request)和 CCA(Credit-Control-Answer)。和 Rf 的"事后上报"不同,Ro 是"事前申请、事中续订、事后终结"。
# 抓 Ro 接口 CCR 消息,看请求的配额和使用的配额 tshark -i eth0 -f "tcp port 3868" -Y "diameter.cmd.code == 272" \ -T fields -e diameter.Session-Id -e diameter.CC-Request-Type \ -e diameter.Requested-Service-Unit -e diameter.Used-Service-UnitCC-Request-Type 有四个值:INITIAL_REQUEST(1)、UPDATE_REQUEST(2)、TERMINATION_REQUEST(3)、EVENT_REQUEST(4)。VoLTE 语音通话典型流程是 INITIAL 申请配额,通话中按周期发 UPDATE 续订,挂机发 TERMINATION 终结。
参数上最容易踩的坑是配额单位和配额大小。Requested-Service-Unit 里可以按时间(CC-Time)或流量(CC-Total-Octets)申请,VoLTE 语音一般按时间。如果 OCS 返回的 GSU 是 60 秒,网元必须在 60 秒用完前发 UPDATE,否则 OCS 侧会认为配额超用,触发异常告警。
3.4 用中文版行标写测试用例的三个切入点
测试用例不是把规范抄一遍,而是把规范里的"必须"和"应该"转成可验证的步骤。我一般从三个切入点下手:
第一,字段完整性。规范里标了 Mandatory 的 AVP,测试时逐条检查有没有值。比如 IMS-Charging-Identifier 在 ACR 里是必选,缺了就是不合格。
第二,关联一致性。同一个 ICID 在 P-CSCF、S-CSCF、MRFC 的 CDR 里必须一致,测试时构造一次跨网元通话,抓三份话单做比对。
第三,异常场景。规范里对异常处理有描述,比如 CDF 不可达时网元应该缓存还是丢弃。测试时模拟 CDF 断连,看网元行为是否符合规范要求。
4. 避坑与排查:IMS 计费对账时最常见的 5 个翻车现场
这一章是我这些年踩过的坑里挑出来的,每条都按"现象→原因→解决"写。有些坑看起来是设备问题,根子其实在规范理解偏差。
4.1 话单缺失:ICID 在某个网元断了
现象:一次 VoLTE 通话,P-CSCF 和 S-CSCF 都有话单,MRFC 的话单找不到,对账时这次通话的时长少了一段。
原因:MRFC 从 SIP 消息里读 P-Charging-Vector 头域失败。常见情况是 S-CSCF 转发 INVITE 到 MRFC 时,头域被某个中间设备改写或剥离。也有厂商实现里 MRFC 只在特定呼叫流程(比如会议)才读 ICID,普通放音场景直接生成新 ICID。
解决:先在 S-CSCF 出向抓包,确认 P-Charging-Vector 有没有透传。如果透传了但 MRFC 没读,查 MRFC 配置里 ICID 提取开关。如果 MRFC 生成了新 ICID,那是实现 bug,需要厂商补丁。临时方案是在后处理系统里用"主被叫+时间窗口"做模糊关联,但要把误关联率监控起来。
4.2 重复计费:Rf 和 Ro 同时触发
现象:预付费用户通话后,余额扣了两次,一次来自 OCS 的在线计费,一次来自 CDF 的离线话单。
原因:S-CSCF 上同时配置了 Rf 和 Ro 地址,但用户 Profile 判断逻辑有缺陷,导致两条链路都走了。规范要求网元根据用户签约的计费类型二选一,但有些实现里判断条件写成了"只要配了就发"。
解决:检查 S-CSCF 的计费配置,确认 Rf 和 Ro 的触发条件互斥。如果配置没问题,抓 Diameter 信令看两条链路的 ACR 和 CCR 是不是都发了。确认是设备 bug 后,短期可以在 CDF 侧加去重规则(按 ICID+时间戳),长期要厂商修判断逻辑。
4.3 时间戳对不上:网元间时钟不同步
现象:同一次通话,P-CSCF 话单的开始时间比 S-CSCF 早 3 秒,合并后通话时长算出来偏大。
原因:各网元没有统一 NTP 源,或者 NTP 同步精度不够。IMS 计费对时间戳的依赖很强,CDR 合并、时长计算、跨网元关联都靠它。
解决:所有 IMS 网元必须配置同一组 NTP 服务器,同步精度控制在毫秒级。如果已经出现时间偏差,先查 NTP 服务状态,再看网元有没有配置时区偏移。有些设备默认用本地时间而不是 UTC,跨时区部署时会出大问题。
4.4 ACR STOP 丢失:异常重启后的孤儿单
现象:CDF 里堆积了一批"未关闭"的 ACR 记录,对应的通话早就结束了。
原因:网元在通话过程中异常重启,只发了 ACR START 没发 ACR STOP。CDF 靠超时机制兜底,但超时时间如果设得太长(比如 24 小时),这些孤儿单会一直挂着。
解决:CDF 侧的超时时间建议设在 1 到 4 小时之间,根据业务最长通话时长调整。同时网元侧要开启计费缓存,重启后能把未发送的 ACR 补发。如果孤儿单已经产生,后处理时按 ICID 找对应的 START 记录,人工补一个 STOP 或者标记为异常单。
4.5 字段截断:ICID 超长被老设备砍掉
现象:某些老型号网元出的 CDR 里,ICID 只有前半段,和别的网元对不上。
原因:ICID 生成时没有控制长度,超过了某些设备字段的最大长度限制。TS 32.260 没有强制规定 ICID 长度,但工程实践里一般控制在 64 字符以内。
解决:检查 ICID 生成规则,确保长度不超过 64 字符。如果已经部署的设备有截断问题,要么改生成规则,要么在后处理系统里做前缀匹配。后者是权宜之计,会引入误关联风险。
5. 进阶:用脚本做 CDR 关联校验和计费一致性验证
规范读到最后,落脚点一定是"怎么验证实现是对的"。手工对账只能抽查,真正靠谱的做法是写脚本做批量校验。这一章给一个可复现的思路和代码骨架。
5.1 从 CDR 文件到关联结果的最小脚本
假设你手上有三份 CDR 文件,分别来自 P-CSCF、S-CSCF、MRFC,格式是 CSV,每行一条记录,关键列是 icid、calling、called、start_time、end_time、node。下面这个脚本做三件事:按 ICID 分组、检查组内记录数、输出缺失网元的 ICID。
import csv from collections import defaultdict # 三份 CDR 文件路径,实际使用时替换 cdr_files = { 'p-cscf': 'p-cscf_cdr.csv', 's-cscf': 's-cscf_cdr.csv', 'mrf': 'mrf_cdr.csv' } # 按 ICID 聚合,记录每个网元是否出现 icid_map = defaultdict(set) icid_detail = defaultdict(list) for node, path in cdr_files.items(): with open(path, newline='', encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: icid = row.get('icid', '').strip() if not icid: continue # 跳过无 ICID 的孤儿单 icid_map[icid].add(node) icid_detail[icid].append({ 'node': node, 'calling': row.get('calling', ''), 'called': row.get('called', ''), 'start': row.get('start_time', ''), 'end': row.get('end_time', '') }) # 输出关联结果 expected_nodes = {'p-cscf', 's-cscf'} for icid, nodes in icid_map.items(): missing = expected_nodes - nodes if missing: print(f"ICID {icid} 缺失网元: {missing}") for rec in icid_detail[icid]: print(f" {rec['node']}: {rec['calling']} -> {rec['called']} " f"[{rec['start']} ~ {rec['end']}]")这段代码的逻辑很直白:把三份 CDR 读进内存,按 ICID 建索引,然后检查每个 ICID 是否覆盖了预期网元。expected_nodes根据实际组网调整,比如有些场景 MRF 不参与,就不放进预期集合。
参数上要注意两点:一是icid列名要和实际 CDR 表头一致,不同厂商导出的字段名可能不同;二是时间格式,脚本里只做字符串比对,如果要算时长差,需要先解析成 datetime。
5.2 关联校验的三个验证维度
脚本跑通只是第一步,真正要验证的是三个维度:
完整性:每个 ICID 是否覆盖了所有应该出话单的网元。缺失的 ICID 要分类,是网元没出单,还是出了但 ICID 不一致。
一致性:同一个 ICID 在不同网元的话单里,主被叫号码、通话起止时间是否一致。时间差超过阈值(比如 2 秒)的要标出来查时钟同步。
合理性:通话时长是否为正、是否超过业务上限、同一用户短时间内是否有大量重复 ICID。这些异常往往指向设备故障或信令风暴。
5.3 把校验脚本接进日常巡检
脚本写完不要只跑一次,要接进日常巡检。我的做法是每天凌晨跑一次前一天的 CDR,输出三个指标:ICID 覆盖率、时间戳偏差分布、孤儿单数量。这三个指标连续几天异常,基本就能定位到具体网元。
| 指标 | 正常范围 | 异常指向 |
|---|---|---|
| ICID 覆盖率 | > 99.5% | 网元透传逻辑或生成规则问题 |
| 时间戳偏差 | < 500ms | NTP 同步或时区配置问题 |
| 孤儿单比例 | < 0.1% | 网元异常重启或 ACR STOP 丢失 |
这套方法不复杂,但坚持做下来,计费对账从"月底救火"变成"日常可控"。我自己最大的教训是:早期觉得脚本麻烦,靠人工抽查,结果一次版本升级引入的 ICID 截断问题拖了两个月才发现,补数据补到怀疑人生。后来把校验脚本当成必选项,每次网元升级后先跑一遍,心里才有底。希望帮到你。
本文还有配套的精品资源,点击获取