EoMPLS (Ethernet over MPLS) 是一种在 MPLS 网络上传输以太网流量的技术。

相较在同一二层域内直接传输以太网流量,它具有如下优势:

  • 易于管理
  • 更完善的 QoS 支持
  • 流量转发路径可控

而相较在 IP 网络上传输以太网流量,MPLS 又具有与现有的电信网络基础设施(LDP,RSVP,BGP 等)高度集成,开销更小(IPv4 首部开销 20 字节起步,MPLS 每个标签占用 4 字节)的优势。

在电信网络中,使用 MPLS 承载流量传输业务比使用 IP 更加流行。

尽管 EoMPLS 有这样那样的优势,但它和我们,普通的 Linux 玩家没有太大的缘分:Linux 并没有原生的 MPLS 伪线支持,而社区对此也没有太多的关注。

幸运的是,目前 Linux 的网络协议栈和现成的工具已经足以支撑静态的 MPLS 伪线。无需额外的编程,只需要一张现成的 MPLS 网络,以及一些命令。

我强烈建议使用 SR-MPLS 组建这张 MPLS 网络,在 SR-MPLS 网络中,我们可以为每个环回接口地址配置全域唯一的标签。这会为我们的 MPLS 伪线业务带来很大的帮助,特别是没有信令的情况下,我们需要手动配置标签。

目前,frr 是在 Linux 上组建 MPLS 网络的最优选择,它支持 SR-MPLS。

关于如何使用 frr 组建 SR-MPLS 网络,请参阅:

网络拓扑

    +-------------------+  +-------------------+
    |    SR Router 1    |  |    SR Router 1    |
    |   default netns   |  |   pw_inter netns  |
    |                   |  |                   |
    |            pw_in ====== pw_out           |
    |                   |  |                   |
    |              pw0 ====== pw0_ns           |
    |                   |  |                   |
    |      can1         |  |                   |
    +-------||----------+  +-------------------+
            ||
            ||
    +-------||----------+
    |                   |
    |  SR-MPLS Network  |
    |                   |
    +-------||----------+
            ||
            ||
    +-------||----------+  +-------------------+
    |      gz1          |  |                   |
    |                   |  |                   |
    |    SR Router 2    |  |    SR Router 2    |
    |   default netns   |  |   pw_inter netns  |
    |                   |  |                   |
    |            pw_in ====== pw_out           |
    |                   |  |                   |
    |              pw0 ====== pw0_ns           |
    +-------------------+  +-------------------+

创建 Netns 和 Veth 对

在 SR Router 1 上执行如下命令:

ip netns add pw_inter
ip link add pw0 type veth peer pw0_ns
ip link add pw_in type veth peer pw_out
ip link set pw0 up
ip link set pw_in up
ip link set pw0_ns netns pw_inter
ip link set pw_out netns pw_inter

进入 pw_inter 并启用各个接口:

ip netns exec pw_inter bash
ip link set pw0_ns up
ip link set pw_out up
exit

将以上步骤在 SR Router 2 上重复一遍。

配置网络接口的 IP 地址

在 SR Router 1 上执行如下命令:

ip addr add 192.168.96.1/24 dev pw0

在 SR Router 2 上执行如下命令:

ip addr add 192.168.96.2/24 dev pw0

在 Netns 内配置 TC 规则

在两个节点上都执行如下命令:

ip netns exec pw_inter bash
ip link show pw0_ns 
ip link show pw_out 
tc qdisc add dev pw0_ns ingress
tc filter add dev pw0_ns ingress matchall \
    action mpls mac_push protocol mpls_uc label 200 \
    action mpls mac_push protocol mpls_uc label (这里填对端环回地址的标签) \
    action vlan push_eth dst_mac (这里填 pw_out 的 mac 地址) src_mac (这里填 pw0_ns 的 mac 地址) \
    action mirred egress redirect dev pw_out
tc qdisc add dev pw_out ingress
tc filter add dev pw_out ingress protocol mpls_uc \
    flower mpls_label 200 mpls_bos 1 \
    action vlan pop_eth protocol teb \
    action mirred egress redirect dev pw0_ns 
exit

配置去往 pw_inter 的回程 MPLS 路由

在两个节点上都执行如下命令:

ip -M route add 200 as 200 dev pw_in

测试

我在我的 SERNET-HET1 节点上进行如下测试,它相当于本文中的 SR Router 1:

root@SERNET-HET1:~# ping 192.168.96.2 -c 4
PING 192.168.96.2 (192.168.96.2) 56(84) bytes of data.
64 bytes from 192.168.96.2: icmp_seq=1 ttl=64 time=217 ms
64 bytes from 192.168.96.2: icmp_seq=2 ttl=64 time=214 ms
64 bytes from 192.168.96.2: icmp_seq=3 ttl=64 time=218 ms
64 bytes from 192.168.96.2: icmp_seq=4 ttl=64 time=213 ms

--- 192.168.96.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 212.652/215.414/217.973/2.166 ms

反过来:

root@SERNET-SJC1:~# ping 192.168.96.1 -c 4
PING 192.168.96.1 (192.168.96.1) 56(84) bytes of data.
64 bytes from 192.168.96.1: icmp_seq=1 ttl=64 time=213 ms
64 bytes from 192.168.96.1: icmp_seq=2 ttl=64 time=213 ms
64 bytes from 192.168.96.1: icmp_seq=3 ttl=64 time=214 ms
64 bytes from 192.168.96.1: icmp_seq=4 ttl=64 time=214 ms

--- 192.168.96.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 212.801/213.423/214.120/0.537 ms
root@SERNET-SJC1:~#

中间节点的抓包: 截图

抓包文件: 2026-03-07-0340.pcapng