SDNLAB群分享(四):利用ODL下发流表创建VxLAN网络

今天想跟大家分享如何通过ODL控制器下发流表来创建VxLAN网络。ODL作为当前流行的控制器,已经有广泛的应用。基于ODL提供了丰富的北向接口,使得应用对网络有了更好的掌控。我们为什么需要研究VxLAN网络,VxLAN网络现在已经成为多数据中心网络的解决方案,提供丰富的网络功能,比如更多的租户数量、虚拟机迁移、IP冲突等问题得到有效解决。

一.实验目的

通过本次分享,你将会了解到以下内容:

  • 构建VxLAN网络的基本步骤。
  • Mininet构建网络拓扑。
  • ODL北向接口Restconf的使用。
  • XML格式的流表创建

二.实验准备

  • Mininet虚拟机:实验中使用mininet-2.2.1-150420-ubuntu-14.04-server-amd64
  • VMware Workstation:加载Mininet虚拟机、运行ODL虚拟机。
  • OpenDaylight: Lithium版本(Oracle JDK8)。
  • Wireshark:抓包分析,建议利用远程方式抓包。
  • Postman:发送REST请求。

三.构建环境

实验中共使用了3台虚拟机,如下图所示,VM1和VM2是Mininet虚拟机,VM3运行ODL。

如上图所示,我们所要构建的网络假定VM1和VM2分别代表两个互通的数据中心。颜色不同的host代表不同的租户。假定当前租户RED和BLUE的网络需求如下表,即租户RED和BLUE拥有两个IP和MAC相同的主机,为了在同一个数据中心网络中保证租户间的网络隔离,并且使得租户网络层实现L2通信。

Table1. 租户信息表

DC

Host

IP

MAC

TENANT

VM1

red1

10.0.0.1/8

00:00:00:00:aa:01

RED

blue1

10.0.0.1/8

00:00:00:00:aa:01

BLUE

VM2

red2

10.0.0.2/8

00:00:00:00:aa:02

RED

blue2

10.0.0.2/8

00:00:00:00:aa:02

BLUE

四.实验过程

实验过程分为以下几个步骤:

  • 创建网络拓扑:构建如图1所需要的实验场景。
  • 创建隧道:构建VxLAN网络,建立L2通信隧道。
  • 下发流表:控制器下发流表,演示流表的工作原理。
  • 验证网络:验证VxLAN网络。

1.创建网络拓扑

首先启动三台虚拟机,VM1(192.168.1.10)和VM2(192.168.2.20)是Mininet虚拟机,VM3(192.168.3.30)为安装有ODL的控制器服务器。

启动控制器,安装下列组件。下列组件中虽然不是所有的都是该实验必须的,没有经过仔细的排查。如果运行的环境中已经有安装的组件,可以从列表中忽略。另外,有些组件会与当前的组件有端口占用情况,请仔细查看日子。在VM3上运行ODL,通过karaf控制台执行如下命令进行安装:

$> feature:install odl-l2switch-all odl-ovsdb-all odl-base-all odl-aaa-authn odl-restconf-all odl-nsf-all odl-adsal-northbound odl-mdsal-apidocs  odl-dlux-all
$> feature:install odl-ovsdb-southbound-api odl-ovsdb-southbound-impl odl-ovsdb-southbound-impl-rest odl-ovsdb-southbound-impl-ui odl-openflowplugin-all-li odl-openflowplugin-adsal-compatibility-all

如图1所示的网络部署图,分别启动Mininet虚拟机,复制Mininet的自定义的拓扑文件,并修改如下部分,一下代码为VM1的执行,请根据具体情况执行VM2创建脚本。

$> cp ~/mininet/custom/ topo-2sw-2host.py ~/vm1.py
#修改vm1.py
$> vi ~/vm1.py

仅对添加Hosts和Switches以及Links的部分进行修改,修改如下:

# Add hosts and switches
leftHost = self.addHost( 'red1', ip="10.0.0.1/8", mac="00:00:00:00:aa:01")
rightHost = self.addHost('blue1', ip="10.0.0.1/8", mac="00:00:00:00:aa:01")
leftSwitch = self.addSwitch( 's1' )
# Add links
self.addLink( leftHost, leftSwitch )
self.addLink( leftSwitch, rightSwitch )

