提高SDN控制器的拓扑发现性能

SDN网络的一大特点就是资源由控制器集中管理,控制器管理网络,最基本的当然需要知道网络的拓扑,而网络拓扑可能时时发生变化,所以控制器需要时时监测,对于整个网络来说,控制器担负了太多的计算任务,所以如果能够帮助控制器减压,则会提高整个网络的性能。本篇文章将以ryu控制器为例,首先介绍传统网络和现在SDN网络的拓扑发现原理,然后介绍改进算法,最后讲解改写后的代码逻辑。

一. LLDP拓扑发现原理

传统网络中的链路发现协议为LLDP(Link Layer Discovery Protocol),LLDP允许局域网中的结点告诉其他结点他自己的capabilities和neighbours。在传统以太网交换机中,交换机从自己的每个端口发送LLDP数据包,这个数据包不会被其他交换机转发,寿命只有一跳,LLDP负载被封装在以太网帧中,结构如下图,其中深灰色的即为LLDP负载,Chassis ID TLV, Port ID TLV和Time to live TLV三个是强制字段,分别代表交换机标识符(在局域网中是独一无二的),端口号和TTL。这个数据发出并被邻居结点收到之后进行解析,就可以知道这条链路的源目的交换机以及源目的接口。

二. ryu拓扑发现原理

OpenFlow的官方没有规定标准的拓扑发现方法,现在的OFDP(OpenFlow Discovery Protocol)利用的仍然是传统网络中的链路发现协议LLDP,接下来介绍ryu如何利用LLDP发现拓扑,假设现在有两个OpenFlow交换机连接在控制器上,如下图,简述拓扑发现步骤(以S1作为主体,S2的类似):

1. SDN控制器构造PacketOut消息向S1的三个端口分别发送上图所示的LLDP数据包,其中将Chassis ID TLV和Port ID TLV分别置为S1的dpid和端口号;

2. 控制器向交换机S1中下发流表,流表规则为:将从Controller端口收到的LLDP数据包从他的对应端口发送出去;

3. 控制器向交换机S2中下发流表,流表规则为:将从非Controller接收到LLDP数据包发送给控制器;

4. 控制器通过解析LLDP数据包,得到链路的源交换机,源接口,通过收到的PacketIn消息知道目的交换机和目的接口;



现在的ryu发现拓扑是对整个数据平面的所有交换机的所有端口发送PacketOut数据包,对于Fattree等网络来说,端口的数量是交换机数量的k倍,因此导致了很多资源的消耗,所以是否可以对这个拓扑发现的机制进行改进,让发送的PacketOut消息和交换机的数量相同?

三. 改进后的ryu拓扑发现机理

为了实现上面所提到的改进目标,需要将LLDP负载中的Port ID TLV进行改进,或者有其他的域和Port ID TLV一一映射也可以,这里提供一种解决办法,在LLDP数据包从交换机端口转发出去的时候,将这个以太网数据包的源MAC地址替换成为这个端口的MAC地址,而控制器在早先的配置阶段已经获得了关于交换机的端口的所有信息,所以对控制器来说,MAC地址和交换机的端口号是一一对应的,下面详细讲述改进方案。

1. 更新控制器的LLDP PacketOut消息数量,由一个端口一个,改为一个交换机一个PacketOut消息,LLDP数据包负载中的域Port ID TLV值置为零;

2. 控制器向流表下发一条规则:所有从端口Controller接收到的LLDP数据包,依次将其源MAC地址置为端口MAC地址,然后从相应的端口转发出去;

3. 更新控制器的PacketIn消息处理机制,根据LLDP数据包的来源,可以得到目的交换机,目的端口,通过解析LLDP数据包,得到源MAC和源交换机,通过源MAC地址查找对应的端口号;

4. 由于是修改的代码,所以不要忘了删除原来的以端口主导的相关代码。

四. 代码分析

首选需要添加的一些变量和类

