SFP 猫棒接管运营商光猫,外加 igmpproxy 跑通 IPTV

缘起
家里那台中国移动给配的 ZTE F663N 光猫,已经服役 6 年多了。
这玩意儿当年我就吐槽过——只有 LAN1 一个千兆口、限制 4 个终端、Wi-Fi 还停留在 2.4GHz 802.11n。当时实在受不了,就有了那篇 《解包和打包中兴光猫配置文件》,写了个工具把 cfg 解包改桥接,套自己的路由器和 AC Wi-Fi,总算把 100M 跑满了。
带宽从最早的 50Mbps 一路升到现在的 500Mbps,光猫这台硬件却没换过,一直在原地扛着。年头一长,老化的迹象就藏不住了:莫名其妙断流、PPPoE 重拨不上来、TR-069 后台时不时被推一份「看似为你好」的配置回来、最近半年甚至到了三五天就得手动重启一次的程度。修一台疲态尽显的运营商光猫,还要继续替它擦屁股,实在没意思。
正好赶上换路由器,挑了一台 BeeconMini SEED AC5——MT7987 SoC、2.5G 双 RJ45、自带 SFP 槽、带 PoE 输出。SFP 槽这个配置就很有意思:插一根 SFP 光猫棒,光纤直接进路由器,运营商那台砖头就可以扔抽屉里了。PoE 输出留着以后扩 AP 不用走砖头电源,这条也是加分项。
顺手再吐槽一句:现在所有运营商的 IPTV 都还在死磕「魔百盒 + 多播 VLAN」这套上古架构。智能电视、Apple TV、安卓盒子早就什么都能装,节目源完全可以做成一个 App,账号鉴权 + DRM 在云端搞定就行——非要塞一个独立硬件 + 多播 VLAN,本质是业务捆绑、硬件 KPI、加上多一道防盗看的物理壁垒。这套配下来网络拓扑直接复杂 N 倍,也是为什么大量用户最后还是认栽用回运营商光猫。这篇就把怎么绕开它记一下。
整体拓扑
flowchart TD
ISP[ISP 光纤]
SFP["HSGQ DFP-34X-2C2
(SFP 光猫棒,烧入运营商克隆 profile)"]
AC5["BeeconMini SEED AC5
SFP 槽 + 2×2.5G + PoE"]
LAN["br-lan
VLAN 6 untagged"]
WAN["pppoe-wan
VLAN 41"]
TR069["tr069
VLAN 46, DHCP"]
IPTV["br-iptv + iptv_mcast
+ igmpproxy"]
AP[AP / 客户端]
NET[公网]
ACS[运营商 ACS]
MBOX["魔百盒
(移动 IPTV)"]
TV[电视]
ISP --> SFP --> AC5
AC5 --> LAN --> AP
AC5 --> WAN --> NET
AC5 --> TR069 --> ACS
AC5 --> IPTV --> MBOX --> TV
SFP 光猫棒:选什么、怎么进

这次用的是 HSGQ DFP-34X-2C2,Realtek RTL960x 方案。选它有两个理由:
- 能刷 ODI 固件,telnet 进去用
flash get / flash set直接读写 boot 参数,比改运营商光猫的固件友好十倍。 - 社区资料齐全,OMCI 字段克隆有现成参考。
猫棒的进入方式:
| Item | Value |
|---|---|
| Default IP | 192.168.1.1(无 DHCP,本机配静态 192.168.1.2) |
| 默认账号 | admin / admin |
| Web UI | http://192.168.1.1 |
| Telnet | telnet 192.168.1.1 |
固件用 Anime4000/RTL960x 仓库里的 ODI 系列。我实际刷的是 M114_sfp_ODI_Vlan_220414.tar(2022-04-14 的 VLAN 构建)。
扒运营商参数(克隆原光猫)
要让 OLT 接受这根猫棒,得让它自报家门跟原光猫一模一样。每家运营商的注册逻辑不太一样:
- 广东移动:PLOAM 密码 = LOID(ASCII 转 hex)
- 上海移动:取原光猫的 LOID 当 PLOAM 密码(再加 SN 和 VLAN ID)
需要的字段(下面用 <placeholder> 表示需要替换为实际值):
GPON_SN(如CMHIxxxxxxxx,从原光猫超管页或 OMCI 抓出)GPON_PLOAM_PASSWD(hex 形式,下面会讲怎么算)ELAN_MAC_ADDR(原光猫 LAN MAC)OUI(取 MAC 前 3 字节)- OMCI 相关:
HW_CWMP_MANUFACTURER,HW_CWMP_PRODUCTCLASS,HW_HWVER,OMCI_SW_VER1/2,GPON_ONU_MODEL,OMCI_VEIP_SLOT_ID,OMCI_OLT_MODE
⚠️ 以下命令里所有具体值都是示例占位。实际克隆时请用你自己原光猫的真实参数,不要照抄博客里的字符串——那既不会工作,也不该公开。
最关键的一步是 OMCI 字段——OLT 在 OMCI 协商阶段会校验厂商和型号,对不上就拒绝注册。OLT 看的不是光猫外壳上印的型号,而是它在协商里报上来的那一串字段,所以克隆要从 OMCI 视角抄,不能从用户视角抄。从原光猫的 ctromfile.cfg(解码后的 OMCI/管理配置 XML)能看到 OLT 实际看到的是什么字段,照抄就行。
我家原光猫是 ZTE F663N,但它 OMCI 上
ONU Vendor ID报的是MTKc(MediaTek 芯片),ONU Model是EPON,ONU Hardware Version是PT632V1.0——这些都不能写错。F663N 内部 cfg 怎么解出来的,可以参考我之前那篇 解包打包工具。
MAC_KEY 重生成
HSGQ 固件 V1.0-220304+ 引入了 MAC_KEY,每次改 ELAN_MAC_ADDR 都要重新生成:
1 | echo -n "hsgq1.9aMAC_ADDR_UPPERCASE" | md5sum |
烧入 profile
最后用一组 flash set 把克隆参数刷进去:
1 | flash set PON_VENDOR_ID ZTEG |
⚠️ PLOAM 错了 ONU 会被拒,可恢复;但 SN 克隆错了可能被运营商风控标记。先在小范围验证再上线。
另外提一句合规:克隆 SN/MAC 是灰色地带,本文记的是自家电路上的折腾过程,不是教你去蹭别人的宽带。运营商真要查,PON 口下挂的设备都是看得见的。
猫棒重启后插回 SFP 槽,OLT 收到注册请求,验证通过会下发 PPPoE/IPTV/TR-069 的 service profile。
路由器配 VLAN:先把容易的搞定

下游路由器用的是 SEED AC5(iStoreOS,MT7987),SFP 槽里就是上面那根猫棒,所以从猫棒出来的所有 VLAN 都直接落在 eth1 上。需要识别四个 VLAN:
| VID | 用途 |
|---|---|
| 41 | 互联网(PPPoE 拨号) |
| 46 | TR-069 管理 |
| 48 | IPTV 单播控制(DHCP / 鉴权 / EPG / 回看 / 时移) |
| 900 | IPTV 多播视频流(直播) |
**互联网 / TR-069 这部分是常规操作。**PPPoE 在 OpenWrt 里就是标准配置:
1 | uci set network.wan.proto='pppoe' |
TR-069 类似,DHCP 拿地址但关掉 default route 和 peer DNS,避免污染主路由表:
1 | uci set network.tr069.proto='dhcp' |
到这里互联网部分跑通——PPPoE 拨号、IPv6、CGNAT 全都正常,2.5G 物理口直接打满。
难的是 IPTV。这才是这篇文章的重头戏。
IPTV:以为很简单,结果……
家里有长辈,他们不像年轻人都看网络点播,习惯坐沙发上看电视直播——这也是为什么必须把 IPTV 跑通,不能「算了用网络版凑合」。
最初看这事是真不当回事的。原来那台 F663N 光猫上有一个独立的 IPTV LAN 口,运营商出厂时就把对应的 VLAN、PPPoE/IPoE、组播参数都在光猫内部配好了,魔百盒直接插那个口就能开机看直播,用户根本不需要知道 VLAN 48、VLAN 900 这些东西的存在。所以我换猫棒的时候很自然地想:那不就是把这一个口的逻辑挪到自己路由器上吗?给机顶盒拉一个 VLAN,配下 DHCP,应该半小时搞完。
结果整整折腾了一天。
第一阶段:只配 VLAN 48,发现少了点东西
最初的想法很朴素:VLAN 48 是单播控制,VLAN 900 是多播视频,先把 VLAN 48 弄通看看魔百盒能不能开机。
把 eth1.48 起一个接口、放一个 br-iptv、给魔百盒一个 DHCP——很顺利就跑起来了:
- ✅ 魔百盒能开机、能登录、能鉴权
- ✅ 频道列表、EPG 正常加载
- ✅ 回看正常、时移正常(这俩走 HTTP 单播,VLAN 48 就够了)
- ❌ 直播没画面
奇了怪了,回看都能看,怎么直播反而不行?看了一下才反应过来:直播走的是组播,封装在 VLAN 900 里,单纯把 VLAN 48 通了根本没把直播流喂下来。
试过的弯路(避坑)
在搞清楚要上 igmpproxy 之前,我先试了两条看起来更省事的路子,都不通,记下来给后人避坑:
弯路 A:VLAN 48 + VLAN 900 都做 untagged 扔同一个桥
直觉上是把所有 IPTV 流量都堆给魔百盒,让它自己处理。结果魔百盒同时从 VLAN 48 和 VLAN 900 收到 DHCP 响应,拿到两个 IP,状态机直接卡住——注册不上 IPTV 平台。
弯路 B:在 AC5 的交换芯片上把 LAN6 配两个 untagged VLAN
打算让交换机硬件层面就把两个 VLAN 都送到魔百盒口。结果发现 AC5 的 eth1 交换芯片不支持同一个端口配置两个 untagged VLAN——这是硬件限制,VLAN ingress 表里一个 port 只能落到一个 PVID。换句话说,想「魔百盒口同时收 VLAN 48 和 VLAN 900 的 untagged 帧」在 MT7987 这套交换芯片上根本配不出来。
走完这两条死路之后才确认:多播必须在路由器上做 L3 处理,不能指望硬件 L2 解决。
第二阶段:L2 桥跨 VLAN flood——还是不行
下一个直觉:把 eth1.48(控制 VLAN)和 eth1.900(多播 VLAN)扔进同一个 bridge br-iptv,开 IGMP snooping,让多播在桥里 flood 给魔百盒——这跟原 F663N 内部 IGMP-Proxy 的逻辑大致是一样的。
这套在 MT7987 上根本不工作。魔百盒能拿单播 IP,能登录,但选频道之后还是没画面。
抓包发现:
eth1.900 RX哗哗地涌进多播包(一个频道几百 kB/s)eth1.48 TX几乎纹丝不动bridge mdb show dev br-iptv全空——即使魔百盒在发合法的 IGMP v2 report
三个原因,每个都能让你怀疑人生:
MTK PPE / hwnat 在劫持流量。iStoreOS 默认
flow_offloading_hw=1,硬件加速会在 Linux bridge 之前就把多播包消化掉。即便multicast_snooping=0让桥强制 flood,硬件这层也拦着不放。桥的 IGMP snooping
mdb表始终空的。桥本身没 IP,querier 源 IP 是0.0.0.0,snooping 模块在这种状态下不会正确学习魔百盒的 join report。同 trunk 的 split-horizon:魔百盒和 carrier 都通过同一根物理 eth1 走 VLAN 48 上来,Linux bridge 默认不会把流量送回入口端口(除非开 hairpin),所以即便桥成功转发,魔百盒也收不到 carrier 的回包。
结论:这套必须上 L3,让内核多播路由(MFC)来干这事,绕开桥和硬件加速。
第三阶段:igmpproxy L3 方案
整体思路:
flowchart TD
MBOX["魔百盒
(VLAN 48 untagged, 接交换机 LAN6)"]
BR["br-iptv
192.168.99.1/30, 仅含 eth1.48
(downstream)"]
PROXY(["igmpproxy
(kernel MFC)"])
UP["eth1.900
10.0.0.2/24, 独立 L3 接口
(upstream)"]
CARRIER[Carrier 多播头端]
MBOX --> BR
BR --> PROXY
PROXY --> UP
UP --> CARRIER
/etc/config/network 关键部分:
1 | # br-iptv 只放魔百盒这一侧 |
防火墙加一个区让两边互通:
1 | config zone |
最重要:硬件 flow offload 必须关掉:
1 | uci set firewall.@defaults[0].flow_offloading_hw='0' |
/etc/config/igmpproxy:
1 | config igmpproxy |
1 | /etc/init.d/igmpproxy enable |
收尾的坑:altnet 不能写 0.0.0.0/0
第一遍配的时候我图省事在 upstream 和 downstream 两边都写了 altnet 0.0.0.0/0,igmpproxy 死活不工作,日志一直在刷:
1 | warn igmpproxy: No interfaces found for source 100.98.x.y |
ip mroute show 永远是 Iif: unresolved。
原因在 igmpproxy 0.4 的 getIfByAddress() 实现:它用最长前缀匹配来决定 IGMP 报文是从哪个 phyint 进来的。两边都是 0.0.0.0/0(mask = 0),两个接口都「匹配」但优先级一致,函数返回 NULL,IGMP 报文直接被拒收。
修法是给两边各自一个能区分来源 IP 的具体段:
- upstream
eth1.900:altnet 183.235.0.0/16—— carrier 多播头端的源段(用tcpdump -i eth1.900 -nn 'multicast'实测确认) - downstream
iptv(br-iptv):altnet 100.64.0.0/10—— 运营商 CGNAT 大段(实测魔百盒拿到的就是100.98.x.x之类的 IP,全在这段里)
改完重启 igmpproxy,立即就工作了。
验证
1 | # 内核 MFC 已建立路由 |
电视画面瞬间出来,遥控切台也丝滑。
三层心法
把这件事拆成三个层次记住:
运营商 PON 鉴权 = 克隆 OMCI 字段。SN / PLOAM 是公开的克隆要点,OMCI 那一堆
HW_CWMP_*、OMCI_SW_VER*、GPON_ONU_MODEL才是 OLT 真正用来识别「你是不是合法设备」的地方。PPPoE / TR-069 / IPTV 单播 = L2 透传就行。VLAN 41/46/48 在 OpenWrt 上当成普通 8021q sub-interface 处理,连标准 NAT/DHCP 流程都能跑。注意 IPTV 的回看和时移都走单播 HTTP,只配 VLAN 48 就够;唯独直播是多播,必须额外处理 VLAN 900。
多播 IPTV ≠ L2 转发。在 MT7987 这类带 PPE 硬件加速的平台上,L2 桥跨 VLAN flood 多播是不工作的。正解是 L3:igmpproxy + 关 hwnat + altnet 写具体段。
附带踩出来的几条经验:
getIfByAddress的最长前缀匹配会让0.0.0.0/0成为陷阱,写 altnet 一定要用能区分来源的具体段。flow_offloading_hw默认开但对多播路由有害,软件 flow offload (flow_offloading=1) 是安全的——这个组合是 MT7987 这一代 SoC 上多播工作的硬条件。multicast_querier=1在桥没 IP 的情况下源会变成0.0.0.0,许多机顶盒和 snooping 模块对这种 query 处理有问题——交给 igmpproxy 做 querier 反而更可靠。- 别试图在交换芯片上让一个端口同时 untagged 两个 VLAN,至少 MT7987 这套硬件不支持。
后记
跑了一段时间,记录一下实际效果:
- 那台 ZTE F663N 已经收进抽屉吃灰,光纤直接进 AC5 的 SFP 槽。
- PPPoE 的 500M 带宽轻轻松松跑满,2.5G 内网也能稳定 280MB/s+。
- 直播 4K 频道流畅、回看时移都正常,切台没感觉跟原来有什么不同——这条最关键,验收通过。
- 不再需要每隔几天去重启那台砖头光猫,省心。
回头看,这次折腾的本质是把光猫这个最后的「运营商飞地」也收进自己的网络管理体系里。六年前那次解 cfg 改桥接是软改,治标;这次直接把硬件也换掉,治本。下一步可能是 PoE 那条 LAN 出去带个吸顶 AP,全屋 Wi-Fi 6E 也升一升,不过那是另一篇文章了。
参考
- HSGQ DFP-34X-2C2 猫棒文档:hack-gpon.org/ont-odi-realtek-dfp-34g-2c2/
- ODI 固件:github.com/Anime4000/RTL960x
- ZTE OMCI 克隆参考:github.com/Septrum101/zteOnu
igmpproxy源码:github.com/pali/igmpproxy- OpenWrt IGMP/Multicast 文档:openwrt.org/docs/guide-user/network/wan/multicast
- 我之前那篇:《解包和打包中兴光猫配置文件》