修改完成后创建拓扑:

$> sudo mn --controller remote,ip=192.168.3.30 --custom ~/vm1.py

创建完网络拓扑后,对网络拓扑进行相应的检查,比如创建的端口编号,对应端口的链路,以及当前网桥的流表,知道这些细节对后面流表编程有帮助。

检查创建的端口以及端口

mininet> sh ovs-ofctl show s1

检查当前网络链路

mininet> net

检查当前网络端口号

mininet> sh ovs-vsctl -- --columns=name,ofport list Interface

查看manager和controller的状态是否连接控制器成功

mininet> sh ovs-vsctl show

如果没有连接成功,先删除,再重新设置

mininet> sh ovs-vsctl del-manager
mininet> sh ovs-vsctl del-controller s1
mininet> sh ovs-vsctl set-manager tcp:192.168.3.30:6640

设置s1网桥控制器,注意端口号,有的控制器默认端口是6653

mininet> sh ovs-vsctl set-controller tcp:192.168.3.30:6633

2.创建隧道

网络拓扑创建完成后,可以登录ODL的dlux界面查看创建的端口以及拓扑情况。如果在mininet上执行ping命令,ODL会下发相关流表到对应的网桥上。开始创建VxLAN隧道,当然我们也可以用命令行进行创建。命令行创建相对来说比较简单,命令行如下:

> sh ovs-vsctl add-port s1 vtep -- set interface vtep type=vxlan option:remote_ip=192.168.2.20 option:key=flow ofport_request=10

如上面命令所示: 在网桥s1上创建端口vtep并在端口下创建同名的接口,接口类型为vxlan,可选参数中指定隧道的remote_ip为192.168.2.20,key=flow表示隧道的VNI是通过流表来指定,ofport_request=10表示创建默认端口号10的端口作为VxLAN通信端口,如果端口被占用,系统自动分配,该端口号在创建流表时会用到。需要注意的是隧道创建是双向的,即是说在一端创建了VTEP,在另一个所指的remote机器上也应创建相应的vxlan端口。 我们接下来不准备用命令行创建,而是用ODL的北向接口创建隧道。在VM3的服务器上利用Postman依次完成以下操作: 1).获得OVS节点 Postman发送Get请求,并在参数列表中添加Basic Auth,默认为 admin/admin

GET: http://192.168.3.30:8282/ovsdb/nb/v3/node

GET结果返回值如下:

[
  "OVS|192.168.1.10:63344",
  "OVS|192.168.2.20:63647"
]

以上端口分别为OVS实例。分别在VM1和VM2上。 2)创建隧道端口(port) 根据返回的节点,依据上面的创建隧道命名,依次创建端口,接口和隧道,其中node后的参数为Get获得的OVS实例。

POST: http:// 192.168.3.30:8282/ovsdb/nb/v2/node/OVS/192.168.1.10:63344/tables/port/rows

BODY内容如下,parent_uuid是s1的UUID,可以通过相关的REST API获得。

{ 
    "parent_uuid":"4d2742b0-e5d8-4228-8c56-4a283f50038e",
    "row":{ 
        "Port":{ 
                "name":"vtep"
        }
      } 
}

3)创建隧道接口 依然在VM1上创建

POST: http:// 192.168.3.30:8282/ovsdb/nb/v2/node/OVS/192.168.1.10:63344/tables/interface/rows

BODY如下,请根据实际情况调整uuid.

{
    "parent_uuid": "2fdc88be-0908-4738-ae8c-9328aeb4fcc5",
      "row":{
        "Interface":{
            "name":"vtep",
            "type":"vxlan"
      }
    }
}

4)更新隧道配置项的值。 通过Postman的put更新VxLAN的interface的值。注意UUID是interface.

PUT: http:// 192.168.3.30:8282/ovsdb/nb/v2/node/OVS/192.168.1.10:63344/tables/interface/rows/${UUIU}
{ 
    "row":{ 
      "Interface":{ 
              "type":"vxlan",
              "ofport_request":10,
              "options": ["map", 
	[
        ["key","flow"],
        ["local_ip","192.168.1.10"],
        ["remote_ip","192.168.2.20"]
                            	]
                        	]
      } 
    } 
  }