* SwitchData类:包含了时间戳以及交换机所包含的LLDP数据Shell


  1. class SwitchData(object): 
  2.   
  3. #store the lldp information 
  4.   
  5. #send one LLDP information per switch 
  6.   
  7. def init (self, lldpdata): 
  8. super(SwitchData, self).init() 
  9. self.lldp_data = lldp_data 
  10. self.timestamp = None 
  11. self.sent = 0 
  12. def lldp_sent(self): 
  13.     self.timestamp = time.time() 
  14.     self.sent += 1 
  15.   
  16. def lldp_received(self): 
  17.     self.sent = 0 
  18.   
  19. def lldp_dropped(self): 
  20.     return self.sent 
  21.   
  22. def clear_timestamp(self): 
  23.     self.timestamp = None 
  24.   
  25. def __str__(self): 
  26.     return 'SwitchData<timestamp=%s, sent=%d>' \ 
  27.         % (self.timestamp, self.sent) 

* SwitchDataState:类似于PortDataState类,继承自字典,保存从Switch类到SwitchData类的映射,维护了一个类似双向链表的数据结构Shell


  1. class SwitchDataState(dict): 
  2. # dict: Switch class -> SwitchData class 
  3. # slimed down version of OrderedDict as python 2.6 doesn't support it. 
  4. _PREV = 0 
  5. _NEXT = 1 
  6. _KEY = 2 
  7. def __init__(self): 
  8.     super(SwitchDataState, self).__init__() 
  9.     self._root = root = []          # sentinel node 
  10.     root[:] = [root, root, None]    # [_PREV, _NEXT, _KEY] 
  11.                                     # doubly linked list 
  12.     self._map = {} 
  13.   
  14. def _remove_key(self, key): 
  15.     link_prev, link_next, key = self._map.pop(key) 
  16.     link_prev[self._NEXT] = link_next 
  17.     link_next[self._PREV] = link_prev 
  18.   
  19. def _append_key(self, key): 
  20.     root = self._root 
  21.     last = root[self._PREV] 
  22.     last[self._NEXT] = root[self._PREV] = self._map[key] = [last, root, key]                                                                
  23.   
  24. def _prepend_key(self, key): 
  25.     root = self._root 
  26.     first = root[self._NEXT] 
  27.     first[self._PREV] = root[self._NEXT] = self._map[key] = [root, first, key]                                                                  
  28.   
  29. def _move_last_key(self, key): 
  30.     self._remove_key(key) 
  31.     self._append_key(key) 
  32.   
  33. def _move_front_key(self, key): 
  34.     self._remove_key(key) 
  35.     self._prepend_key(key) 
  36.   
  37. def add_switch(self, dp, lldp_data): 
  38.     if dp not in self: 
  39.         self._prepend_key(dp) 
  40.         self[dp] = SwitchData( lldp_data) 
  41.   
  42. def lldp_sent(self, dp): 
  43.     switch_data = self[dp] 
  44.     switch_data.lldp_sent() 
  45.     self._move_last_key(dp) 
  46.     return switch_data 
  47.   
  48. def lldp_received(self, dp): 
  49.     self[dp].lldp_received() 
  50.   
  51. def move_front(self, dp): 
  52.     switch_data = self.get(dp, None) 
  53.     if switch_data is not None: 
  54.         switch_data.clear_timestamp() 
  55.         self._move_front_key(dp) 
  56.   
  57. def get_switch(self, dp): 
  58.     return self[dp] 
  59.   
  60. def del_port(self, dp): 
  61.     del self[dp] 
  62.     self._remove_key(dp) 
  63.   
  64. def __iter__(self): 
  65.     root = self._root 
  66.     curr = root[self._NEXT] 
  67.     while curr is not root: 
  68.         yield curr[self._KEY] 
  69.         curr = curr[self._NEXT] 
  70.   
  71. def clear(self): 
  72.     for node in self._map.values(): 
  73.         del node[:] 
  74.     root = self._root 
  75.     root[:] = [root, root, None] 
  76.     self._map.clear() 
  77.     dict.clear(self) 
  78.   
  79. def items(self): 
  80.     'od.items() ->;gt; list of (key, value) pairs in od' 
  81.     return [(key, self[key]) for key in self] 
  82.   
  83. def iteritems(self): 
  84.     'od.iteritems -> an iterator over the (key, value) pairs in od' 
  85.     for k in self: 
  86.         yield (k, self[k]) 

接着简述修改的核心代码,对应上面第三部分提到的四点

1. 更新控制器的LLDP PacketOut消息数量,由一个端口一个,改为一个交换机一个PacketOut消息,LLDP数据包负载中的域Port ID TLV值置为零;


  1. #construct LLDP packet for switch 
  2. def switchadded(self, dp): 
  3. lldpdata = LLDPPacket.lldppacket( 
  4. dp.dp.id, 0, '00:00:00:00:00:00', self.DEFAULTTTL) 
  5. self.switches.addswitch(dp, lldpdata) 

