自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

提高SDN控制器的拓?fù)浒l(fā)現(xiàn)性能

網(wǎng)絡(luò)
本篇文章將以ryu控制器為例,首先介紹傳統(tǒng)網(wǎng)絡(luò)和現(xiàn)在SDN網(wǎng)絡(luò)的拓?fù)浒l(fā)現(xiàn)原理,然后介紹改進(jìn)算法,最后講解改寫后的代碼邏輯。

SDN網(wǎng)絡(luò)的一大特點(diǎn)就是資源由控制器集中管理,控制器管理網(wǎng)絡(luò),最基本的當(dāng)然需要知道網(wǎng)絡(luò)的拓?fù)洌W(wǎng)絡(luò)拓?fù)淇赡軙r(shí)時(shí)發(fā)生變化,所以控制器需要時(shí)時(shí)監(jiān)測(cè),對(duì)于整個(gè)網(wǎng)絡(luò)來說,控制器擔(dān)負(fù)了太多的計(jì)算任務(wù),所以如果能夠幫助控制器減壓,則會(huì)提高整個(gè)網(wǎng)絡(luò)的性能。本篇文章將以ryu控制器為例,首先介紹傳統(tǒng)網(wǎng)絡(luò)和現(xiàn)在SDN網(wǎng)絡(luò)的拓?fù)浒l(fā)現(xiàn)原理,然后介紹改進(jìn)算法,最后講解改寫后的代碼邏輯。

一. LLDP拓?fù)浒l(fā)現(xiàn)原理

傳統(tǒng)網(wǎng)絡(luò)中的鏈路發(fā)現(xiàn)協(xié)議為L(zhǎng)LDP(Link Layer Discovery Protocol),LLDP允許局域網(wǎng)中的結(jié)點(diǎn)告訴其他結(jié)點(diǎn)他自己的capabilities和neighbours。在傳統(tǒng)以太網(wǎng)交換機(jī)中,交換機(jī)從自己的每個(gè)端口發(fā)送LLDP數(shù)據(jù)包,這個(gè)數(shù)據(jù)包不會(huì)被其他交換機(jī)轉(zhuǎn)發(fā),壽命只有一跳,LLDP負(fù)載被封裝在以太網(wǎng)幀中,結(jié)構(gòu)如下圖,其中深灰色的即為L(zhǎng)LDP負(fù)載,Chassis ID TLV, Port ID TLV和Time to live TLV三個(gè)是強(qiáng)制字段,分別代表交換機(jī)標(biāo)識(shí)符(在局域網(wǎng)中是獨(dú)一無二的),端口號(hào)和TTL。這個(gè)數(shù)據(jù)發(fā)出并被鄰居結(jié)點(diǎn)收到之后進(jìn)行解析,就可以知道這條鏈路的源目的交換機(jī)以及源目的接口。

tp1

二. ryu拓?fù)浒l(fā)現(xiàn)原理

OpenFlow的官方?jīng)]有規(guī)定標(biāo)準(zhǔn)的拓?fù)浒l(fā)現(xiàn)方法,現(xiàn)在的OFDP(OpenFlow Discovery Protocol)利用的仍然是傳統(tǒng)網(wǎng)絡(luò)中的鏈路發(fā)現(xiàn)協(xié)議LLDP,接下來介紹ryu如何利用LLDP發(fā)現(xiàn)拓?fù)洌僭O(shè)現(xiàn)在有兩個(gè)OpenFlow交換機(jī)連接在控制器上,如下圖,簡(jiǎn)述拓?fù)浒l(fā)現(xiàn)步驟(以S1作為主體,S2的類似):

1. SDN控制器構(gòu)造PacketOut消息向S1的三個(gè)端口分別發(fā)送上圖所示的LLDP數(shù)據(jù)包,其中將Chassis ID TLV和Port ID TLV分別置為S1的dpid和端口號(hào);

2. 控制器向交換機(jī)S1中下發(fā)流表,流表規(guī)則為:將從Controller端口收到的LLDP數(shù)據(jù)包從他的對(duì)應(yīng)端口發(fā)送出去;

3. 控制器向交換機(jī)S2中下發(fā)流表,流表規(guī)則為:將從非Controller接收到LLDP數(shù)據(jù)包發(fā)送給控制器;

4. 控制器通過解析LLDP數(shù)據(jù)包,得到鏈路的源交換機(jī),源接口,通過收到的PacketIn消息知道目的交換機(jī)和目的接口;

 

tp2

現(xiàn)在的ryu發(fā)現(xiàn)拓?fù)涫菍?duì)整個(gè)數(shù)據(jù)平面的所有交換機(jī)的所有端口發(fā)送PacketOut數(shù)據(jù)包,對(duì)于Fattree等網(wǎng)絡(luò)來說,端口的數(shù)量是交換機(jī)數(shù)量的k倍,因此導(dǎo)致了很多資源的消耗,所以是否可以對(duì)這個(gè)拓?fù)浒l(fā)現(xiàn)的機(jī)制進(jìn)行改進(jìn),讓發(fā)送的PacketOut消息和交換機(jī)的數(shù)量相同?

 

三. 改進(jìn)后的ryu拓?fù)浒l(fā)現(xiàn)機(jī)理

