---
# System prepended metadata

title: mininet
tags: [' mininet', SDN]

---

---
tags: SDN, mininet
---

# mininet

## 1

`mn` 創造網路拓樸
![預設](https://i.imgur.com/h0aunry.png)
> 編號 主機: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` 查看網路架構 
![](https://i.imgur.com/GEwqdN1.png)

`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
![](https://i.imgur.com/aXUF1T9.png)

目的是 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~

![](https://i.imgur.com/Uvo0JKv.png)

```
#!/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()
```

![](https://i.imgur.com/vgSJS68.png)

測試
`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


![](https://i.imgur.com/XSbtYKN.png)
 

----

![homework](https://i.imgur.com/VGP4uwR.png)

目的是讓r3`wireshark`只能看到request
r4`wireshark`只能看到response

## 5
mkdir bridge
cd bridge
vim 1.py

![](https://i.imgur.com/agSHIP9.png)


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

----

![](https://i.imgur.com/xtcrFac.png)



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

----

![](https://i.imgur.com/VBOWRuU.png)

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

![](https://i.imgur.com/GHfm0Ju.png)

```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編號

![](https://i.imgur.com/E9WyZlz.png)

---

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


![](https://i.imgur.com/AkcTZmp.png)

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

----

![](https://i.imgur.com/BPnKhND.png)

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.

![](https://i.imgur.com/26qOamK.png)

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.

![](https://i.imgur.com/X9U51GF.png)

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

![](https://i.imgur.com/XRu3bzJ.png)

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變動

----

![](https://csie.nqu.edu.tw/smallko/sdn/group_chaining.files/image003.png)

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

![](https://i.imgur.com/hcf2eUQ.png)


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