DLMS/COSEM 蓝皮书解读(三十六):IPv6 setup(class_id = 48)—— 把电表接入 IPv6 网络所需的"地址/前缀/网关/DNS/ND"建模
系列说明:本系列基于 DLMS UA《Blue Book(蓝皮书)第 16 版 · 第 2 部分》,一个接口类一篇。第 35 篇讲了
GSM diagnostic(class_id = 47),它是蜂窝模组的"体检表"。本篇的IPv6 setup(class_id = 48)回到网络层配置,回答"一块支持 IPv6 的电表,它的 IPv6 地址、网关、DNS、邻居发现参数怎么建模"——和第 30 篇IPv4 setup(class_id = 42)正好组成双栈的两半。
上篇回顾:第 34 篇
SMTP setup解决电表"怎么发邮件",第 35 篇GSM diagnostic解决"蜂窝模组状态怎么查";本篇把视角拉回网络层,补齐 IP 协议栈里的 IPv6 这一侧——MAC address setup(43) 在第 31 篇提到"IPv6 的地址配置由 IPv6 setup 提供",本篇就是那个对象。
0. 为什么需要这个类 —— IPv4 地址不够用,且一个网卡要挂多个地址
IPv4 的 32 位地址早已枯竭,而智能电表/集中器越来越多地跑在 IPv6 网络上(4G/5G 模组、G3-PLC、PRIME、Wi-SUN 等几乎都默认 IPv6)。更重要的是,IPv6 允许一个物理接口同时挂多个地址(链路本地、唯一本地、全局单播),这和 IPv4 的"一个接口一个地址"思路完全不同,因此 DLMS 专门为它建了一个接口类,而不是复用IPv4 setup。
蓝皮书对它的定位:
蓝皮书原文(
IPv6 setup, Overview):
“The IPv6 setup IC allows modelling the setup of the IPv6 layer, handling all information related to the IPv6 address settings associated to a given device and to a lower layer connection on which these settings are used.”
蓝皮书原文(
IPv6 setup, Overview):
“There shall be an instance of this IC in a device for each different network interface implemented. For example, if a device has two interfaces (using the UDP/IP and/or TCP/IP profile on both of them), there shall be two instances of the IPv6 setup IC in that device: one for each of these interfaces.”
一句话:每个网络接口一个实例。双栈设备通常同时存在一个IPv4 setup(42) 和一个IPv6 setup(48),两者通过各自的DL_reference指到同一个数据链路层 setup 对象。
1. 类蓝图
IPv6 setup 0…n class_id = 48, version = 0| 属性 | 静态/动态 | 数据类型 | Min | Max | Def | Short name |
|---|---|---|---|---|---|---|
| logical_name | static | octet-string | — | — | — | x |
| DL_reference | static | octet-string | — | — | — | x + 0x08 |
| address_config_mode | static | enum | — | — | 0 | x + 0x10 |
| unicast_IPv6_addresses | — | array | — | — | — | x + 0x18 |
| multicast_IPv6_addresses | static | array | — | — | — | x + 0x20 |
| gateway_IPv6_addresses | static | array | 0 | — | — | x + 0x28 |
| primary_DNS_address | static | octet-string | 0 | — | — | x + 0x30 |
| secondary_DNS_address | static | octet-string | 0 | — | — | x + 0x38 |
| traffic_class | static | unsigned | 0 | 63 | 0 | x + 0x40 |
| neighbor_discovery_setup | static | array | — | — | — | x + 0x48 |
注:原文属性表中
unicast_IPv6_addresses未标注 static/dyn(其余地址数组与neighbor_discovery_setup也未标注);其余 5 个显式标 (static)。logical_name不计入 Short name 偏移序列。
Specific methods(m/o):
| 方法 | 必选/可选(m/o) | Short name |
|---|---|---|
| add_IPv6_address (data) | optional | x + 0x60 |
| remove_IPv6_address (data) | optional | x + 0x68 |
2. 属性逐条解读
2.1 logical_name
蓝皮书原文:
"Identifies the ‘IPv6 setup’ object instance."
就是该对象的 OBIS(6 字节)。示例:0.0.25.7.0.255(非蓝皮书原文,实际以设备对象列表为准)。
2.2 DL_reference
蓝皮书原文:
"References a Data link layer setup object by its logical name. The referenced object contains information about the specific settings of the data link layer supporting the IPv6 layer."
通过logical_name指回底层数据链路层 setup 对象(如G3-PLC MAC setup(54) 或MAC address setup(43) 等)。这一项把 IP 层"绑"到具体链路——读 IPv6 配置前必须知道它底下跑的是哪条介质。
2.3 address_config_mode
蓝皮书原文:
"Defines the IPv6 address configuration mode"
enum: (0) Auto-configuration (default), (1) DHCPv6, (2) Manual, (3) ND (Neighbour Discovery)蓝皮书原文(NOTE):“The address_config_mode is common for all IPv6 addresses managed by an instance of the IPv6 setup class.”
关键点:这一个模式对实例管理的所有IPv6 地址(单播/组播/网关/DNS)同时生效,不能"单播走自动、网关走手动"。
2.4 unicast_IPv6_addresses
蓝皮书原文:
"Carries unicast IPv6 address(es) assigned to the related interface of the physical device on the network (unique local unicast, link local unicast and / or global unicast addresses). An IPv6 address can be either (static) or (dynamic) or both."
unicast_IPv6_addresses ::= array of octet-string蓝皮书原文:
"The format of each unicast IPv6 address shall be as specified in RFC 3513."
蓝皮书原文:"If no unicast IPv6 address is assigned to the interface, an array of zero elements is present (default)."/"To reset all unicast IPv6 address(es) configured, an array of zero elements shall be written."
也就是说:IPv6 地址在 DLMS 里就是一个 16 字节的 octet-string(address ::= array octet-string,每个元素 16 字节,符合 RFC 3513 / RFC 4291 的 128 位格式)。默认是空数组;要清空全部地址,就写回一个空数组。
2.5 multicast_IPv6_addresses
multicast_IPv6_addresses ::= array of octet-string蓝皮书原文:
"Contains an array of IPv6 addresses used for multicast."同样 16 字节/地址,RFC 3513 格式;空数组为默认,写空数组即重置。
2.6 gateway_IPv6_addresses
gateway_IPv6_addresses ::= array of octet-string蓝皮书原文:
"Contains the IPv6 addresses of the IPv6 gateway device."网关也允许多个(多出口路由),空数组为默认。
2.7 primary_DNS_address / secondary_DNS_address
蓝皮书原文:
"Contains the IPv6 address of the primary / secondary Domain Name Server (DNS)."/"If no IPv6 address is assigned, the length of the octet-string shall be 0."
注意:这里 DNS 是单个 octet-string(长度 0 表示未配置),而不是IPv4 setup里的 double-long-unsigned——因为 IPv6 地址没有"整数表示",只能用 16 字节串。
2.8 traffic_class
蓝皮书原文:
"Contains the traffic class element of the IPv6 header. The 6 most-significant bits are used for DSCP (Differentiated Services Codepoint), which is used to classify packets as specified in RFC 2474:1998, Clause 3."
traffic_class ::= unsigned, range 0…63, default 0只管 8 位中的高 6 位 DSCP(低 2 位 CU 当前未用)。这是一个"尽力而为"的优先级标记,并不保证传输(原文:“do not secure the transmission (the philosophy of the IP network is to do its best)”)。
2.9 neighbor_discovery_setup
蓝皮书原文:
"Contains the configuration to be used for both routers and hosts to support the Neighbor Discovery protocol for IPv6 (RFC 4861)."
neighbor_discovery_setup ::= array of structure structure { RS_max_retry: unsigned, // 1…255, default 3 RS_retry_wait_time: long-unsigned, // 0…65535 ms, default 10000 RA_send_period: double-long-unsigned // 0…4294967295 s }| 字段 | 含义 | 范围 | 缺省 |
|---|---|---|---|
| RS_max_retry | 收不到 RA 时,节点最多重发几次路由器请求(Router Solicitation) | 1–255 | 3 |
| RS_retry_wait_time | 两次 RS 重试之间的等待时间(毫秒) | 0–65535 | 10000 |
| RA_send_period | 路由器通告(Router Advertisement)发送周期(秒) | 0–4294967295 | — |
3. 方法:add_IPv6_address / remove_IPv6_address
两个方法都是 optional,结构完全一样:
data ::= structure { IPv6_address_type: enum, // (0) unicast, (1) multicast, (2) gateway IPv6_address: octet-string }蓝皮书原文(add):“Adds one IPv6 address for the physical interface to the IPv6 address array.”/“The new address will be automatically added at the end of the list. If an address has to be added to a specific position, this can be done by writing the whole array.”
蓝皮书原文(remove):“Removes one IPv6 address for the physical interface to the IPv6 address array.”
要点:
IPv6_address_type决定这条地址加到/从哪个数组(单播/组播/网关)里增删;- 新地址自动追加到末尾;要插到特定位置,只能整个数组写回(
SET unicast_IPv6_addresses); - 方法用
xDLMS ACTION调用(参数data为上面这个 structure)。
4. 【实战举例】
示例 1:双栈集中器的两个 setup 实例
一台集中器同时跑 IPv4/IPv6,底层是 G3-PLC 链路。它应有两个网络层实例(示例 OBIS,非蓝皮书原文):
| 对象 | logical_name(示例) | DL_reference | 作用 |
|---|---|---|---|
| IPv4 setup | 0.0.25.1.0.255 | 0.0.25.2.0.255(G3-PLC MAC setup 的 LN) | IPv4 地址/网关/DNS |
| IPv6 setup | 0.0.25.7.0.255 | 同上 | IPv6 地址/网关/DNS/ND |
两者DL_reference指向同一个链路层对象——这就是蓝皮书"每个接口一个实例"要求落地后的样子。
示例 2:单播地址数组的 A-XDR 编码
假设给接口配两个单播地址:链路本地fe80::1和全局2001:db8::2。
说明:下面字节为示意(非蓝皮书原文),按 A-XDR/COSEM 结构编码习惯写出,帮助理解。
array (tag 0x01) 长度=2 ├─ octet-string (tag 0x09) 长度=16 : FE 80 00 00 00 00 00 00 00 00 00 00 00 00 00 01 // fe80::1 └─ octet-string (tag 0x09) 长度=16 : 20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 02 // 2001:db8::22001:db8::2展开为 16 字节:20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 02——2001→20 01,0db8→0d b8,后面补 0。
示例 3:address_config_mode 怎么选
- 现场手动规划地址(无 DHCPv6 服务器)→ 选
(2) Manual,并手动填unicast_IPv6_addresses/gateway_IPv6_addresses; - 网络里有 DHCPv6 服务器(如 4G 核心网 / 企业网)→ 选
(1) DHCPv6,地址由服务器分配; - 纯链路本地、靠路由器通告自学 → 选
(3) ND,并配好neighbor_discovery_setup; - 想"能自动就自动" → 选
(0) Auto-configuration(缺省)。
注意:选了某个模式,单播/组播/网关/DNS 全跟着同一个模式走,不能拆分。
示例 4:neighbor_discovery_setup 默认值
array (长度=1) structure { RS_max_retry: unsigned 3, RS_retry_wait_time: long-unsigned 10000, // 10 秒 RA_send_period: double-long-unsigned 600 // 600 秒(示意,非蓝皮书原文) }示例 5:调用 add_IPv6_address 增加一个网关
ACTION add_IPv6_address的参数data:
structure { IPv6_address_type: enum 2, // (2) gateway IPv6_address: octet-string 16B = 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 0a // 2001:db8::a }调用后,gateway_IPv6_addresses数组末尾追加2001:db8::a。如果想删它,调remove_IPv6_address传同样的结构。
示例 6:traffic_class 与 DSCP 的位关系
traffic_class是一个 0–63 的整数,存的是 IPv6 头 8 位 Traffic Class 的高 6 位(DSCP)。例如要把某类报文标成 EF(加速转发,DSCP=46):
DSCP = 46 (0b101110) → traffic_class = 46低 2 位 CU 永远为 0,所以 DLMS 里traffic_class的可写范围就是 0–63(即 DSCP 0–63)。这不是"优先级数值越大越优先"的线性概念,而是按 RFC 2474 的 DSCP 分类。
示例 7:IPv6 setup 与 IPv4 setup 的差异对照
| 维度 | IPv4 setup (42) | IPv6 setup (48) |
|---|---|---|
| 地址类型 | double-long-unsigned(4 字节) | octet-string(16 字节) |
| 配置模式 | use_DHCP_flag(布尔) | address_config_mode(0/1/2/3 枚举) |
| 组播 | 无专门属性 | multicast_IPv6_addresses数组 |
| 邻居发现 | 无 | neighbor_discovery_setup结构 |
| DNS | primary_DNS/secondary_DNS(整数) | primary_DNS_address/secondary_DNS_address(串) |
| 流量类 | 无 | traffic_class(DSCP) |
说明:对照表基于两篇原文属性,为工程视角的归纳(非蓝皮书原文逐字句),帮助主站统一处理双栈。
示例 8:IPv6 地址的三种作用域(背景,informative)
蓝皮书原文(IPv6 addressing,informative):“Global Unicast is a routable address in the whole internet… Unique Local Unicast is an address only applicable to local network… Link Local Unicast is a unicast address allowed for a link local (without router)… Multicast is an address assigned to different devices…”
- Global Unicast:全球可路由,组成 = IANA 分配的全局前缀 + 网络管理员分配的 SID(子网 ID)+ 接口标识(可由 MAC 经 modified EUI-64 生成、或 DHCPv6 分配、或手动);
- Unique Local Unicast:仅本地网络有效,不可在外部路由;
- Link Local Unicast:仅链路本地(无路由器)有效,不可路由出去;
- Multicast:按作用域(Interface-local / Link-local / Admin-local / Site-local / Organization-local / global)分组;
- 蓝皮书明确:“there is no broadcast address defined in IPv6”。
说明:以上为原文 informative 附录的归纳,帮助理解"为什么
unicast_IPv6_addresses里会同时出现链路本地和全局地址"。
示例 9:traffic_class 在 IPv6 头里的位置(背景,informative)
蓝皮书原文(IPv6 header format,informative):“Traffic class is used by originating nodes and/or forwarding routers to identify and distinguish between different classes or priorities of IPv6 packets… the traffic class value is only a notion of prioritization… do not secure the transmission.”
IPv6 头 8 位 Traffic Class = 高 6 位 DSCP + 低 2 位 CU(当前未用)。本类只ManagedTraffic class;Version / Flow label / Payload length / Next header / Hop limit / 源目的地址均Not managed(由设备协议栈处理)。
5. 工程上容易踩的坑
- IPv4 与 IPv6 地址数据类型完全不同:
IPv4 setup用double-long-unsigned(4 字节整数),IPv6 setup用octet-string(16 字节)。主站解析两套对象时必须分支,别把 16 字节当 4 字节整数解。 - 每个接口一个实例:双栈设备不是"一个 IPv6 setup 管所有",而是每个网络接口各一个;枚举对象列表时别漏掉第二个接口。
address_config_mode对所有地址通用:改一个模式,单播/组播/网关/DNS 一起变——想"网关手动、单播自动"做不到,要重新设计。- 写空数组 = 清空:
unicast_IPv6_addresses等写回array of 0 elements是"重置全部地址"的语义,不是"不动",别误用。 - DNS 未配置 = octet-string 长度 0:
primary_DNS_address长度为 0 表示没配,不是"0.0.0.0"。 traffic_class只管 DSCP 高 6 位:其余 IPv6 头字段(Version/Flow label/Payload length/Next header/Hop limit/源目的地址)本类都不管(见示例 9 的 informative 对照)。- ND 模式才需要配
neighbor_discovery_setup:Manual/DHCPv6 下这组参数基本用不上,但对象里它始终存在,别以为"没配 ND 就不用管这个属性"。 - 地址是 16 字节,不是字符串:设备对象列表里看到的是 16 字节 octet-string,缺省值用
::记法是人类可读形式,链路层只认那 16 字节。 - IPv6 没有广播地址:蓝皮书明确“there is no broadcast address defined in IPv6”。需要"一对多"只能用
multicast_IPv6_addresses,别去找 broadcast 概念。
参考资料(informative,非类定义):蓝皮书在
IPv6 setup末尾附了"IPv6 header vs IPv6 IC"对照表——本类只管 Traffic class,Version / Flow label / Payload length / Next header / Hop limit / 源目的地址均 Not managed;可选扩展头(Hop-by-Hop / Destination / Routing / Fragment / Security/AH+ESP)也均 Not managed。这些由设备 IPv6 协议栈自己处理,COSEM 对象不碰。
6. 小结 & 下期预告
本篇要点:
IPv6 setup(48) 建模 IPv6 网络层,每个接口一个实例,与IPv4 setup(42) 组成双栈;- 地址统一用16 字节 octet-string(RFC 3513/4291),单播/组播/网关都是
array of octet-string; address_config_mode(0 自动/1 DHCPv6/2 手动/3 ND)对所有地址通用;traffic_class(0–63)只对应 IPv6 头 Traffic Class 的 DSCP 高 6 位;neighbor_discovery_setup给出 ND 协议的 RS 重试/RA 周期参数;- 两个 optional 方法
add_IPv6_address/remove_IPv6_address用structure{type, address}增删,新地址自动追加到末尾。
下一篇(第 37 篇):S-FSK Phy&MAC set-up(class_id = 50)—— 把视角从 IP 网络切到电力线载波(PLC)物理层:S-FSK(IEC 61334)这种慢速、可靠的窄带 PLC 技术,它的物理层+MAC 层参数怎么建模(频率、增益、MAC 地址、中继、同步)。
参考资料:DLMS UA《Blue Book Ed.16 Part 2 – COSEM interface classes》,IPv6 setup(class_id = 48, version = 0) 章节;文中属性、数据类型、Short name 偏移、方法与引文均与原文一致;示例中的 OBIS、地址字节、配置取值为帮助理解而构造(标注"示例/非蓝皮书原文",实际以设备对象列表为准);IPv6 头对照表等属原文 informative 附录。