2.控制器向流表下发一条规则:所有从端口Controller接收到的LLDP数据包,依次将其源MAC地址置为端口MAC地址,然后从相应的端口转发出去;


  1. if dp.ofproto.OFPVERSION>= ofprotov12.OFPVERSION: 
  2. for portinfor in self.portstate[dp.id].values(): 
  3. if portinfor.name != "tap:": 
  4. actions.append(dp.ofprotoparser.OFPActionSetField(ethsrc=portinfor.hwaddr)) 
  5. actions.append(dp.ofprotoparser.OFPActionOutput(portinfor.portno)) 
  6. #actions = [dp.ofprotoparser.OFPActionOutput(self.portstate[dp].portno)] 
  7. out = dp.ofprotoparser.OFPPacketOut( 
  8. datapath=dp, inport=dp.ofproto.OFPP_CONTROLLER, 
  9. bufferid=dp.ofproto.OFPNOBUFFER, actions=actions, 
  10. data=switchdata.lldpdata) 
  11. dp.sendmsg(out) 
  12. else: 
  13. LOG.error('cannot send lldp packet. unsupported version. %x', 
  14. dp.ofproto.OFPVERSION) 

3.更新控制器的PacketIn消息处理机制,根据LLDP数据包的来源,可以得到目的交换机,目的端口,通过解析LLDP数据包,得到源MAC和源交换机,通过源MAC地址查找对应的端口号;


  1. for port in self.portstate[srcdpid].values(): 
  2. if port.hwaddr == srcmac: 
  3. srcportno = port.portno 

4.由于是修改的代码,所以不要忘了删除原来的以端口主导的相关代码。完整的代码见github。

五. 实验验证

用Mininet建立一个二层二叉树,s3作为根节点分别连接s1和s2。如下图:

写个简单的ryu应用来调用拓扑发现模块提供的API接口,应用为topo_learner.py,代码见github用wireshark抓取OpenFlow和LLDP数据包来进行验证



首先抓取交换机对控制器的响应消息,查看交换机的端口以及对应的MAC地址,从解析可以看到这是s3交换机,拥有四个端口(分别连接控制器,s1,s2,h3),下图是截取到的一个LLDP数据包,可以看出图中蓝色背景的LLDP的数据包的源MAC地址是s3交换机的3端口的MAC地址,说明前面的代码修改成功。

作者:何妍

来源:51CTO

时间: 2024-11-03 22:55:52

提高SDN控制器的拓扑发现性能的相关文章

SDN控制器测试工具面世 RYU性能测试报告发布

当软件定义网络SDN逐渐成为网络世界新的范式,商用部署速度加快,因此整个SDN网络性能的关键--SDN控制器也必将越来越成为网络用户关心的焦点.天地互连-全球SDN测试认证中心(www.sdnctc.com)经过广泛的需求征集和独立科研,成功开发出了SDN控制器测试工具:OFsuite_Performance,填补了SDN控制器系统性性能测试市场空白,并将向公众发布<RYU控制器性能测试报告>.至此,全球SDN测试认证中心将正式面向全球范围开展SDN控制器测试业务,为SDN控制器用户提供更多的

瞻博网络马绍文:做云计算最好用的 SDN 控制器

[51CTO.com原创稿件]采访马绍文是在全球网络技术大会上.SDN专场的听众很多,座位坐满了,很多听众就站着听,听到精彩的地方就举起手机拍照,闪光灯此起彼伏,颇有几分粉丝追星的味道.当时身为瞻博网络亚太区资深产品总监的他,刚刚在SDN专场结束了<云计算需要什么样的 SDN 控制器>的演讲.记者也随后采访了他,听他聊聊瞻博网络眼中的SDN发展之道. 全球网络技术大会马绍文发言现场 SDN:颠覆传统带来更多创新可能 马绍文告诉记者,在人们传统意识里,创业不仅仅需要投入大量人力物力,更意味着要经