注:只有等Interface创建好后,对属性设置才有效。如果在创建过程中指定属性值,属性值可能不会被写入。

上述过程描述的是利用OpenDaylight的REST接口创建隧道,相对于命令而言显得复杂。如命令行创建隧道一样,在一个节点创建隧道,统一需要对另一个节点创建隧道,是一个双向的操作过程,在实践过程中,请注意根据实际情况对REST中相应的参数进行修改。值得注意的是:REST请求的接口有时用v2,有时用v3,是由于Lithium版本的v3接口实现了部分功能,但当前的v2版本是向下兼容的。

3.下发流表

当隧道建立完毕,对应的网桥中的流表为空,也就是当前OVS对任何流不做处理,下面我们就通过控制器下发流表,让OVS完成我们所需要的功能:

  • 根据端口号为租户设置VNI。
  • 根据MAC地址转发相应的包。
  • 根据IP地址转发相应的包。

以下流表是需要下发到VM1上OVS的s1的网桥中,以完成整个VxLAN网络的建立。当然目前只是针对4个host构建的拓扑网络,相对比较简单。如果大家有兴趣,可以参考OpenStack的Neutron网络中是如何规划VxLAN的流表,其中涉及到了Mac地址学习等。所以当前直接把Mac地址写入到流表。大家可以根据以下流表看出转发包的逻辑,以端口1的包转发为例解释如下:

第1条:端口1的流为其设置VNI为100,并转到下一级流表处理; 第4条:VNI为100的包,如果其目的地址为aa:01,则从1号口出,即转发给red1。 第6条:VNI为100的包,如果目的地址为00:a2, 这将包从隧道端口10发送出去。 第8条:VNI为100的ARP包,网络地址为本地IP,从端口1转出。 第10条:VNI为100的ARP包,网络地址为远端IP,从隧道端口10转出。

table=0,in_port=1,actions=set_field:100->tun_id,resubmit(,1)
table=0,in_port=2,actions=set_field:200->tun_id,resubmit(,1)
table=0,actions=resubmit(,1)

table=1,tun_id=100,dl_dst=00:00:00:00:aa:01,actions=output:1
table=1,tun_id=200,dl_dst=00:00:00:00:aa:01,actions=output:2
table=1,tun_id=100,dl_dst=00:00:00:00:aa:02,actions=output:10
table=1,tun_id=200,dl_dst=00:00:00:00:aa:02,actions=output:10

table=1,tun_id=100,arp,nw_dst=10.0.0.1,actions=output:1
table=1,tun_id=200,arp,nw_dst=10.0.0.1,actions=output:2
table=1,tun_id=100,arp,nw_dst=10.0.0.2,actions=output:10
table=1,tun_id=200,arp,nw_dst=10.0.0.2,actions=output:10
table=1,priority=100,actions=drop

下面将通过ODL的restconf API来下发流表。根据上面的讲述,对于VM1和VM2,都需要下发12条流,如果用命令行,那么只需要将流表保存于文本中,利用ovs-ofctl add-flows命令可以一次性加入,如果用REST API下发流表,则需要逐条发送。

将文本流表转换成XML格式的流表,请参考ODL官方指南,另外大家可以参考ask.opendaylight.org针对该问题的解决方案。此处列举了流表第1条的例子。更完整的例子可以到SDNLAB官方下载。

POST: http://192.168.3.30:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/

Body:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="urn:opendaylight:flow:inventory">
    <flow-name>S1T0F1</flow-name>
    <table_id>0</table_id>
    <id>1</id>
    <installHw>false</installHw>
    <strict>false</strict>
	<priority>10</priority>
    <instructions>
        <instruction>
            <order>0</order>
            <apply-actions>
                <action>
                    <order>0</order>
		<set-field>
		<tunnel>
		<tunnel-id>100</tunnel-id>
		</tunnel>
		</set-field>
                </action>
            </apply-actions>
        </instruction>
        <instruction>
            <order>1</order>
            <go-to-table>
                <table_id>1</table_id>
            </go-to-table>
        </instruction>
    </instructions>
    <match>
        <in-port>1</in-port>
    </match>
</flow>

注:完整Postman流表脚本下载

注:这个是本次实验的重点和难点。由于在网上找不到关于流表的DTD的定义,很多字段靠自己揣摩和反复实验,才知道是否是正确的。更难的是,因为最终的效果必须等到12条流表全部正确,才能知道结果是否正确。

