Nox-Spanning_Tree

Spanning_tree 是nox的一個module.

nox會藉由此moudle來維護spanning tree,避免封包在廣播的時候會產生broadcast storm.

###init###
這邊做的是一些成員的初始化,包括一些set的初始。

###install###
首先會呼叫

1
2
3
4
5
6
7
8
9
10
會根據port的數量去決定LLDP發送的頻率,目前FLOO_D_WAIT_TIME 預設是10秒,代表10秒內要把平均的送出LLDP出去。
<!--more-->
接者會去註冊一些相關事件
```python
self.register_for_datapath_join ( self.dp_join )
self.register_for_datapath_leave( self.dp_leave )
self.register_for_port_status( self.handle_port_status )
self.register_for_packet_in( self.handle_packet_in)

這段還不是很清楚,但是感覺是讓一些變數在各module之間互通使用的。
self.bindings = self.resolve(pybindings_storage)

這段則是透過reactor把命令給延緩1秒後執行
意思就是這行結束一秒後,就會自己執行update_spanning_tree.
self.post_callback(1, self.update_spanning_tree)

###dp_join###
當有switch 與controller連線之後,便會呼叫此function來做處理。

如果Nox本身不認得該switch的話,就會去紀錄該switch有哪些port
如果該port的port number 小於 OFPP_MAX(65280)的話,就進行相關設定

設定該port的起始時間
預設該port是不能flood的,這樣可以避免新的PORT一出現就會使得spanning tree出問題。
然後發送一個port_modify的封包去把該port給設定成no_flood

最後紀錄該Port,並且重新調整LLDP的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
now = time.time()
ports = {}
for port in stats['ports']:
ports[port[core.PORT_NO]] = port
if port[core.PORT_NO] <= openflow.OFPP_MAX:
port['enable_time'] = now + FLOOD_WAIT_TIME
port['flood'] = False
hw_addr = "\0\0" + port[core.HW_ADDR]
hw_addr = struct.unpack("!q", hw_addr)[0]
self.ctxt.send_port_mod(dp, port[core.PORT_NO], ethernetaddr(hw_addr),
openflow.OFPPC_NO_FLOOD, openflow.OFPPC_NO_FLOOD)
self.datapaths[dp] = ports
self.port_count += len(ports)
self.update_lldp_send_period()

###dp_leave###
當有swtich離開的時候,先檢查該switch是否存在
然後把整體的port_count給調整。

###update_spanning_tree###
先利用bindings去取得所有的link,然後把本身的一個callback function傳進去。
接者在FLOOD_PORT_UPDATE_INTERVAL(5 sec)的時間後,呼叫update_spanning_tree.

1
2
self.bindings.get_all_links(self.update_spanning_tree_callback)
self.post_callback(FLOOD_PORT_UPDATE_INTERVAL, self.update_spanning_tree)

###update_spanning_tree_llback###

###handle_port_status###

###handle_packet_in###

port是flood port或是該封包是LLDP 這兩種情況就直接把該封包傳給下一個module去處理。

除了此情況以外

  • 檢查destination的mac address 是否學過
  • 檢查destination的ip type = ethernet 且 ip version = ipv4且 ip header = 20byte (5*4)
1
2
3
if not packet.parsed:
if packet.type == ethernet.LLDP_TYPE:
return CONTINUE
1
2
3
4
5
6
7
8
9
10
11
12
13
try:
dst_mac = (struct.unpack('!I', packet.arr[0:4])[0] << 16) + struct.unpack('!H', packet.arr[4:6])[0]
if dst_mac in self.mac_bypass:
return CONTINUE
type = struct.unpack('!H', packet.arr[12:14])[0]
ipver = struct.unpack('!b', packet.arr[14:15])[0]
if type == 0x800 and ipver == 0x45:
dst_ip = struct.unpack('!I', packet.arr[30:34])[0]
if dst_ip in self.ip_bypass:
return CONTINUE
except:
pass
1
2
3
4
5
6
7
8
try:
if self.datapaths[dpid][inport]['flood']:
return CONTINUE
else:
log.warn("STOP")
return STOP
except KeyError:
return STOP

###update_lldp_send_period###

在nox中LLDP的發送情況是要在 FLOOW_WAIT_TIME的時間內 把所有的LLDP都送出去

所以PORT的數量愈多,每個LLDP的間隔就愈短。
預設值

  • FLOOW_WAIT_TIME = 10
  • MIN_LLDP_SEND_PERIOD = 0.05
1
2
3
4
5
6
if self.port_count == 0:
nox.netapps.discovery.discovery.LLDP_SEND_PERIOD = MIN_LLDP_SEND_PERIOD
else:
nox.netapps.discovery.discovery.LLDP_SEND_PERIOD = min(
MIN_LLDP_SEND_PERIOD,
(FLOOD_WAIT_TIME * 1.0) / 2 / self.port_count)