多协议标签交换(MPLS)解释

米米狗· 2019-08-12
本文来自 Medium ,作者 米米狗

这个博客分为两个子部分,第一部分我们将了解MPLS到底是什么,第二部分我们将看到如何使用Golang制作MPLS数据包。


多协议标签交换(MPLS)并不是一项新技术。它已经存在了好几年了。许多人必须熟悉数据如何以网络数据包的形式从一个地方传输到另一个地方。这些数据包包含源IP地址和目标IP地址。数据包通过其间的多个路由器传递,这些路由器包含路由表,该路由表向数据包提供下一跳信息,然后数据包最终到达目的地。这就是IP转发的工作原理。它是第3层协议。

MPLS转发不同于IP转发,因为代替IP地址,转发是基于分组上存在的标签完成的,因此称为标签交换。它是多协议的,因为它支持多种协议,如Internet协议(IP),异步传输模式(ATM)和帧中继网络协议。我们稍后会看到MPLS转发是如何完成的。

如果熟悉计算机网络,则必须知道TCP / IP模型中有5个层。MPLS层位于模型的第2层和第3层之间,即数据链路和网络层。这就是为什么它也被称为2.5层协议或“垫片”协议。

MPLS报头为32位。它包含以下信息: -

  1. 标签:标签字段为20位,因此标签可以采用0到2 ^ 20-1或1,048,575之间的值。但是,前16个标签值即0到15免除正常使用,因为它们具有特殊含义。

  2. 实验(Exp):三位保留为实验位。它们用于服务质量(QoS)。

  3. 堆栈底部(BoS):网络数据包可以有多个MPLS标签,这些标签彼此堆叠在一起。为了确保哪个MPLS标签位于堆栈底部,我们有一个1位的BoS字段。仅当该特定标签位于堆栈的底部时该位为高(即值1),否则其值保持为0。

  4. 生存时间(TTL):最后8位用于生存时间(TTL)。该TTL具有与IP报头中存在的TTL相同的功能。它的值在每一跳时简单地减少1。TTL的工作是通过在数据包的值为零时丢弃数据包来避免数据包卡在网络中。

现在我们将看到典型的MPLS网络如何:

MPLS网络包含标签交换路由器(LSR)。这些路由器能够理解MPLS标签以及接收和发送带标签的数据包。

MPLS网络中存在三种标签交换路由器: -

  1. Ingress LSR:这些路由器出现在MPLS网络的开头。他们的工作是接收未标记的IP数据包并将标签推到其上。

  2. 出口LSR:这些路由器位于MPLS网络的末端。他们的工作是从传入的数据包中弹出标签并将数据包作为IP数据包转发。

  3. 中间LSR:这些路由器位于上述两个路由器之间。他们的工作是接收带标签的数据包,交换数据包的标签并将其转发到下一跳。它们负责数据包的MPLS转发。

入口和出口也称为边缘路由器

因此,在任何特定路由器处,标签的三个步骤PUSH,POP或SWAP中的任何一个发生。

标签交换路径(LSP)

标签交换路径(LSP)可以定义为在MPLS网络内传输分组的标签交换路由器(LSR)的序列。基本上,LSP是数据包在传输过程中所采用的预定义路径。LSP中的第一个LSR是Ingress LSR,类似LSP中的最后一个LSR是Egress路由器,其后是中间的LSR。

这里的主要内容是,在IP转发中,没有固定路径,数据包必须遵循,而在MPLS转发中,我们预定义路径,即在数据包传输过程中必须遵循的LSP。

MPLS转发

因此,现在我们可以很容易地看到如何在网络中转发MPLS数据包,并结合我们学到的上述概念。

当网络数据包进入MPLS网络时,入口路由器会在其上面放置一个标签。该标签对应于分组需要遵循的特定路径,即LSP。不同的LSP对应不同的标签栈。使用诸如标签分发协议(TDP),标签分发协议(LDP)和资源预留协议(RSVP)的不同协议来分发标签。

