---
tags: SDN, mininet
---
# mininet
## 1
`mn` 創造網路拓樸

> 編號 主機:0開始 交換機:1開始
`net` 顯示網路拓樸連接狀態
`pingall` 測試通信
`exit` 離開
`xterm h1 h2` 開啟h1 h2終端機頁面
以下在xterm中執行,也可以加上hostname直接在終端機執行 `h1 ifconfig`
ifconfig h1-eth0 0 清除h1的基礎設定
ip addr add 192.168.0.1/24 brd + dev h1-eth0 設定h1 IP
brd -> broadcast
iperf -s -i 1 -u -p 5555
-s server
-i interval
-u UDP 預設使用TCP
-p port
iperf -c 10.0.0.2 -t 10 -u -b 10M -p 5555
-c client
-t duration
-b bandwidth
## 2
`mn --link=tc,loss=5`
`h1 ping -c 1000 -i 0.01 h2`
-c count
-i interval(minisecond)
h1 -> s1 -> h2 -> s1 -> h1
1 - 95%**4 = 18.5%
`mn --link=tc,loss=5,bw=10,delay='1ms'`
所有link bw都是一樣的
h1 -> s1 -> h2 -> s1 -> h1
delay * 4 + 2~3(3個processing about 2ms)
= 1*4 + 2~3 = 6~7
測試
iperf -s -i 1 -u
iperf -c 10.0.0.2 -b 20M -t 10
---
問題
iperf -c 10.0.0.2 -t 10 -u -b 10M
iperf -s -i 1 -u
正常
iperf -c 10.0.0.2 -t 10 -b 10M
iperf -s -i 1
沒反應?
iperf -c 10.0.0.2 -t 10
iperf -s -i 1
正常
---
### 繪圖
`apt install gnuplot -y`
`h2 iperf -s -i 1 | tee tcp.txt` 把結果存到tcp.txt
`h1 iperf -c 10.0.0.2 -t 10`
```
$ cat tcp.txt
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 14] local 10.0.0.2 port 5001 connected with 10.0.0.1 port 49944
[ ID] Interval Transfer Bandwidth
[ 14] 0.0- 1.0 sec 588 KBytes 4.82 Mbits/sec
[ 14] 1.0- 2.0 sec 437 KBytes 3.58 Mbits/sec
[ 14] 2.0- 3.0 sec 571 KBytes 4.68 Mbits/sec
[ 14] 3.0- 4.0 sec 41.0 KBytes 336 Kbits/sec
[ 14] 4.0- 5.0 sec 223 KBytes 1.83 Mbits/sec
[ 14] 5.0- 6.0 sec 378 KBytes 3.09 Mbits/sec
[ 14] 6.0- 7.0 sec 238 KBytes 1.95 Mbits/sec
[ 14] 7.0- 8.0 sec 115 KBytes 938 Kbits/sec
[ 14] 8.0- 9.0 sec 438 KBytes 3.59 Mbits/sec
[ 14] 9.0-10.0 sec 97.6 KBytes 799 Kbits/sec
[ 14] 10.0-11.0 sec 313 KBytes 2.56 Mbits/sec
[ 14] 0.0-11.5 sec 3.38 MBytes 2.46 Mbits/sec
```
透過 grep sec 過濾出需要的raw
cat tcp.txt | grep sec | head -n 10 | tr "-" " " | awk '{print $4,$8}' > a
gunplot
plot "a" title "tcp" with linespoints
set yrange[0:10]
set ytics 0,1,10
replot
set xrange[0:10]
set xtics 0,1,10
replot
set xlabel "time(sec)"
set ylabel "throughput (Mbps)"
set title "TCP Throughput"
replot
set terminal git
set output "a.gif"
replot
exit
## 3
```
#!/usr/bin/env python
from mininet.cli import CLI # cmd line interface
from mininet.net import Mininet
from mininet.link import Link,TCLink # Link只是可以把節點連起來,TCLink還可以設定delay, loss rate, bandwidth
if '__main__' == __name__:
net = Mininet(link=TCLink) # 創造一個名稱為net的網路空間,並指定節點間以TCLink連接
h1 = net.addHost('h1') # 新增節點
h2 = net.addHost('h2')
Link(h1, h2) #連接節點
net.build() # 建立網路
CLI(net) # 出現命令提示符號
net.stop() # 等待使用者輸入
```
`net` 查看網路架構