注:实验过程中,有时候流表是错误的,但是POST的消息没有反馈任何错误提示,也是试验中的坑。

4.验证网络

可以通过ping命令对网络进行验证。为了确定租户网络是否隔离,可以尝试分别断开相同MAC地址的网络连接,再尝试ping,看是否能达到预期效果。测试命令如下:

在VM2上断开blue2的链接

mininet> blue2 ip link set dev blue2-eth0 down

在VM1上租户red1 ping 对端主机

mininet> red1 ping 10.0.0.2

注:验证过程中,特别提醒,租户IP最好不要选用10网段,有可能你的网络本身不通,但是遇到10.0.0.1这样的IP可能误解为网络正常。

五.实验结论

ODL提供了丰富的API对底层的转发设备进行控制,可以基于API对网络进行高效的编排和控制。实验中验证的VxLAN网络也具有实际的应用场景,例如OpenStack的Neutron网络是一个很好的案例。相对于本文介绍的实验,在数据中心间构建VxLAN网络更具挑战性,我们期待有从事这方面研究的朋友一起讨论并分享这方面的经验。

Q&A

Q1:安徽-桥 ODL会下发相关流表到对应的网桥上,网桥要自己设置吗? 会到网桥上。你可以通过ovs-ofctl 查询到 通过POST创建的流表。ovs-vsctl show出来通过Post创建的port和interface.

Q2:心随风飞 我想请问下,在你做的实验里,流表中的参数都需要手动制定,包括流表下发。这些动作能否都自动实现呢? 流表中的参数都是属于业务逻辑。比如你要创建100个租户的,那么你的NID就需要规划了。我们利用ODL创建流表,也就是通过编程的方式实现网络的编排。演示过程只是表示ODL可以这么做。所以自动实现是没有问题的。

Q3:新疆-m0ster 我做过VXLAN使用命令行生成隧道的实验,OVS后面的模拟租户通过隧道成功的互通了,这个过程没有流表的下发,它是怎么实现互通的? 你创建隧道的过程中的一个参数 key=flow这个参数没有指定,对吧。默认所有的流表都属于一个租户。所以是没有租户概念的。本实验中体现除了租户隔离的这个功能,所以用了key=flow这个参数,也就是让流表对隧道VNI进行指定。

Q4:如之何 想问下,如果租户自己本身就有几个vlan, 要怎么通过vxlan互通呢? 租户的VLAN有VLAN_ID,那么这个可以通过流表的Modify操作来进行Mapping,转换成VNI。只要租户想通信的网络拥有相同的VNI就没有问题。你可以参考OpenStack的相关流表。比如在OpenStack中,你可以在同一个虚拟路由上创建多个子网,每个子网属于一个VLAN,那么一个vRouter出去后,则属于同一个VNI,那么这些子网是可以相互通信的,就算这些计算节点是分布的。

Q5:大连-吉祥 如何用控制器控制网络中链路的带宽,时延,抖动等qos参数 你的问题我也遇到过,可以参考https://wiki.opendaylight.org/view/OpenDaylight_OpenFlow_Plugin:End_to_End_Flows由于没有官方的XML的流表DTD说明文档,有时候只能靠摸索,然后通过查流表中的参数来验证配置是否正确。但是很遗憾的是,ODL在容错处理上不友好,比如有时候流表的XML参数配置错误,但你POST状态显示成功。

Q6:成都-东风 这个比上次的清楚些老,上次完全坐飞机。初学者感到很费解的,普通交换机二层转发自动通过ARP应答,三层通过IP和网关,现在SDN了难道每一个2层通讯动作都要这么复杂,一个过程就要写那么多条流表?还要事先知道Mac地址? 你的问题很好!你可以参考OpenStack的Neutron网络,它在实现长采用了Mac自学习的方式来配置流表。有兴趣的同学可以去了解如何通过学习Mac地址来简化流表,很好的问题。关于ARP应答,这个就比较复杂,在这里不深入展开,有兴趣可以参考OpenStack的虚拟路由的实现。

Q7:新疆-m0ster 使用命令行创建VXLAN隧道的时候也没有指定VNI信息,当时我就觉得很费解,理论VXLAN支持1600万,这个量体现在哪? 那个1600万就体现在VNI上