与IP转发一样,每个路由器在MPLS网络中类似地包含路由表,每个LSR包含标签转发信息库(LFIB)。此信息库指导LSR将标签与其相应的传出标签交换,从而允许数据包通过网络传输。这里的主要内容是路由器只需要在传入数据包的顶部看到标签,它不关心数据包内存在的IP地址(源和目标),从而允许更快地通过网络路由。

以下是LFIB中存在的信息的示例

在LSP的末尾,Egress LSR弹出数据包的标签,数据包被路由为普通的IP数据包。

这是高级视图如何进行MPLS转发以深入了解您可以参考<a href="https://doc.lagout.org/network/Cisco/CCIE/CCIE%20SP/CiscoPress%20-%20MPLS%20Fundamentals.pdf" style="box-sizing: inherit; text-decoration-line: none; -webkit-tap-highlight-color: transparent; background-repeat: repeat-x; background-image: url("data:image/svg+xml;utf8,"); background-size: 1px 1px; background-position: 0px calc(1em + 1px);">CISCO MPLS基础书籍

制作MPLS数据包

转到下一部分,我们将在这里看到如何使用Golang创建MPLS数据包。为什么Golang?因为它具有高度可扩展性,具有内置的并发性和对服务器端编程的强大支持,并且还具有一组很棒的库。我们将使用<a href="https://github.com/google/gopacket" style="box-sizing: inherit; text-decoration-line: none; -webkit-tap-highlight-color: transparent; background-repeat: repeat-x; background-image: url("data:image/svg+xml;utf8,"); background-size: 1px 1px; background-position: 0px calc(1em + 1px);">GoPacket库来制作数据包。

所以这里是代码

package main    
import (    
"fmt"    
"net"    
"encoding/hex"    
"github.com/google/gopacket"    
"github.com/google/gopacket/layers"    
)    
func getMplsPacket() []byte {    
ipaddr := net.ParseIP("1.1.1.1")    
payload := gopacket.Payload("payload")    
udp := &layers.UDP{SrcPort: layers.UDPPort(2000), DstPort: layers.UDPPort(3000)}    
ip := &layers.IPv4{Version: 4, DstIP: ipaddr, SrcIP: ipaddr, Protocol: layers.IPProtocolUDP}    
hw, _  := net.ParseMAC("c8:b3:02:c0:b9:1b")    
eth := &layers.Ethernet{SrcMAC: hw, DstMAC: hw, EthernetType: 0x8847}    
mpls := &layers.MPLS{    
Label:        17,    
TrafficClass: 0,    
StackBottom:  true,    
TTL:          64,    
}    
if err := udp.SetNetworkLayerForChecksum(ip); err != nil {    
return nil    
}    
buffer := gopacket.NewSerializeBuffer()    
if err := gopacket.SerializeLayers(buffer,    
gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true},    
eth, mpls, ip, udp, payload); err != nil {    
return nil    
}    
str := hex.EncodeToString(buffer.Bytes())    
fmt.Println(str)    
return buffer.Bytes()    
}    
func main() {    
fmt.Println(getMplsPacket())    
}

代码是不言自明的,我们正在为IP,UDP,Payload,MPLS和以太网创建单独的层,并按以下顺序将这些层堆叠在一起并返回创建的字节对象。

MPLS数据包层堆栈

如果我们执行上面的代码,我们将获得以下输出

c8b302c0b91bc8b302c0b91b88470001114045000023000000000011b6c7010101010101010107d00bb8000f2b157061796c6f616400000000000000

这是形成的数据包的输出,我们可以使用<a href="https://hpd.gasmi.net/" style="box-sizing: inherit; text-decoration-line: none; -webkit-tap-highlight-color: transparent; background-repeat: repeat-x; background-image: url("data:image/svg+xml;utf8,"); background-size: 1px 1px; background-position: 0px calc(1em + 1px);">https://hpd.gasmi.net/或Wireshark 等在线工具解码数据包。

对上述数据包进行解码会得到预期的以下结果。

整个代码也可以在我的Github 存储库中找到