`h1 ping -c 3 h2` 測試
---
```
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
r = net.addHost('r') # 作為router
Link(h1, r)
Link(h2, r)
net.build()
CLI(net)
net.stop()
```
linux:
`sed -i '/^$/d ' 2.py`
處理完的結果直接修改並儲存 /^$/ regex->空白行 d:delete
測試
`xterm h1 h2 r`
預設狀態
h1 IP: 10.0.0.1
h2 IP: 10.0.0.2
重設->
ifconfig h1-eth0 0
ifconfig h1-eth0 192.168.1.1/24
h2同理
設定內定路由
`ip route add default via 192.168.1.254`
查看
`route -n` or `ip route show`
h2同理
設定router
清除IP`ifconfig r-eth0 0`
`ifconfig r-eth0 192.168.1.254/24`
`ifconfig r-eth1 192.168.2.254/24`
測試
h1:`ping 192.168.1.254`(ping 自己的內定路由)
h1:`ping 192.168.2.254`
h1:`ping 192.168.1.1`
以上都應該可以通
若失敗可能:
r:`cat /proc/sys/net/ipv4/ip_forward`
1 代表 路由有被啟動
0 代表 路由未被啟動 需要直接改成1
---
```
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
r = net.addHost('r')
Link(h1, r)
Link(h2, r)
net.build()
h1.cmd("ifconfig h1-eth0 0") # 直接h1上操作,不用xterm
h1.cmd("ip addr add 192.168.1.1/24 brd + dev h1-eth0") # 設定IP
h1.cmd("ip route add default via 192.168.1.254") # 設定內定路由
h2.cmd("ifconfig h2-eth0 0")
h2.cmd("ip addr add 192.168.2.1/24 brd + dev h2-eth0")
h2.cmd("ip route add default via 192.168.2.254")
r.cmd("ifconfig r-eth0 0")
r.cmd("ifconfig r-eth1 0")
r.cmd("ip addr add 192.168.1.254/24 brd + dev r-eth0")
r.cmd("ip addr add 192.168.2.254/24 brd + dev r-eth1")
r.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
CLI(net)
net.stop()
```
測試
`python 3.py`
`h1 ping h2 -c 3`
## 4