Q8:Beyond myself 分享过程中涉及到创建vxlan网络,构建l2 tunnel隧道,odl代码实现过程存在add br-int 和br-tun网桥这些网桥吗 ODL通过Rest API创建 Brige, Port和Interface是机上是操作OVSDB的表。在实例中,VXLAN的port同样是用Post创建的,所以应该没有问题。只是本例中将部分过程省略。

Q9:成都-东风 从刚才的Vxlan配置看也很不复杂,但最初的包转发就一大堆流表需要写?这才2台VM,如果大型数据中心咋办? 你说得对。当然只有增加节点是会下发相关流表。另一方面,前面回答过,也有学习Mac地址的实现方式,请参考OpenStack的Neutron网络中如何实现学习流表的。 Q10:小柠檬 vxlan是解决数据中心vlan-id不够分的问题吗 VxLAN解决 VLAN很多的问题,不只是ID不够分,vxlan 一个是扩展vlan 数 另外是建立l2over l3问题 还设计 unicast muticast mapping 问题 到了multicast 这个模型类似 mvpn了 Q11:Beyond myself 还有就是为每个端口配置规则下发流表的时候,ovsdb api里面有支持检测arp欺骗流表吗,如果想配置这样的流表,我们该如何着手,或者自己写这样的代码 关于ARP欺骗这些,也有很多做攻防的利用SDN方式解决,应该也是通过流表来实现。这方面我没有了解过。

原文发布于微信公众号 - SDNLAB(SDNLAB)

原文发表时间:2015-11-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习算法与Python学习

干货 | Python 爬虫的工具列表大全

源 | 伯乐头条 | 小象 这个列表包含与网页抓取和数据处理的Python库。 网络 通用 urllib -网络库(stdlib)。 requests -网络...

3449
来自专栏happyJared

爬虫进阶:Scrapy抓取boss直聘、拉勾心得经验

关于使用Scrapy的体会,最明显的感受就是这种模板化、工程化的脚手架体系,可以说是拿来即可开箱便用,大多仅需按一定的规则套路配置,剩下的就是专注于编写跟爬虫业...

3942
来自专栏Albert陈凯

2018-10-14 Redisson项目介绍Redisson项目介绍i flym

Rui Gu edited this page <relative-time datetime="2018-05-23T22:07:43Z" title="Ma...

2673
来自专栏张泽旭的专栏

信息管理系统(java)

该项目开发的软件为网络QQ账户信息管理系统软件,是鉴于目前人们QQ的使用领域的增加,QQ信息呈爆炸性增长的前提下人们对自己的QQ信息管理的自动化与准确化的要求日...

3842
来自专栏.net

干货,比较全面的c#.net公共帮助类(Common.Utility)

       网上有各式各样的帮助类,公共类,但是比较零碎,经常有人再群里或者各种社交账号上问我有没有这个helper, 那个helper,于是萌生了收集全部h...

5138
来自专栏编程

Pwnhub 第一次线下沙龙竞赛Web题解析

Pwnhub在8月12日举办了第一次线下沙龙,我也出了两道Web相关的题目,其中涉及好几个知识点,这里说一下。 # 《国家保卫者》 国家保卫者是一道MISC题目...

2018
来自专栏沈唁志

【收藏】Python 爬虫的工具列表大全

2344
来自专栏逸鹏说道

【.NET】UnpackMe!Shielden+DNGuard,双层变异壳 - 脱壳详解

前言:自从脱壳神器de4dot横空出世以来,我们可以看到几乎所有的.net破文中的第一部分就是不管三七二十一把程序丢进去脱壳以及反混淆。可是你真的明白de4do...

1.4K4
来自专栏张善友的专栏

API网关Ocelot 使用Polly 处理部分失败问题

在实现API Gateway过程中,另外一个需要考虑的问题就是部分失败。这个问题发生在分布式系统中当一个服务调用另外一个服务超时或者不可用的情况。API Gat...

2685
来自专栏IT技术精选文摘

程序员必知必会的那些邪恶的脚本

set -o errexit 等价于 set -e,表示有任何错误(命令的返回状态非 0 )时即退出。

1372

扫码关注云+社区

领取腾讯云代金券