---
# System prepended metadata

title: Ryu Switch Hub
tags: [SDN, RYU]

---


# Simple Switch (1.3 version )

## Library 

```

from ryu.controller import ofp_event #open flow protocol Event
from ryu.controller.handler import CONFIG_DISPATCHER , MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3 # import open flows version 1.3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet

```




## Class  "Initial & inherit" 

會先設定 OpenFlow 的 Version
-> 1.3 

，MAC 位址表的 mac\_to\_port 也已經被定義。

```python 
class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    def __init__(self , *args, **kwargs):
        super(SimpleSwitch13 , self).__init__(*args,**kwargs)
        self.mac_to_port = {}
```
### inherit (app.app_manager,RyuApp)

`meowheckerSimpleSwitch`  class 它繼承自 `app.app_manager` 和 `RyuApp` 兩個父類


## Event Handler 


Ryu 完成 Switch 3 handshake -> 後收到 from Swith 的 openflow Message(BUTTON XD 概念) -> 產生Event  

CONFIG_DISPATCHER(收發 dispatcher)

寫function 來處理OVS 發過來的Message (Event Handler)


![](https://hackmd.io/_uploads/r1Ugo0sY2.png)

## Create Table-miss Flow Entry

OVS 連到Controller 時 ADDing Table-miss Flow Entry 到 Flow table 中為接收 Packet-In 訊息做準備。


```python
#ryu.controller.handler.CONFIG_DISPATCHER 接收 SwitchFeatures 訊息
    @set_ev_cls(ofp_event,EventOFPSwitchFeatures,CONFIG_DISPATCHER)
    def switch_features_handler(self,ev):
        datapath = ev.msg.datapath  # Switch ID (receive Message)
        ofproto = datapath.ofproto # switch 的 openFlow
        parser = datapath.parser  # switch -> 解析
```
ev.msg -> switch 送過來的Message 


>Table Miss: 
在Flow Table尋找符合規則的Flow Entry時 找不到相對應的Flow Entry

ev.msg -> Openflow message entry 



Datapath class 處理 OpenFlow Message e.g.

- 與交換器的通訊 
- Trigger 接收訊息相關的Event 

```python
    # Establish Table-Miss FLOW (policy Rule)
        match = parser.OFPMatch() # mach ALLLLL packet 
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
        self.add_flow(datapath,0,match,actions)
```
他的OFP 應該是 openflowpacket

這個FLOW 可以 match 所有的封包
output action 指向 Ryu Controller 

OFPCML\_NO\_BUFFER -> OFP controller "max length" 送 ( packet Header + packet payload ) to controller

## packet IN: Unknown packet into the controller (No match Rules)


ryu.controller.handler.MAIN_DISPATCHER 一般狀態

```python
   @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in_handler(self,ev):

        # get switch ID && parser it FOr Add FLOWSSSSSSS !!!
        msg=ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.parser
```

### Parse Packet Infromation && Updata Packet Table !!!

```python 
# Parse Packet Infromation 

        ip_port = msg.match['in_port'] # packet Source

        pkt =  packet.Packet(msg.data) 
        eth = pkt.get_protocol(ethernet.ethernet)[0] #get packet protocol 

        dst = eth.dst  #protocol, dst 
        src = eth.src  #protocol, src 

        dpid = datapath.id

        self.mac_to_port.setdefault(dpid,{}) #Mac Table Structure !

        self.logger.info("packet 跑過來拉 ㄚㄚㄚㄚ packet information: %s %s %s %s ", dpid , src , dst , ip_port)
        
        # learn a mac address 
        self.mac_to_port[dpid][src] = in_port #設定 MAC table , Output Port 取得其他 Node 
```

in_port -> Controller 

參考 
```
root@ubuntu:/home/user/Desktop# ovs-ofctl dump-flows s1
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=5.097s, table=0, n_packets=6, n_bytes=588, idle_timeout=60, idle_age=0, priority=65535,icmp,in_port=2,vlan_tci=0x0000,dl_src=26:34:ef:a9:41:b4,dl_dst=ce:ce:b8:90:65:1e,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:1
 cookie=0x0, duration=4.096s, table=0, n_packets=6, n_bytes=588, idle_timeout=60, idle_age=0, priority=65535,icmp,in_port=1,vlan_tci=0x0000,dl_src=ce:ce:b8:90:65:1e,dl_dst=26:34:ef:a9:41:b4,nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:2
 cookie=0x0, duration=0.082s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=0, priority=65535,arp,in_port=2,vlan_tci=0x0000,dl_src=26:34:ef:a9:41:b4,dl_dst=ce:ce:b8:90:65:1e,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1 actions=output:1
 cookie=0x0, duration=0.079s, table=0, n_packets=1, n_bytes=42, idle_timeout=60, idle_age=0, priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=ce:ce:b8:90:65:1e,dl_dst=26:34:ef:a9:41:b4,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=2 actions=output:2
```

src ,dst 為Ehernet 收到MAC aDDress 


Mac table structure 
```
dpid {} (key:dpid,value:{})

{
    switch1 {src:in_port}
    switch2 {src:in_port}
}
```

self.mac_to_port[dpid][src] = in_port 
接到多個 OpenFlow Switch 紀錄它們的ID


### Packet Forwarding && Add the Flow(MAC 有找到 routing)
```
# Packet Forwarding (根據MAC table )
        
        if dst in self.mac_to_port[dpid]: #Look up Mac Table 
            out_port = self.mac_to_port[dpid][dst] 
        else:
            out_port = ofproto.OFPP_FLOOD # HUB -> 找不到就 brocast (security Badddddd!!! )

        actions = [parser.OFPActionOutput(out_port)]

        #install a flow to avoid next packet_in next Time 

        if out_port != ofproto.OFPP_FLOOD:
            match = parser.OFPMatch(input=in_port, eth_dst=dst)
            self.add_flow(datapath,1,match,actions) 
```

## add_Flow function 

```python
 def add_flow(self,datapath,priority,match,actions):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        
        #Action 
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)] //isntruction (commend)
```
Apply Actions 是用來設定那些必須立即執行的 action (??)

### Adding the flow into Switch Flow Table
OFPFlowMod "Class"

```
# Adding the flow into Switch Flow Table 

        newFlow = parser.OFPFlowMod(datapath=datapath,property=property,match=match,isinstance = inst)

        #Send the Flow to Switch
        datapath.send_msg(newFlow)
```

OFPFlowMod 類別的inintial Parameter 很多

- datapath
- cookie (0) //Controller 所設定儲存的資料
- table_id (0) //指定 Flow Entry 的 Table ID 。
- command (ofproto_v1_3.OFPFC_ADD
    ![](https://hackmd.io/_uploads/B1sNwVu5h.png)
Flow Entry 的有效期限
    - idle_timeout (0) Flow Entry 有被參照，則超過時間之後會
重新歸零計算
    - hard_timeout (0)
    
- priority (0
- out_port (0)
- match 
- instructions ([])

```python=
        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data
            
            #forward Packet 
            out = parser.OFPPacketOut(datapath=datapath,buffer_id=msg,buffer.id,in_port=in_port,actions=actions,data=data)
            datapath.send_msg(out)
```


設定封包的 binary data 。主要用在 buffer_id 為 OFP_NO_BUFFER 的情況。如果使用
了 OpenFlow 交換器的緩衝區則可以省略


### Switch Hub Code 

```python=
# openflow 13 

from ryu.controller import ofp_event #open flow protocol Event
from ryu.controller.handler import CONFIG_DISPATCHER , MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3 # import open flows version 1.3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet


class meowheckerSimpleSwitch(app.app_manager,RyuApp):
    OFP_VERSION = [ofproto_v1_3.OFP_VERSION] # ofp version 

#Initial Class 

    def __init__(self,*args,**kwargs):
        super(meowheckerSimpleSwitch,self).__init__(*args,**kwargs)
        self.mac_to_port={}  # MAC table 


#Event Handler 


# Deal with the First Connection 

    #ryu.controller.handler.CONFIG_DISPATCHER   接收 SwitchFeatures 訊息
    @set_ev_cls(ofp_event,EventOFPSwitchFeatures,CONFIG_DISPATCHER)
    def switch_features_handler(self,ev):
        datapath = ev.msg.datapath  # Switch ID (receive Message)
        ofproto = datapath.ofproto # switch 的 openFlow
        parser = datapath.parser  # switch -> 解析

    # Establish Table-Miss FLOW (policy Rule)

        match = parser.OFPMatch() # mach ALLLLL packet 
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)] 
        self.add_flow(datapath,0,match,actions)

# add_flow entry 

    def add_flow(self,datapath,priority,match,actions):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        #Action
        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)] //isntruction

    # Adding the flow into Switch Flow Table 

        newFlow = parser.OFPFlowMod(datapath=datapath,property=property,match=match,isinstance = inst)

        #Send the Flow to Switch
        datapath.send_msg(newFlow)


# Unknow packet into the controller (No match Rules)
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in_handler(self,ev):

    # get switch ID && parser it FOr Add FLOWSSSSSSS !!!
        msg=ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.parser

    # Parse Packet Infromation 

        ip_port = msg.match['in_port'] # packet Source

        pkt =  packet.Packet(msg.data) 
        eth = pkt.get_protocol(ethernet.ethernet)[0] #get packet protocol 

        dst = eth.dst  #protocol, dst 
        src = eth.src  #protocol, src 

        dpid = datapath.id

        self.mac_to_port.setdefault(dpid,{}) #Mac Table Structure !

        self.logger.info("packet 跑過來拉 ㄚㄚㄚㄚ packet information: %s %s %s %s ", dpid , src , dst , ip_port)
        
        # learn a mac address 
        self.mac_to_port[dpid][src] = in_port #設定 MAC table , Output Port 取得其他 Node 

    # Packet Forwarding (根據MAC table )
        
        if dst in self.mac_to_port[dpid]: #Look up Mac Table 
            out_port = self.mac_to_port[dpid][dst] 
        else:
            out_port = ofproto.OFPP_FLOOD # HUB -> 找不到就 brocast (security Badddddd!!! )

        actions = [parser.OFPActionOutput(out_port)]

        #install a flow to avoid next packet_in next Time 

        if out_port != ofproto.OFPP_FLOOD:
            match = parser.OFPMatch(input=in_port, eth_dst=dst)
            self.add_flow(datapath,1,match,actions) 

        data = None
        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
            data = msg.data
            
            #forward Packet 
            out = parser.OFPPacketOut(datapath=datapath,buffer_id=msg,buffer.id,in_port=in_port,actions=actions,data=data)
            datapath.send_msg(out)
    


```
## Executing Ryu Program 

### Executing Mininet

Controller 上 Run application 



```
root@ubuntu:/home/user/Desktop# ryu-manager ddos2.py
loading app ddos2.py
loading app ryu.topology.switches
loading app ryu.controller.ofp_handler
instantiating app ryu.topology.switches of Switches
instantiating app ryu.controller.ofp_handler of OFPHandler
instantiating app ddos2.py of MyController
pkt in!!
pkt in!!
pkt in!!
pkt in!!
pkt in!!

```

![](https://hackmd.io/_uploads/SyOvWSO52.png)

---