目的是 h1 ping h2
```
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
r1 = net.addHost('r1')
r2 = net.addHost('r2')
Link(h1, r1)
Link(h2, r2)
Link(r1, r2)
net.build()
h1.cmd("ifconfig h1-eth0 0")
h1.cmd("ip addr add 192.168.1.1/24 brd + dev h1-eth0")
h1.cmd("ip route add default via 192.168.1.254")
h2.cmd("ifconfig h2-eth0 0")
h2.cmd("ip addr add 192.168.2.1/24 brd + dev h2-eth0")
h2.cmd("ip route add default via 192.168.2.254")
r1.cmd("ifconfig r1-eth0 0")
r1.cmd("ifconfig r1-eth1 0")
r1.cmd("ip addr add 192.168.1.254/24 brd + dev r1-eth0")
r1.cmd("ip addr add 10.0.0.1/24 brd + dev r1-eth1")
r1.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
r1.cmd("ip route add 192.168.2.0/24 via 10.0.0.2") 需要為下一跳(中繼router)設定(靜態)路由
r2.cmd("ifconfig r2-eth0 0")
r2.cmd("ifconfig r2-eth1 0")
r2.cmd("ip addr add 192.168.2.254/24 brd + dev r2-eth0")
r2.cmd("ip addr add 10.0.0.2/24 brd + dev r2-eth1")
r2.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
r2.cmd("ip route add 192.168.1.0/24 via 10.0.0.1")
CLI(net)
net.stop()
```
測試
`python 4.py`
`h1 ping -c 3 h2`
----
2/15 到 範例4(https://www.youtube.com/watch?v=9kUUJ1EWomc&ab_channel=Chih-HengKe)
2/16 實際執行 ##3~

```
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
r1 = net.addHost('r1')
r2 = net.addHost('r2')
Link(h1, r1)
Link(h2, r2)
Link(r1, r2)
net.build()
h1.cmd("ifconfig h1-eth0 0")
h1.cmd("ip addr add 192.168.1.1/24 brd + dev h1-eth0")
h1.cmd("ip route add default via 192.168.1.254")
h2.cmd("ifconfig h2-eth0 0")
h2.cmd("ip addr add 22.1.1.1/24 brd + dev h2-eth0")
h2.cmd("ip route add default via 22.1.1.254")
r1.cmd("ifconfig r1-eth0 0")
r1.cmd("ifconfig r1-eth1 0")
r1.cmd("ip addr add 192.168.1.254/24 brd + dev r1-eth0")
r1.cmd("ip addr add 12.1.1.1/24 brd + dev r1-eth1")
r1.cmd("ip route add default via 12.1.1.2")
r1.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
r1.cmd("iptables -t nat -A POSTROUTING -o r1-eth1 -s 192.168.1.0/24 -j MASQUERADE") # NAT轉址
r2.cmd("ifconfig r2-eth0 0")
r2.cmd("ifconfig r2-eth1 0")
r2.cmd("ip addr add 22.1.1.254/24 brd + dev r2-eth0")
r2.cmd("ip addr add 12.1.1.2/24 brd + dev r2-eth1")
r2.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
CLI(net)
net.stop()
```

測試
`python 5.py`
`xterm r1 r1 h1`
r1(a):`wireshark` 監聽r1-eth0
r1(b):`wireshark` 監聽r1-eth1
h1:`ping 22.1.1.1 -c 3`
以下是 h1 -> r1 進行轉址的過程
src h1, dst 22.1.1.1 -> src r1, dst 22.1.1.1
只有src更動 所以也稱為SNAT
並且在r1有一個NAT table記錄封包是從h1送出 所以12.1.1.1會轉換成192.168.1.1回傳 完成1次ping

----

目的是讓r3`wireshark`只能看到request
r4`wireshark`只能看到response
## 5
mkdir bridge
cd bridge
vim 1.py

```python
#! /usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
h3 = net.addHost('h3')
br1 = net.addHost('br1')
net.addLink(h1, br1)
net.addLink(h2, br1)
net.addLink(h3, br1)
net.build()
h1.cmd("ifconfig h1-eth0 0")
h2.cmd("ifconfig h2-eth0 0")
h3.cmd("ifconfig h3-eth0 0")
br1.cmd("ifconfig br1-eth0 0")
br1.cmd("ifconfig br1-eth1 0")
br1.cmd("ifconfig br1-eth2 0")
br1.cmd("brctl addbr mybr")
br1.cmd("brctl addif mybr br1-eth0")
br1.cmd("brctl addif mybr br1-eth1")
br1.cmd("brctl addif mybr br1-eth2")
br1.cmd("ifconfig mybr up") # 這樣ifconfig才會看到mybr
h1.cmd("ip address add 192.168.10.1/24 dev h1-eth0")
h2.cmd("ip address add 192.168.10.2/24 dev h2-eth0")
h3.cmd("ip address add 192.168.10.3/24 dev h3-eth0")
CLI(net)
net.stop()
```
xterm br1
ifconfig 可以看到3個NIC eth0 1 2
brctl addr mybr
brctl show
brctl addif mybr br1-eth0 # 把interface br-eth1 連接到 mybr
brctl show
h1 可以 ping h2 h3
----

```python
#! /usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
h3 = net.addHost('h3')
h4 = net.addHost('h4')
br1 = net.addHost('br1')
net.addLink(h1, br1)
net.addLink(h2, br1)
net.addLink(h3, br1)
net.addLink(h4, br1)
net.build()
h1.cmd("ifconfig h1-eth0 0")
h2.cmd("ifconfig h2-eth0 0")
h3.cmd("ifconfig h3-eth0 0")
h4.cmd("ifconfig h4-eth0 0")
br1.cmd("ifconfig br1-eth0 0")
br1.cmd("ifconfig br1-eth1 0")
br1.cmd("ifconfig br1-eth2 0")
br1.cmd("ifconfig br1-eth3 0")
br1.cmd("brctl addbr mybr1")
br1.cmd("brctl addbr mybr2")
br1.cmd("brctl addif mybr1 br1-eth0")
br1.cmd("brctl addif mybr1 br1-eth1")
br1.cmd("brctl addif mybr2 br1-eth2")
br1.cmd("brctl addif mybr2 br1-eth3")
br1.cmd("ifconfig mybr1 up")
br1.cmd("ifconfig mybr2 up")
h1.cmd("ip address add 192.168.10.1/24 dev h1-eth0")
h2.cmd("ip address add 192.168.10.2/24 dev h2-eth0")
h3.cmd("ip address add 192.168.20.1/24 dev h3-eth0")
h4.cmd("ip address add 192.168.20.2/24 dev h4-eth0")
CLI(net)
net.stop()
```
h1 ping h2
h3 ping h4
h1 ping h3 (X)
----

```python
#! /usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
h3 = net.addHost('h3')
h4 = net.addHost('h4')
br1 = net.addHost('br1')
r1 = net.addHost('r1')
net.addLink(h1, br1)
net.addLink(h2, br1)
net.addLink(h3, br1)
net.addLink(h4, br1)
net.addLink(br1,r1)
net.addLink(br1,r1)
net.build()
h1.cmd("ifconfig h1-eth0 0")
h2.cmd("ifconfig h2-eth0 0")
h3.cmd("ifconfig h3-eth0 0")
h4.cmd("ifconfig h4-eth0 0")
br1.cmd("ifconfig br1-eth0 0")
br1.cmd("ifconfig br1-eth1 0")
br1.cmd("ifconfig br1-eth2 0")
br1.cmd("ifconfig br1-eth3 0")
br1.cmd("ifconfig br1-eth4 0")
br1.cmd("ifconfig br1-eth5 0")
br1.cmd("brctl addbr mybr1")
br1.cmd("brctl addbr mybr2")
br1.cmd("brctl addif mybr1 br1-eth0")
br1.cmd("brctl addif mybr1 br1-eth1")
br1.cmd("brctl addif mybr1 br1-eth4")
br1.cmd("brctl addif mybr2 br1-eth2")
br1.cmd("brctl addif mybr2 br1-eth3")
br1.cmd("brctl addif mybr2 br1-eth5")
br1.cmd("ifconfig mybr1 up")
br1.cmd("ifconfig mybr2 up")
r1.cmd('ifconfig r1-eth0 192.168.10.254 netmask 255.255.255.0')
r1.cmd('ifconfig r1-eth1 192.168.20.254 netmask 255.255.255.0')
r1.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
h1.cmd("ip address add 192.168.10.1/24 dev h1-eth0")
h1.cmd("ip route add default via 192.168.10.254")
h2.cmd("ip address add 192.168.10.2/24 dev h2-eth0")
h2.cmd("ip route add default via 192.168.10.254")
h3.cmd("ip address add 192.168.20.1/24 dev h3-eth0")
h3.cmd("ip route add default via 192.168.20.254")
h4.cmd("ip address add 192.168.20.2/24 dev h4-eth0")
h4.cmd("ip route add default via 192.168.20.254")
CLI(net)
net.stop()
```
h1 ping h2
h1 ping h3
---
## 6
上一個圖中 路由器使用2條鏈路這會造成浪費、可以使用vlan做單臂路由 並且它是truck link 其他是 access link

```python
#! /usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
h3 = net.addHost('h3')
h4 = net.addHost('h4')
br1 = net.addHost('br1')
r1 = net.addHost('r1')
net.addLink(h1, br1)
net.addLink(h2, br1)
net.addLink(h3, br1)
net.addLink(h4, br1)
net.addLink(br1,r1)
net.build()
h1.cmd("ifconfig h1-eth0 0")
h2.cmd("ifconfig h2-eth0 0")
h3.cmd("ifconfig h3-eth0 0")
h4.cmd("ifconfig h4-eth0 0")
r1.cmd("ifconfig r1-eth0 0")
br1.cmd("ifconfig br1-eth0 0")
br1.cmd("ifconfig br1-eth1 0")
br1.cmd("ifconfig br1-eth2 0")
br1.cmd("ifconfig br1-eth3 0")
br1.cmd("ifconfig br1-eth4 0")
br1.cmd("vconfig add br1-eth4 10")
br1.cmd("vconfig add br1-eth4 20")
r1.cmd("vconfig add r1-eth0 10") # 這邊是建立虛擬的interface, vlan tag = 10
r1.cmd("vconfig add r1-eth0 20")
br1.cmd("brctl addbr mybr10")
br1.cmd("brctl addbr mybr20")
br1.cmd("brctl addif mybr10 br1-eth0")
br1.cmd("brctl addif mybr10 br1-eth1")
br1.cmd("brctl addif mybr10 br1-eth4.10")
br1.cmd("brctl addif mybr20 br1-eth2")
br1.cmd("brctl addif mybr20 br1-eth3")
br1.cmd("brctl addif mybr20 br1-eth4.20")
br1.cmd("ifconfig br1-eth4.10 up")
br1.cmd("ifconfig br1-eth4.20 up")
r1.cmd("ifconfig r1-eth0.10 up")
r1.cmd("ifconfig r1-eth0.20 up")
br1.cmd("ifconfig mybr10 up")
br1.cmd("ifconfig mybr20 up")
r1.cmd('ifconfig r1-eth0.10 192.168.10.254 netmask 255.255.255.0')
r1.cmd('ifconfig r1-eth0.20 192.168.20.254 netmask 255.255.255.0')
r1.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
h1.cmd("ip address add 192.168.10.1/24 dev h1-eth0")
h1.cmd("ip route add default via 192.168.10.254")
h2.cmd("ip address add 192.168.10.2/24 dev h2-eth0")
h2.cmd("ip route add default via 192.168.10.254")
h3.cmd("ip address add 192.168.20.1/24 dev h3-eth0")
h3.cmd("ip route add default via 192.168.20.254")
h4.cmd("ip address add 192.168.20.2/24 dev h4-eth0")
h4.cmd("ip route add default via 192.168.20.254")
CLI(net)
net.stop()
```
h1 ping h2、3
----
### [vlan](https://youtu.be/5vj4CKAyz6E)
有vlan功能的switch可以將兩個網路區隔開來(2個vlan) 各自的廣播不會互相影響
vlan可以跨switch 原理如下:
透過trunk link(允許乘載有vlan標籤的封包) 將兩個switch連接
並且定義switch 上 每個孔的vlan編號

---
## 7
在運行中新增節點
mn --topo single,2 # 建立拓樸
py net.addHost('h3') # 建立h3節點 使用 `net` 可看到 未與其他節點連線
py net.addLink(s1, net.get('h3')) #使用 `net` 可看到已連線
這邊第2個引數不能直接寫h3,需要傳入它的handler
但是使用`sh ovs-ofctl show s1`只會看到port1、2 沒有port3
所以還需要把h3-eth0 放到 s1
py s1.attach('s1-eth3')
但是使用`xterm h3` 再看 ifconfig 可以看到沒有任何設定
h3上 `ifconfig h3-eth0 10.0.0.3`
或是 `py net.get('h3').cmd("ifconfig h3-eth0 10.0.0.3/8")`
`h1 ping h3` or `pingall`
[6.py](http://csie.nqu.edu.tw/smallko/sdn/add_node_runtime.htm)
```python
#!/usr/bin/python
from mininet.net import Mininet
from mininet.node import Host, Node
from mininet.cli import CLI
from mininet.link import TCLink, Intf
from mininet.log import setLogLevel, info
from subprocess import call
def myNetwork():
net = Mininet()
r1 = net.addHost('r1')
r1.cmd('sysctl -w net.ipv4.ip_forward=1')
h2 = net.addHost('h2', cls=Host, ip='192.168.2.1/24')
h1 = net.addHost('h1', cls=Host, ip='192.168.1.1/24')
info( '*** Add links\n')
net.addLink(h1, r1)
net.addLink(h2, r1)
info( '*** Starting network\n')
net.build()
h1.cmd("ip route add default via 192.168.1.254")
h2.cmd("ip route add default via 192.168.2.254")
r1.cmd("ip addr add 192.168.1.254/24 brd + dev r1-eth0")
r1.cmd("ip addr add 192.168.2.254/24 brd + dev r1-eth1")
CLI(net)
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
myNetwork()
```
h1 ping h2
若想新增節點h3
py net.addHost("h3")
net
py net.addLink(net.get('r1'), net.get('h3'))
net
xterm h3
h3: `ip addr add 192.168.3.1/24 brd + dev h3-eth0`
h3: `ip route add default via 192.168.3.254`
xterm r1
r1: `ifconfig` r1-th0的IP 10.0.0.1 是有問題的 應該是192.168.1.254
r1: `ifconfig r1-eth0 0`
r1: `ifconfig r1-eth0 192.168.1.254/24`
r1: `ifconfig r1-eth2 192.168.3.254/24`
r1: `ifconfig`
pingall r1->h2 會有問題 因為r1不是正常的交換機而是一般的host
所以針對 路由器或是bridge 建議使用ping
h1 ping h2
h1 ping h3
h2 ping h3
---
## 1.

mn --topo single,2 # 建立拓樸
su
ps -aux | grep controller
kill -9 [PID]
h1 ping h2 (x)
ovs-ofctl show s1
dpid: 用來區分不同switch
capabilities: mod_nw_src 支援修改src_ip, mod_nw_tos IP tos欄位, mod_dl_src 修該第二層的來源NIC...
ovs-ofctl dump-flows s1
ovs-ofctl add-flow s1 in_port=1,action=output:2
ovs-ofctl add-flow s1 in_port=2,action=output:1
ovs-ofctl dump-flows s1
h1 ping h2 (O)
n_packet=5 -> 符合規則的封包數
5 = arp + icmp
ovs-ofctl del-flows s1
ovs-ofctl dump-flows s1
ovs-ofctl del-flows s1 in_port=1
----

mn --topo single,3 # 建立拓樸
h1 ping h2 (O)
su
ps -aux | grep controller
kill -9 [PID]
h1 ping h2 (O) 因為規則已經下放
ovs-ofctl dump-flows s1 檢查
ovs-ofctl del-flows s1
假設
ARP broadcast
IP unicast
ovs-ofctl add-flow s1 in_port=1,arp,actions=output:flood
ovs-ofctl add-flow s1 in_port=2,arp,actions=output:flood
ovs-ofctl add-flow s1 in_port=3,arp,actions=output:flood
ovs-ofctl add-flow s1 ip,nw_dst=10.0.0.1,actions=output:1
ovs-ofctl add-flow s1 ip,nw_dst=10.0.0.2,actions=output:2
ovs-ofctl add-flow s1 ip,nw_dst=10.0.0.3,actions=output:3
ovs-ofctl dump-flows s1
h1 ping h2
---
## 2.

mn --topo single,2 # 建立拓樸
h1 ping h2 (O)
ovs-ofctl dump-flows s1
```python
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
from mininet.node import Controller,RemoteController
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1')
h2 = net.addHost('h2')
s1 = net.addSwitch('s1')
s2 = net.addSwitch('s2')
s3 = net.addSwitch('s3')
c0 = net.addController('c0', controller=RemoteController) # 這樣規則就要手動設定,RemoteController沒有要啟用
net.addLink(h1, s1)
net.addLink(s1, s2)
net.addLink(s1, s3)
net.addLink(s3, s2)
net.addLink(s2, h2)
net.build()
c0.start()
s1.start([c0])
s2.start([c0])
s3.start([c0])
# rules for s1
# ovs-ofctl add-flow s1 arp,arp_op=1,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:2
# ovs-ofctl add-flow s1 arp,arp_op=1,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
# ovs-ofctl add-flow s1 arp,arp_op=2,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:2
# ovs-ofctl add-flow s1 arp,arp_op=2,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
# ovs-ofctl add-flow s1 icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2,icmp_type=8,icmp_code=0,actions=output:2
# ovs-ofctl add-flow s1 icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=0,icmp_code=0,actions=output:1
# rules for s2
# ovs-ofctl add-flow s2 arp,arp_op=1,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:3
# ovs-ofctl add-flow s2 arp,arp_op=1,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
# ovs-ofctl add-flow s2 arp,arp_op=2,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:3
# ovs-ofctl add-flow s2 arp,arp_op=2,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
# ovs-ofctl add-flow s2 icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2,icmp_type=8,icmp_code=0,actions=output:3
# ovs-ofctl add-flow s2 icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=0,icmp_code=0,actions=output:2
# rules for s3
# ovs-ofctl add-flow s3 icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=0,icmp_code=0,actions=output:1
CLI(net)
net.stop()
```
python lab1.py
```
ovs-ofctl add-flow s1 arp,arp_op=1,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:2
ovs-ofctl add-flow s1 arp,arp_op=1,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
ovs-ofctl add-flow s1 arp,arp_op=2,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:2
ovs-ofctl add-flow s1 arp,arp_op=2,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
ovs-ofctl add-flow s1 icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2,icmp_type=8,icmp_code=0,actions=output:2
ovs-ofctl add-flow s1 icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=0,icmp_code=0,actions=output:1
ovs-ofctl add-flow s2 arp,arp_op=1,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:3
ovs-ofctl add-flow s2 arp,arp_op=1,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
ovs-ofctl add-flow s2 arp,arp_op=2,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,actions=output:3
ovs-ofctl add-flow s2 arp,arp_op=2,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,actions=output:1
ovs-ofctl add-flow s2 icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2,icmp_type=8,icmp_code=0,actions=output:3
ovs-ofctl add-flow s2 icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=0,icmp_code=0,actions=output:2
ovs-ofctl add-flow s3 icmp,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=0,icmp_code=0,actions=output:1
```
xterm s2 s3
s3: tcpdump -i s3-eth1
s2: tcpdump -i s2-eth1
h1 ping h2
作業: h2 ping h1
---
## 3.

h 1 2 3 互 ping
h1 -> h2 鏡像h3,直接把目的第改成h3
```python
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
from mininet.node import Controller,RemoteController
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1', ip="10.0.0.1/24", mac="00:00:00:00:00:01")
h2 = net.addHost('h2', ip="10.0.0.2/24", mac="00:00:00:00:00:02")
h3 = net.addHost('h3', ip="10.0.0.3/24", mac="00:00:00:00:00:03")
s1 = net.addSwitch('s1')
c0 = net.addController('c0', controller=RemoteController)
net.addLink(h1, s1)
net.addLink(h2, s1)
net.addLink(h3, s1)
net.build()
c0.start()
s1.start([c0])
h1.cmd("arp -s 10.0.0.2 00:00:00:00:00:02")
h1.cmd("arp -s 10.0.0.3 00:00:00:00:00:03")
h2.cmd("arp -s 10.0.0.1 00:00:00:00:00:01")
h2.cmd("arp -s 10.0.0.3 00:00:00:00:00:03")
h3.cmd("arp -s 10.0.0.1 00:00:00:00:00:01")
h3.cmd("arp -s 10.0.0.2 00:00:00:00:00:02")
#rules for s1
#ovs-ofctl add-flow s1 priority=1,ip,nw_dst=10.0.0.1,actions=output:1
#ovs-ofctl add-flow s1 priority=1,ip,nw_dst=10.0.0.2,actions=output:2
#ovs-ofctl add-flow s1 priority=1,ip,nw_dst=10.0.0.3,actions=output:3
#ovs-ofctl add-flow s1 priority=10,udp,nw_dst=10.0.0.2,actions=output:2,mod_dl_dst=00:00:00:00:00:03,mod_nw_dst=10.0.0.3,output:3
CLI(net)
net.stop()
```
python lab2.py
h1 ifconfig 檢查設定
h1 arp -n
h1 ping h2 (x)
priority 高的先執行
ovs-ofctl dump-flows s1
ovs-ofctl add-flow s1 priority=1,ip,nw_dst=10.0.0.1,actions=output:1
ovs-ofctl add-flow s1 priority=1,ip,nw_dst=10.0.0.2,actions=output:2
ovs-ofctl add-flow s1 priority=1,ip,nw_dst=10.0.0.3,actions=output:3
ovs-ofctl add-flow s1 priority=10,udp,nw_dst=10.0.0.2,actions=output:2,mod_dl_dst=00:00:00:00:00:03,mod_nw_dst=10.0.0.3,output:3
以下寫法只是將要傳給2的封包 一模一樣地(包括封包目的地)發送給3 所以3只能透過wireshark去查看
ovs-ofctl add-flow s1 priority=10,udp,nw_dst=10.0.0.2,actions=output:2,output:3
---
## 4.
### Group Table

Select 是 Group 的一種 可以讓上圖中的兩條鏈路 頻均地被使用以達到負載均衡
```python
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSKernelSwitch, UserSwitch, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.link import Link, TCLink
def topology():
net = Mininet( controller=RemoteController, link=TCLink, switch=OVSKernelSwitch)
# Add hosts and switches
h1= net.addHost( 'h1', mac="00:00:00:00:00:01" )
h2 = net.addHost( 'h2', mac="00:00:00:00:00:02" )
# protocols=["OpenFlow10,OpenFlow13"] 同時支援1.0、1.3版
s1 = net.addSwitch( 's1', protocols=["OpenFlow10,OpenFlow13"], listenPort=6634 )
s2 = net.addSwitch( 's2', protocols=["OpenFlow10,OpenFlow13"], listenPort=6635 )
s3 = net.addSwitch( 's3', protocols=["OpenFlow10,OpenFlow13"], listenPort=6636 )
s4 = net.addSwitch( 's4', protocols=["OpenFlow10,OpenFlow13"], listenPort=6637 )
c0 = net.addController( 'c0', controller=RemoteController, ip='127.0.0.1', port=6633 )
net.addLink( h1, s1)
net.addLink( h2, s4)
net.addLink( s1, s2)
net.addLink( s1, s3)
net.addLink( s2, s4)
net.addLink( s3, s4)
net.build()
c0.start()
s1.start( [c0] )
s2.start( [c0] )
s3.start( [c0] )
s4.start( [c0] )
print "*** Running CLI"
CLI( net )
print "*** Stopping network"
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
topology()
```
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=1,actions=output:2
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s3 in_port=1,actions=output:2
ovs-ofctl -O OpenFlow13 add-flow s3 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s4 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s4 in_port=3,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s4 in_port=1,actions=output:3
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=3,actions=output:1
ovs-ofctl -O OpenFlow13 add-group s1 group_id=5,type=select,bucket=output:2,bucket=output:3
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=1,actions=group:5
h1: iperf -c 10.0.0.2 -t 100
ovs-ofctl dump-ports -O OpenFlow13 s1
觀察 tx pkts 有封包數字就會增加 (可以觀察到只有一個port的數字不斷增加,重新發送發包會發現 變成只有另一個port數字增加 代表使用了Group的Select
同一條資料流 5tuple相同(來源IP 目的IP 來源埠號 目的埠號 傳輸協定) 會走相同路徑
以上是TCP實驗
----
以下是UDP實驗
h1: iperf -c 10.0.0.2 -t 100 -u -b 1M
h2: iperf -s -i 1 -u
ovs-ofctl dump-ports -O OpenFlow13 s1
觀察> 切換資料流後 只會選擇相同的port
對於UDP而言 **無法**使用Group Select做負載均衡
---
## 5.
Group - Fast Failover 當主要使用的port(鏈路)有問題時,才切換到備用port(鏈路),直到原先的port修復
```python
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSKernelSwitch, UserSwitch, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.link import Link, TCLink
def topology():
net = Mininet( controller=RemoteController, link=TCLink, switch=OVSKernelSwitch)
# Add hosts and switches
h1= net.addHost( 'h1', mac="00:00:00:00:00:01" )
h2 = net.addHost( 'h2', mac="00:00:00:00:00:02" )
s1 = net.addSwitch( 's1', protocols=["OpenFlow10,OpenFlow13"], listenPort=6634 )
s2 = net.addSwitch( 's2', protocols=["OpenFlow10,OpenFlow13"], listenPort=6635 )
s3 = net.addSwitch( 's3', protocols=["OpenFlow10,OpenFlow13"], listenPort=6636 )
s4 = net.addSwitch( 's4', protocols=["OpenFlow10,OpenFlow13"], listenPort=6637 )
c0 = net.addController( 'c0', controller=RemoteController, ip='127.0.0.1', port=6633 )
net.addLink( h1, s1)
net.addLink( h2, s4)
net.addLink( s1, s2)
net.addLink( s1, s3)
net.addLink( s2, s4)
net.addLink( s3, s4)
net.build()
c0.start()
s1.start( [c0] )
s2.start( [c0] )
s3.start( [c0] )
s4.start( [c0] )
print "*** Running CLI"
CLI( net )
print "*** Stopping network"
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
topology()
```
python lab4.py
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=1,actions=output:2
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s3 in_port=1,actions=output:2
ovs-ofctl -O OpenFlow13 add-flow s3 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s4 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s4 in_port=3,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s4 in_port=1,actions=output:3
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=3,actions=output:1
// Fast Failover -> ff
ovs-ofctl -O OpenFlow13 add-group s1 group_id=4,type=ff,bucket=watch_port:2,output:2,bucket=watch_port:3,output:3
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=1,actions=group:4
h2: iperf -s -i 1 -u
h1: iperf -c 10.0.0.2 -t 100 -u -b 1M
ovs-ofctl dump-ports -O OpenFlow13 s1
觀察> port2、port3的 tx_pkts
只有2變動
mininet> link s1 s2 down
ovs-ofctl dump-ports -O OpenFlow13 s1
只有3變動
mininet> link s1 s2 up
ovs-ofctl dump-ports -O OpenFlow13 s1
只有2變動
----

port 2、4 一組 (主要)
port 3、5 一組 (備用)
group training = Select + Fast Failover 負載均衡+容錯
```
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSKernelSwitch, UserSwitch, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.link import Link, TCLink
def topology():
net = Mininet( controller=RemoteController, link=TCLink, switch=OVSKernelSwitch)
# Add hosts and switches
h1= net.addHost( 'h1', mac="00:00:00:00:00:01" )
h2 = net.addHost( 'h2', mac="00:00:00:00:00:02" )
s1 = net.addSwitch( 's1', protocols=["OpenFlow10,OpenFlow13"], listenPort=6634 )
s2 = net.addSwitch( 's2', protocols=["OpenFlow10,OpenFlow13"], listenPort=6635 )
c0 = net.addController( 'c0', controller=RemoteController, ip='127.0.0.1', port=6633 )
linkopt={'bw':10}
linkopt2={'bw':100}
net.addLink( h1, s1, cls=TCLink, **linkopt2)
net.addLink( h2, s2, cls=TCLink, **linkopt2)
net.addLink( s1, s2, cls=TCLink, **linkopt)
net.addLink( s1, s2, cls=TCLink, **linkopt)
net.addLink( s1, s2, cls=TCLink, **linkopt)
net.addLink( s1, s2, cls=TCLink, **linkopt)
net.build()
c0.start()
s1.start( [c0] )
s2.start( [c0] )
print "*** Running CLI"
h1.cmd("arp -s 10.0.0.2 00:00:00:00:00:02")
h2.cmd("arp -s 10.0.0.1 00:00:00:00:00:01")
CLI( net )
print "*** Stopping network"
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
topology()
```
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=2,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=3,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=4,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=5,actions=output:1
ovs-ofctl -O OpenFlow13 add-flow s2 in_port=1,actions=output:5
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=5,actions=output:1
ovs-ofctl -O OpenFlow13 add-group s1 group_id=2,type=select,bucket=output:2,bucket=output:4
ovs-ofctl -O OpenFlow13 add-group s1 group_id=3,type=select,bucket=output:3,bucket=output:5
ovs-ofctl -O OpenFlow13 add-group s1 group_id=1,type=ff,bucket=watch_port:2,group:2,bucket=watch_port:3,group:3
ovs-ofctl -O OpenFlow13 add-flow s1 in_port=1,actions=group:1
ovs-ofctl -O OpenFlow13 dump-flows s1
ovs-ofctl -O OpenFlow13 dump-groups s1
xterm h1 h1 h2 h2
h2a: iperf -s -i 1 -p 5566
h2b: iperf -s -i 1 -p 5555
h1a: iperf -c 10.0.0.2 -p 5555 -t 1000
ovs-ofctl -O OpenFlow13 dump-ports s1
觀察> 只有一個port(2) tx pkts 增加
h1b: iperf -c 10.0.0.2 -p 5566 -t 1000
ovs-ofctl -O OpenFlow13 dump-ports s1
觀察> 只有port(2、4) tx pkts 增加
ovs-ofctl mod-port s1 s1-eth2 down
ovs-ofctl -O OpenFlow13 dump-ports s1
觀察> 只有port(3、5) tx pkts 增加
ovs-ofctl mod-port s1 s1-eth2 up
ovs-ofctl -O OpenFlow13 dump-ports s1
觀察> 只有port(3、5) tx pkts 增加
## 6.
### NFV 網路功能虛擬化
假設h1是可疑的,h3是server,可以先讓封包透過h2檢查或是NFV(限速,檢查可以pattern...) 再傳給h3

```python
#!/usr/bin/env python
from mininet.cli import CLI
from mininet.net import Mininet
from mininet.link import Link,TCLink,Intf
from mininet.node import Controller,RemoteController
if '__main__' == __name__:
net = Mininet(link=TCLink)
h1 = net.addHost('h1', ip="10.0.0.1/24", mac="00:00:00:00:00:01")
h2 = net.addHost('h2', ip="10.0.0.2/24", mac="00:00:00:00:00:02")
h3 = net.addHost('h3', ip="10.0.0.3/24", mac="00:00:00:00:00:03")
s1 = net.addSwitch('s1')
c0 = net.addController('c0', controller=RemoteController)
net.addLink(h1, s1)
net.addLink(h2, s1)
net.addLink(h3, s1)
net.build()
c0.start()
s1.start([c0])
# rules for s1
h1.cmd("arp -s 10.0.0.2 00:00:00:00:00:02")
h1.cmd("arp -s 10.0.0.3 00:00:00:00:00:03")
h2.cmd("arp -s 10.0.0.1 00:00:00:00:00:01")
h2.cmd("arp -s 10.0.0.3 00:00:00:00:00:03")
h3.cmd("arp -s 10.0.0.1 00:00:00:00:00:01")
h3.cmd("arp -s 10.0.0.2 00:00:00:00:00:02")
h3.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
# 建立防火牆8080埠放行,80阻擋
h3.cmd("iptables -A FORWARD -p tcp --destination-port 8080 -j ACCEPT")
h3.cmd("iptables -A FORWARD -p tcp --destination-port 80 -j DROP")
s1.cmd("ovs-ofctl add-flow s1 priority=1,in_port=1,actions=output:2")
s1.cmd("ovs-ofctl add-flow s1 priority=1,in_port=2,actions=output:1")
# 若經過port3的封包不是 廣播封包 或 目的地不是port3 則會被drop, 所以需要把mac_address改成port3的
s1.cmd("ovs-ofctl add-flow s1 priority=10,ip,in_port=1,actions=mod_dl_dst=00:00:00:00:00:03,output:3")
s1.cmd("ovs-ofctl add-flow s1 priority=10,ip,in_port=2,actions=mod_dl_dst=00:00:00:00:00:03,output:3")
# 把dl_dst改回去
s1.cmd("ovs-ofctl add-flow s1 priority=10,ip,in_port=3,nw_dst=10.0.0.2,actions=mod_dl_dst=00:00:00:00:00:02,output:2")
s1.cmd("ovs-ofctl add-flow s1 priority=10,ip,in_port=3,nw_dst=10.0.0.1,actions=mod_dl_dst=00:00:00:00:00:01,output:1")
CLI(net)
net.stop()
```
python nfv.py
xterm h2 h2
h2a: python -m SimpleHTTPServer 80
h2b: python -m SimpleHTTPServer 8080
h1 ping h2 (O)
h1 curl 10.0.0.2:8080
> 會回傳網頁,h2b也會顯示
h1 curl 10.0.0.2:80
> 不會回傳網頁,h2a不會顯示,因為被防火牆阻擋了
---
## miniedit 1
cd /home/user/mininet-wifi/example
python miniedit.py