# 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)

## 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

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!!
```

---