1. GRE
1.1 概念
GRE全称是Generic Routing Encapsulation,是一种协议封装的格式,具体格式内容见:
协议封装指的是用一种格式的协议封装另一种格式的协议。我们熟悉的TCP/IP协议可以看成是一种封装:TCP传输层协议被网络层的IP协议封装,通过IP协议来进行传输。还有比如很有用的IP SAN,就是通过IP协议封装scsi协议,使得我们可以直接通过IP网络来进行磁盘数据的传输。对于这两个例子来说,前一种封装的目的是通过分层来严格的区分协议的设计,使得具体的协议设计的时候可以更加的清晰,而后者则是为了使用现有的设施,方便厂商推广自己的产品,同时通过两种协议的结合产生更多的功能。对于GRE来说,应是偏向后者的一种封装。
GRE的目的是设计一种通用的封装格式,所以如果将它与一些为特定目的进行设计的封装协议比较,那么GRE是没有太多优势的。
A GRE encapsulated packet has the form: --------------------------------- | | | Delivery Header | | | --------------------------------- | | | GRE Header | | | --------------------------------- | | | Payload packet | | | ---------------------------------
在GRE中,需要被传输和封装的报文称之为payload packet,而用于封装和传输的协议则成为delivery protocol。GRE在封装的时候,除了payload和delivery协议的header外,会生成一个GRE header。GRE header + payload一起被delivery协议封装用于传输,GRE header会包含payload的一些信息,包括checksum、version、payload的协议类型等。可以看到,通过这个GRE header的协议类型字段,我们可以做很多的事情。既然底层的delivery协议是用于传输的,那么A和B通信的时候delivery协议可以看成是个邮局送信火车,虽然很重要,但是对于业务理解来说没有其运送的信重要。当脱取这一层delivery层后,我们怎么知道信的格式呢?通过GRE header中的协议类型我们就能知道协议类型了,既然知道了协议类型,那么就有能力解析了。
由于GRE是一种通用的格式,我们可以使用GRE进行很多不同种类的封装。比如我们可以使用PPTP协议来进行VPN,可以使用IPv4来包裹IPv6。比较常见的delivery协议一般是IP协议。
不过GRE在设计的时候有一个问题,那就是没有考虑加密。因此现在常见的需要加密的封装一般是用的IPsec协议。
比如说:A主机是在公司,B主机是在家,A网络的地址为192.168.1.1,B网络的地址为192.168.2.1,A如果要和B通信,则需要通过互联网,所以在A连接的路由器RA上,会配置一个tunnel口,tunnel口的信息是(1.1.1.1 -> 2.2.2.2),在B连接的路由器RB上也会配置一个tunnel口,tunnel口的信息是(2.2.2.2 -> 1.1.1.1)。同时在设置好路由的情况下,A发送一个报文给B,报文会首先到RA,RA发现报文需要走互联网,于是通过tunnel口封装,封装的delivery协议的目的地址写的是配置的RB的地址2.2.2.2。报文到了RB后delivery协议被脱去,然后RB根据路由信息转发给B。
()
当A(192.168.1.1) ping B(192.168.2.1)时,报文是如下形式的:
从A到RA
从RA到RB
1.2 Neutron中的GRE
()
- br-tun网桥信息:
[root@NextGen1 ~]# ovs-vsctl show911ff1ca-590a-4efd-a066-568fbac8c6fb[... Bridge br-int omitted ...] Bridge br-tun Port patch-int Interface patch-int type: patch options: {peer=patch-tun} Port br-tun Interface br-tun type: internal Port "gre-2" Interface "gre-2" type: gre options: {in_key=flow, local_ip="192.168.1.100", out_key=flow, remote_ip="192.168.1.101"} Port "gre-1" Interface "gre-1" type: gre options: {in_key=flow, local_ip="192.168.1.100", out_key=flow, remote_ip="192.168.1.102"}
- VM1(10.0.0.1) pings VM2(10.0.0.2) in different nodes :
Before VM1 can create an ICMP echo request message, VM1 must send out an ARP request for VM2’s MAC address. A quick reminder about ARP encapsulation – It is encapsulated directly in an Ethernet frame – No IP involved (There exists a base assumption that states that ARP requests never leave a broadcast domain therefor IP packets are not needed). The Ethernet frame leaves VM1’s tap device into the host’s br-int. br-int, acting as a normal switch, sees that the destination MAC address in the Ethernet frame is FF:FF:FF:FF:FF:FF – The broadcast address. Because of that it floods it out all ports, including the patch cable linked to br-tun. br-tun receives the frame from the patch cable port and sees that the destination MAC address is the broadcast address. Because of that it will send the message out all GRE tunnels (Essentially flooding the message). But before that, it will encapsulate the message in a GRE header and an IP packet. In fact, two new packets are created: One from 192.168.1.100 to 192.168.1.101, and the other from 192.168.1.100 to 192.168.1.102. The encapsulation over the GRE tunnels looks like this:
To summarize, we can conclude that the flow logic on br-tun implements a learning switch but with a GRE twist. If the message is to a multicast, broadcast, or unknown unicast address it is forwarded out all GRE tunnels. Otherwise if it learned the destination MAC address via earlier messages (By observing the source MAC address, tunnel ID and incoming GRE port) then it forwards it to the correct GRE tunnel.
- br-tun流表:
[root@NextGen1 ~]# ovs-ofctl dump-flows br-tunNXST_FLOW reply (xid=0x4): cookie=0x0, duration=182369.287s, table=0, n_packets=5996, n_bytes=1481720, idle_age=52, hard_age=65534, priority=1,in_port=3 actions=resubmit(,2) cookie=0x0, duration=182374.574s, table=0, n_packets=14172, n_bytes=3908726, idle_age=5, hard_age=65534, priority=1,in_port=1 actions=resubmit(,1) cookie=0x0, duration=182370.094s, table=0, n_packets=0, n_bytes=0, idle_age=65534, hard_age=65534, priority=1,in_port=2 actions=resubmit(,2) cookie=0x0, duration=182374.078s, table=0, n_packets=3, n_bytes=230, idle_age=65534, hard_age=65534, priority=0 actions=drop cookie=0x0, duration=182373.435s, table=1, n_packets=3917, n_bytes=797884, idle_age=52, hard_age=65534, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20) cookie=0x0, duration=182372.888s, table=1, n_packets=10255, n_bytes=3110842, idle_age=5, hard_age=65534, priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,21) cookie=0x0, duration=182103.664s, table=2, n_packets=5982, n_bytes=1479916, idle_age=52, hard_age=65534, priority=1,tun_id=0x1388 actions=mod_vlan_vid:1,resubmit(,10) cookie=0x0, duration=182372.476s, table=2, n_packets=14, n_bytes=1804, idle_age=65534, hard_age=65534, priority=0 actions=drop cookie=0x0, duration=182372.099s, table=3, n_packets=0, n_bytes=0, idle_age=65534, hard_age=65534, priority=0 actions=drop cookie=0x0, duration=182371.777s, table=10, n_packets=5982, n_bytes=1479916, idle_age=52, hard_age=65534, priority=1 actions=learn(table=20,hard_timeout=300,priority=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]),output:1 cookie=0x0, duration=116255.067s, table=20, n_packets=3917, n_bytes=797884, hard_timeout=300, idle_age=52, hard_age=52, priority=1,vlan_tci=0x0001/0x0fff,dl_dst=fa:16:3e:1f:19:55 actions=load:0->NXM_OF_VLAN_TCI[],load:0x1388->NXM_NX_TUN_ID[],output:3 cookie=0x0, duration=182371.623s, table=20, n_packets=0, n_bytes=0, idle_age=65534, hard_age=65534, priority=0 actions=resubmit(,21) cookie=0x0, duration=182103.777s, table=21, n_packets=10235, n_bytes=3109310, idle_age=5, hard_age=65534, priority=1,dl_vlan=1 actions=strip_vlan,set_tunnel:0x1388,output:3,output:2 cookie=0x0, duration=182371.507s, table=21, n_packets=20, n_bytes=1532, idle_age=65534, hard_age=65534, priority=0 actions=drop
- table表流程
- 在openstack中主要是通过ovs,ovs支持GRE。通过GRE,VM之间的ARP、IP报文都能在GRE的封装下通过IP网络进行传递。不同的网络通过GRE header中的tunnel id号区别。由于ovs支持openflow协议,为了效率和性能,mac和GRE的路由关系会存放在ovs的流表中。从链接中的文章可以看出,GRE有一个缺点,那就是每新增一个计算节点,都需要其和所有其他计算节点以及network控制器建立GRE链接。在计算节点很多的时候会有性能问题。
2. vxlan
2.1 概念
相比于GRE的通用性,VXLAN主要用于封装、转发2层报文。VXLAN全称Virtual eXtensible Local Area Network,简单的说就是扩充了的VLAN,其使得多个通过三层连接的网络可以表现的和直接通过一台一台物理交换机连接配置而成的网络一样处在一个LAN中。其将二层报文加上个vxlan header,封装在一个UDP包中进行传输。vxlan header会包括一个24位的ID(称为VNI),含义类似于VLAN id或者上面提到的GRE的tunnel id。在上面GRE的例子中,是通过路由器来进行GRE协议的封装和解封的,在VXLAN中这类封装和解封的组件有个专有的名字叫做VTEP。相比起VLAN来说,好处在于其突破了VLAN只有4094子网的限制,同时架设在UDP协议上后其扩展性提高了不少(因为UDP是高层协议,屏蔽了底层的差异,换句话说屏蔽了二层的差异)。
表面上看VXLAN和GRE区别不大,只是对delivery协议做了限定,使用UDP。但是实际上在协议的交互动作上面还是有区别的。和上面的例子一样,假如主机A和主机B想通信,那么A的报文会的被VTEP封装,然后发往连接B的VTEP。在上面的例子中类似于VTEP的角色是由路由器来充当的,而且路由器的两端的地址是配置好的,所以RA知道RB的地址,直接将报文发给RB即可。但是在VXLAN中,A的VTEP并不知道B的VTEP在哪,所以需要一个发现的过程。如何发现呢?VXLAN要求每个VNI都关联一个组播地址。所以对于一次ARP请求,A的VTEP会的发送一个组播IGMP报文给所有同在这个网络组中的其他VTEP。所有的订阅了这个组播地址的VTEP会的收到这个报文,学习发送端的A的MAC和VTEP地址用于以后使用,同时VTEP会将报文解析后比较VNI,发送给同VNI的主机。当某个主机B的IP和ARP中的一样时,其会的发送ARP应答报文,应答报文通过B的VTEP按照类似的流程发送给A,但是由于B的VTEP已经学习到了A的MAC地址,因此B的VTEP直接就可以发送给A的VTEP,而不需要再走一遍通过IGMP的组播过程了。
从这个例子可以看出,VXLAN屏蔽了UDP的存在,上层基本上不感知这层封装。同时VXLAN避免了GRE的点对点必须有连接的缺点。由于需要IGMP,对于物理交换机和路由器需要做一些配置,这点在GRE是不需要的。
vxlan报文格式:
()
()
报文走向:
2.2 Neutron中的vxlan
()
vxlan的br-tun流表与上面GRE类似。
2.3 需要vxlan的原因
- vlan的数量限制
- 物理网络基础设施的限制
- TOR交换机MAC表耗尽
2.4 vxlan与GRE的主要区别
若br-tun之间两两点对点的连接,通信封包为GRE格式,那么这样的网络环境就是OVS-GRE网络模式。同理,若br-tun之间跑三层网络协议,封包方式为VXLAN格式,这样的网络环境就是OpenStack-Neutron-OVS-VXLAN网络模式。对于GRE和VXLAN网络模式而言,可以抽象地将每个br-tun看成隧道端点,有状态的隧道点对点连接即为GRE;无状态的隧道使用UDP协议连接则为VXLAN。
() 两者的区别还是不太懂?
QA:
- vxlan网络指定的segment id 就是vxlan的tunnel id,local vlan号则由neutron代码按序生成,tunnel id 与 local vlan 由br-tun流表来保证一一对应。
而由于br-tun的port与trunk0的tunnel-bearing子接口相连,tunnel-bearing子接口也带vlan id,该vlan id放在Delivery Header的vlan id中,是为了与管理网络隔离。
- local vlan 与 外部 vlan 区别
两个VM所属segment id 一样,位于不同server上时,local vlan id 不一定一样。local vlan只是作用于当前server上,用于隔离该server上的其他VM。
- br-tun中有关GRE/Vxlan的port是如何生成的?
ovs-agent启动时,会上报自己的tunnel local ip 给neutron server ,然后neutron server 会发rpc消息给其他所有 ovs-agent ,在br-tun上建立相关联的port。