应当关注SDN控制器的哪些要素?

  软件定义网络潜在用户所面临的一个关键挑战是判断特定SDN控制器的特定价值,毕竟控制器作为网络应用和网络基础设施之间的桥梁发挥着关键性作用.但目前还没有一个可以规范SDN的模型,也没有一个SDN控制器必须要遵守的任何标准. 虽然Linux基金会旗下的多厂商OpenDaylight项目的出现为统一的模块化控制器架构所需的SDN堆栈带来了希望,但是对于控制器需要提供什么样的特定服务,厂商当中仍然存在着许多不同的意见.用户的压力在于确定SDN控制器具有什么样的能力,以及这些功能是否能够帮助实现期望的

【SDN控制器分析之二】ONOS网络状态表述

概述 控制平面所维护的关键信息是网络状态.控制平面必须聚合此信息,并使其对应用程序可用.此外,为了保持可扩展性和组件重用,应用程序应该免受协议细节的影响,即使网络状态信息是通过特定协议的方式获得的. ONOS协议不可知的拓扑结构是采用两个互补机制:网络发现和配置来实现的.前者利用网络协议让ONOS识别网络元素的位置和/或性能,在功能使能的情况下会主动开展相关的采集工作.后者允许应用程序和操作人员配置预期的拓扑,或者为网络组件提供提示,这些组件在网络中不能被典型的方法发现. 下一节首先说明ONOS

如何提高SDN可拓展性

× loading.. 企业网D1Net 登入注册 CIO频道 云计算 智慧城市 数据中心 大数据 数据网络 移动办公 服务器 存储 安全 统一通信 视频会议 视频监控 呼叫中心 物联网 虚拟化 IP语音 更多 首   页 产品专区/路 技术专区 专家视点 解决方案 企业动态 行业动态 更多 当前位置:数据网络 → 行业动态 → 正文 如何提高SDN可拓展性 责任编辑:editor005 作者:李呈 |  2016-01-20 14:48:35 本文摘自:SDNLAB Software Defi

AT&amp;T开发出可进行400Gbe试验的SDN控制器

美国最大电信运营商AT&T正在继续推动对网络的更大规模的软件控制,以期达到2017年其网络55%向SDN转型的目标.该公司2016年实现了其网络34%由软件控制,目标是到2020年,75%的网络由软件控制. 该公司近日宣布,使用内部开发的软件定义网络(SDN)控制器来实现公司第一部分多阶段400Gb/s以太网(Gbe)数据速度的测试.在试验期间,AT&T将在纽约和华盛顿建立400Gbe连接.然后,该软件使用软件控制提供第二条路径的服务,以模拟对网络故障的响应. AT&T发言人表示,

SDN控制器究竟在干啥?

一提到SDN,大家就会想到南北向接口,南向接口负责和交换机的交互,北向接口负责和各种应用的交互,SDN控制器稳坐中间,运筹帷幄,决胜千里.在博主看来,这只是SDN的冰山一角.对这个问题比较全面的阐述出现在OpenStack Silicon Valley上Martin Casado的一次演讲.虽然这次演讲的主题是数据中心的策略管理(Policy for the Cloud Frontier),但Martin在演讲中定义的三个方面却实实在在是所有SDN系统需要解决的最基本的三个问题. 1. 南向接口

《软件定义网络:基于OpenFlow的SDN》一一3.1 SDN控制器

3.1 SDN控制器 如后面的图3-1所描绘的那样,在软件定义网络(SDN)中,特别是OpenFlow中,控制平面和数据平面是分离的,我们可以把两者类比作操作系统和计算机硬件,OpenFlow控制器(就好比操作系统)提供一个OpenFlow交换机(就好比计算机硬件)的编程接口,利用这个编程接口,就可以开发网络应用,完成控制和管理任务,并提供新的功能.SDN中的控制平面,特别是OpenFlow的控制平面,在逻辑上是集中化的,因此在开发网络应用的时候,可以把网络视为一个系统.由于采用应变式的(rea

AT&amp;T开发出400 GbE试验的SDN控制器

AT&T继续推动对网络的更大规模的软件控制,以期达到2017年实现其网络55%向SDN的转型.该公司2016年实现了其网络34%由软件控制,目标是到2020年,75%的网络由软件控制. 该公司本周宣布,其使用内部开发的软件定义网络(SDN)控制器来实现公司第一部分多阶段测试400 Gb/s以太网(Gbe)数据速度的测试.在试验期间,AT&T将在纽约和华盛顿建立400 Gbe连接.然后,该软件使用软件控制来重新路由第二条路径的服务,以模拟对网络故障的响应. AT&T发言人表示,SDN