為了實(shí)現(xiàn)上面所提到的改進(jìn)目標(biāo),需要將LLDP負(fù)載中的Port ID TLV進(jìn)行改進(jìn),或者有其他的域和Port ID TLV一一映射也可以,這里提供一種解決辦法,在LLDP數(shù)據(jù)包從交換機(jī)端口轉(zhuǎn)發(fā)出去的時(shí)候,將這個(gè)以太網(wǎng)數(shù)據(jù)包的源MAC地址替換成為這個(gè)端口的MAC地址,而控制器在早先的配置階段已經(jīng)獲得了關(guān)于交換機(jī)的端口的所有信息,所以對(duì)控制器來說,MAC地址和交換機(jī)的端口號(hào)是一一對(duì)應(yīng)的,下面詳細(xì)講述改進(jìn)方案。

1. 更新控制器的LLDP PacketOut消息數(shù)量,由一個(gè)端口一個(gè),改為一個(gè)交換機(jī)一個(gè)PacketOut消息,LLDP數(shù)據(jù)包負(fù)載中的域Port ID TLV值置為零;

2. 控制器向流表下發(fā)一條規(guī)則:所有從端口Controller接收到的LLDP數(shù)據(jù)包,依次將其源MAC地址置為端口MAC地址,然后從相應(yīng)的端口轉(zhuǎn)發(fā)出去;

3. 更新控制器的PacketIn消息處理機(jī)制,根據(jù)LLDP數(shù)據(jù)包的來源,可以得到目的交換機(jī),目的端口,通過解析LLDP數(shù)據(jù)包,得到源MAC和源交換機(jī),通過源MAC地址查找對(duì)應(yīng)的端口號(hào);

4. 由于是修改的代碼,所以不要忘了刪除原來的以端口主導(dǎo)的相關(guān)代碼。

四. 代碼分析

首選需要添加的一些變量和類

* SwitchData類:包含了時(shí)間戳以及交換機(jī)所包含的LLDP數(shù)據(jù)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類的映射,維護(hù)了一個(gè)類似雙向鏈表的數(shù)據(jù)結(jié)構(gòu)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]) 

接著簡(jiǎn)述修改的核心代碼,對(duì)應(yīng)上面第三部分提到的四點(diǎn)

1. 更新控制器的LLDP PacketOut消息數(shù)量,由一個(gè)端口一個(gè),改為一個(gè)交換機(jī)一個(gè)PacketOut消息,LLDP數(shù)據(jù)包負(fù)載中的域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.控制器向流表下發(fā)一條規(guī)則:所有從端口Controller接收到的LLDP數(shù)據(jù)包,依次將其源MAC地址置為端口MAC地址,然后從相應(yīng)的端口轉(zhuǎn)發(fā)出去;

  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消息處理機(jī)制,根據(jù)LLDP數(shù)據(jù)包的來源,可以得到目的交換機(jī),目的端口,通過解析LLDP數(shù)據(jù)包,得到源MAC和源交換機(jī),通過源MAC地址查找對(duì)應(yīng)的端口號(hào);

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

4.由于是修改的代碼,所以不要忘了刪除原來的以端口主導(dǎo)的相關(guān)代碼。完整的代碼見github。

五. 實(shí)驗(yàn)驗(yàn)證

用Mininet建立一個(gè)二層二叉樹,s3作為根節(jié)點(diǎn)分別連接s1和s2。如下圖:

tp3

寫個(gè)簡(jiǎn)單的ryu應(yīng)用來調(diào)用拓?fù)浒l(fā)現(xiàn)模塊提供的API接口,應(yīng)用為topo_learner.py,代碼見github用wireshark抓取OpenFlow和LLDP數(shù)據(jù)包來進(jìn)行驗(yàn)證

tp4

首先抓取交換機(jī)對(duì)控制器的響應(yīng)消息,查看交換機(jī)的端口以及對(duì)應(yīng)的MAC地址,從解析可以看到這是s3交換機(jī),擁有四個(gè)端口(分別連接控制器,s1,s2,h3),下圖是截取到的一個(gè)LLDP數(shù)據(jù)包,可以看出圖中藍(lán)色背景的LLDP的數(shù)據(jù)包的源MAC地址是s3交換機(jī)的3端口的MAC地址,說明前面的代碼修改成功。

tp5

責(zé)任編輯:何妍 來源: SDNLAB
相關(guān)推薦

2023-08-13 18:31:45

SDN控制器

2015-02-02 09:37:42

SDN控制器

2015-05-26 10:16:27

SDNSDN控制器

2013-06-08 09:50:30

SDN控制器應(yīng)用OpenFlow軟件定義網(wǎng)絡(luò)

2015-07-14 11:09:26

SDN

2015-07-20 11:34:06

2018-01-10 21:07:35

2013-12-19 09:32:01

SDN南向網(wǎng)絡(luò)控制

2015-02-27 10:52:17

SDN

2013-09-22 09:39:16

SDN控制器SDN軟件定義網(wǎng)絡(luò)

2013-09-17 09:18:02

SDN控制SDN軟件定義網(wǎng)絡(luò)

2013-07-18 09:10:30

SDN控制器標(biāo)準(zhǔn)

2013-11-28 09:16:14

SDN控制器軟件定義網(wǎng)絡(luò)

2015-03-23 11:26:38

2015-09-22 13:26:58

SDN通信領(lǐng)域

2016-04-27 09:54:52

SDNSDN控制器

2015-12-18 17:31:54

SDN控制器白皮書

2013-10-23 09:07:57

華為SDN控制器

2013-12-19 09:35:49

SDN控制器北向

2021-12-26 00:01:44

元宇宙SDN控制器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)