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