# 網路模擬與分析(3/22):在 Mininet 環境中實現 Router & Bridge 功能 + 應用 ###### tags: `Mininet`、`NAT 轉換`、`vlan`、`單臂路由`、`trunk link`、`access link` ## 透過 Python 程式建立你的第一個 Mininet 環境 (ep.2) ### 在 mininet 的環境下建立2個 Router 的功能 我們上週有介紹了如何在 Mininet 的環境中建立2台 Hosts 和一台 Router,並能夠讓彼此通訊,接下來我們將會介紹如何在2台 Router 的環境下能夠通訊,我們將上週的`2.py`複製一份,變成`3.py`。 ![](https://i.imgur.com/50Dr4yH.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(r1, r2) Link(h2, 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("ip route add default via 10.0.0.2") r1.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward") r2.cmd("ifconfig r2-eth0 0") r2.cmd("ifconfig r2-eth1 0") r2.cmd("ip addr add 10.0.0.2/24 brd + dev r2-eth0") r2.cmd("ip addr add 192.168.2.254/24 brd + dev r2-eth1") r2.cmd("ip route add default via 10.0.0.1") r2.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward") CLI(net) net.stop() ``` > 1. `r1.cmd("ip route add default via 10.0.0.2")`=`r1.cmd("ip route add 192.168.2.0/24 via 10.0.0.2")` > 2. `r2.cmd("ip route add default via 10.0.0.1")`=`r2.cmd("ip route add 192.168.1.0/24 via 10.0.0.1")` 儲存後,執行`python 3.py`,並且測試雙方通訊是否正常。 ``` root@vm2:/home/user/mininet/examples# python 3.py mininet> h1 ping h2 -c 3 PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data. 64 bytes from 192.168.2.1: icmp_seq=1 ttl=62 time=0.159 ms 64 bytes from 192.168.2.1: icmp_seq=2 ttl=62 time=0.178 ms 64 bytes from 192.168.2.1: icmp_seq=3 ttl=62 time=0.082 ms --- 192.168.2.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.082/0.139/0.178/0.043 ms mininet> h2 ping h1 -c 3 PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. 64 bytes from 192.168.1.1: icmp_seq=1 ttl=62 time=0.112 ms 64 bytes from 192.168.1.1: icmp_seq=2 ttl=62 time=0.111 ms 64 bytes from 192.168.1.1: icmp_seq=3 ttl=62 time=0.159 ms --- 192.168.1.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.111/0.127/0.159/0.024 ms mininet> ``` --- ### 在2台不同網路環境下的 Router 透過 NAT 轉換去實現通訊 接下來將`3.py`繼續做延伸,其中的拓樸不變,而網路環境會分成**私人網域**以及**公有網域**,其中 h1 (私人網域) 是能 ping 到 h2 (公有網域),而 h2 (公有網域) 不能 ping 到 h1 (私人網域),如下圖: ![](https://i.imgur.com/vHaS0Gd.png) 其中特別注意的是,在私人網域轉換成公有網域,需要進行 **NAT 轉換**,且在公有網域的 IP 設定以及 IP 規則設定也需要重新撰寫,因此接下來我們將`3.py`複製一份變成`4.py`。 ``` #!/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") 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() ``` > 1. **NAT 轉換**: `r1.cmd("iptables -t nat -A POSTROUTING -o r1-eth1 -s 192.168.1.0/24 -j MASQUERADE")` > **-t(translate): 轉換成 NAT** > **-A(after): 轉換完之後使用 POSTROUTING** > **-o(output): 封包傳輸選擇的出口是 r1-eth1** > **-s(source): 來源端是 192.168.1.0/24** > **-j(jump): jump to** > **MASQUERADE: 做 Network Address 的轉換** > 2. **ip route 規則說明**: 對 R1 而言,假設要通訊到 H2 的網域 22.1.1.2/24,我們選擇它的下一跳是 r2-eth0,以此類推。 測試是否成功,我們執行`python 4.py`,進入到 mininet 的環境,h1 去 ping 看看能不能通訊。 ``` root@vm2:/home/user/mininet/examples# python 4.py mininet> mininet> h1 ping h2 -c 3 PING 22.1.1.1 (22.1.1.1) 56(84) bytes of data. 64 bytes from 22.1.1.1: icmp_seq=1 ttl=62 time=0.090 ms 64 bytes from 22.1.1.1: icmp_seq=2 ttl=62 time=0.200 ms 64 bytes from 22.1.1.1: icmp_seq=3 ttl=62 time=0.104 ms --- 22.1.1.1 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 0.090/0.131/0.200/0.049 ms mininet> ``` 其中我們可以開啟2個 Router 以及 h1,使用`xterm r1 r1 h1` 而2台 Router 分別開啟 wireshark,監控的接口 選擇 r1-eth0, r1-eth1。 而 h1 去執行`ping 22.1.1. -c 3`的動作,去查看2台 wireshark IP 轉換的情形 我們在監控 r1-eth0 的接口時可以看到,來源端是 192.168.1.1,而目的端是 22.1.1.1。 ![](https://i.imgur.com/0Jt6DGy.png) 而當我們看到 r1-eth1 的接口時可以看到,**來源端的 IP 原本是 192.168.1.1,轉換成了 12.1.1.1。而從 h2 發送封包回 h1 時,目的端的 IP 會先到 r1-eth0 的接口,而封包到達 r1-eth0 時,封包內的 IP 會再轉換成 h1 的 IP (可以透過上圖得知)**,因此可以驗證了當封包傳輸時,在經過 Router 時進行了 NAT 的轉換。 ![](https://i.imgur.com/HKVdJ5I.png) 而當發生了 ping 不通需要 debug 的情形時,也可以透過 wireshark 這項工具進行監控,去查找哪個步驟發生了錯誤。 > 1. debug 的原則為 (以 h1 為範例): 先 ping localhost (127.0.0.1),在 ping 自己的 IP (192.168.1.1),在 ping 預設路由 (192.168.1.254),最後在 ping Internet 的 IP Address (12.1.1.1),以此類推。 而 h2 是 ping 不到 h1 的 ``` mininet> h2 ping h1 -c 3 PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. From 22.1.1.254 icmp_seq=1 Destination Net Unreachable From 22.1.1.254 icmp_seq=2 Destination Net Unreachable From 22.1.1.254 icmp_seq=3 Destination Net Unreachable --- 192.168.1.1 ping statistics --- 3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2000ms mininet> ``` 我們做完了 Router 的部分,接下來會將 Router 的網路設備會變成 Switch (bridge)! --- ### 在 mininet 的環境中實現 bridge 功能 當我們的網路設備是 **“Switch”** or **“Bridge”** 時,我們如何在 Mininet 環境中去達到互相通訊呢? 拓樸如下: ![](https://i.imgur.com/aCSCLdJ.png) 特別注意的是,我們在開始實驗之前,我們需要先安裝一個套件`bridge-utils`,使用`apt install bridge-utils`去進行安裝,而這個套件主要會將一般的 node 變成 bridge。 我們可以創建一個檔案叫`5.py` ``` #! /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") 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() ``` **1. 那如何透過程式把 node 變成 bridge 的?** 我們可以先執行`5.py`,接著在 mininet 的環境使用`xterm br1`,接著執行`brctl -h` ![](https://i.imgur.com/yn7YTI4.png) > 1. brctl (bridge control): 橋接器的控制器 > 2. addbr (add bridge): 新增一個 bridge > 3. br1: bridge 的名稱 創建好 bridge 之後,可以在 br1 執行`brctl show`,去查看 bridge 的資訊,可以看到目前的 bridge 沒有任何 interfaces 連接。 ``` # brctl show bridge name bridge id STP enabled interfaces mybr 8000.5e25f337ee19 no ``` **2. 那如何讓 interface 去連接 bridge 呢?** 我們可以使用`brctl addif + bridge_name + device_interface` > 1. addif (add interface): 在 bridge 新增一個 interface 將`br1-eth0`、`br1-eth1`、`br1-eth2`新增上去後,我們在使用`brctl show`去查看,可以看到: ![](https://i.imgur.com/QQxO9Zu.png) 現在 interface 已經有連接至 bridge 了,接著我們可以去使用`ifconfig`去進行查看。 可以看到,剛剛所創建的 br1 並沒有出現在`ifconfig`內。 ``` mininet> br1 ifconfig br1-eth0 Link encap:Ethernet HWaddr 3e:b2:4b:1f:87:4a inet6 addr: fe80::3cb2:4bff:fe1f:874a/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:10 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:828 (828.0 B) br1-eth1 Link encap:Ethernet HWaddr 46:0f:3f:e3:3f:72 inet6 addr: fe80::440f:3fff:fee3:3f72/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:648 (648.0 B) br1-eth2 Link encap:Ethernet HWaddr ae:6b:f4:da:29:e2 inet6 addr: fe80::ac6b:f4ff:feda:29e2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:648 (648.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) ``` 事實上,br1 這個 interface 是已經有創建好了,只不過還沒啟動而已 ``` mininet> br1 ifconfig -a br1 Link encap:Ethernet HWaddr 3e:b2:4b:1f:87:4a BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) br1-eth0 Link encap:Ethernet HWaddr 3e:b2:4b:1f:87:4a inet6 addr: fe80::3cb2:4bff:fe1f:874a/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:10 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:828 (828.0 B) br1-eth1 Link encap:Ethernet HWaddr 46:0f:3f:e3:3f:72 inet6 addr: fe80::440f:3fff:fee3:3f72/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:648 (648.0 B) br1-eth2 Link encap:Ethernet HWaddr ae:6b:f4:da:29:e2 inet6 addr: fe80::ac6b:f4ff:feda:29e2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:648 (648.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) ``` 因此我們可以使用`ifconfig br1 up`去啟動 br1。 而我們再去執行 ping 的動作,可以看到所有的 host 都能互相通訊了。 ``` mininet> h1 ping h2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. 64 bytes from 192.168.10.2: icmp_seq=1 ttl=64 time=0.135 ms ^C --- 192.168.10.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.135/0.135/0.135/0.000 ms mininet> h1 ping h3 PING 192.168.10.3 (192.168.10.3) 56(84) bytes of data. 64 bytes from 192.168.10.3: icmp_seq=1 ttl=64 time=0.128 ms ^C --- 192.168.10.3 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.128/0.128/0.128/0.000 ms mininet> h2 ping h3 PING 192.168.10.3 (192.168.10.3) 56(84) bytes of data. 64 bytes from 192.168.10.3: icmp_seq=1 ttl=64 time=0.091 ms ^C --- 192.168.10.3 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.091/0.091/0.091/0.000 ms ``` 因此我們`5.py`的程式對於 node 設定成 bridge 只需要加上這幾行程式,就可以實現出 bridge 的功能了! ``` 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") ``` 因此這裡是完整的 code: ``` #! /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") 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() ``` 為了要驗證這個 node 是有 bridge 的功能,我們在 mininet 使用`xterm h2`,並在 h2 的終端機執行`tcpdump -i h2-eth0` > 1. tcpdump: 可以擷取通過某個網路介面的封包 > 2. -i: interface 接著讓 h1 去 ping h3,可以看到: ![](https://i.imgur.com/sQCuIGa.png) 當我們在 ping h3 的時候,h2 是監聽不到任何封包,因此可以驗證 bridge 的特性。 --- ### bridge 的環境中將2個不同的網域彼此獨立,同網域能進行通訊 剛剛的實驗可以看到將一般的 node 變成 bridge,接下來我們將原本的拓樸進行延伸,將 Host 數目增加為4個,其中 h1, h2 屬於 192.168.10.0/24 的網域,而 h3, h4 屬於 192.168.20.0/24 的網域,而10的網域是不能通訊到20的網域,反之亦然。 ![](https://i.imgur.com/LaZsAoi.png) 因此我們將`5.py`複製一份為`6.py` ``` #! /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") h3.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("ifconfig h4-eth0 192.168.20.2/4") CLI(net) net.stop() ``` > 1. `ifconfig h4-eth0 192.168.20.2/4`是另一種設定 IP addr 的做法。 儲存後,執行`6.py`,可以看到說 h1 ping h2 是可以互通的,但是 h1 在 ping 20網域的 host 是 ping 不通的,而 h3 在 ping 的情形也是一樣的,因此這個實驗是成功的。 ``` root@vm2:/home/user/mininet/examples# python 6.py mininet> h1 ping h2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. 64 bytes from 192.168.10.2: icmp_seq=1 ttl=64 time=0.104 ms ^C --- 192.168.10.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.104/0.104/0.104/0.000 ms mininet> h1 ping h3 connect: Network is unreachable mininet> h1 ping h4 connect: Network is unreachable mininet> h3 ping h4 PING 192.168.20.2 (192.168.20.2) 56(84) bytes of data. 64 bytes from 192.168.20.2: icmp_seq=1 ttl=64 time=0.142 ms ^C --- 192.168.20.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.142/0.142/0.142/0.000 ms mininet> h3 ping h1 connect: Network is unreachable mininet> h3 ping h2 connect: Network is unreachable mininet> ``` --- ### bridge + router 去實現在不同網域之間彼此互相通訊 上一個實驗是當有2個網域時,bridge 該怎麼去處理同一區網的連線問題,接下來我們要將 switch 與 router 結合,並且讓不同網域之間能互相通訊,拓樸如下: ![](https://i.imgur.com/oo6gt4B.png) 我們將`6.py`複製一份為`7.py`: ``` #! /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() ``` > 1. 對於 h1, h2 而言,它的內定路由為 192.168.10.254/24,對於 h3, h4 而言,它的內定路由為 192.168.20.254/24。 ``` root@vm2:/home/user/mininet/examples# python 7.py mininet> h1 ping h2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. 64 bytes from 192.168.10.2: icmp_seq=1 ttl=64 time=0.125 ms ^C --- 192.168.10.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.125/0.125/0.125/0.000 ms mininet> h1 ping h3 PING 192.168.20.1 (192.168.20.1) 56(84) bytes of data. 64 bytes from 192.168.20.1: icmp_seq=1 ttl=63 time=0.273 ms ^C --- 192.168.20.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.273/0.273/0.273/0.000 ms mininet> h1 ping h4 PING 192.168.20.2 (192.168.20.2) 56(84) bytes of data. 64 bytes from 192.168.20.2: icmp_seq=1 ttl=63 time=0.200 ms ^C --- 192.168.20.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.200/0.200/0.200/0.000 ms mininet> h3 ping h4 PING 192.168.20.2 (192.168.20.2) 56(84) bytes of data. 64 bytes from 192.168.20.2: icmp_seq=1 ttl=64 time=0.143 ms ^C --- 192.168.20.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.143/0.143/0.143/0.000 ms mininet> h3 ping h1 PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data. 64 bytes from 192.168.10.1: icmp_seq=1 ttl=63 time=0.134 ms ^C --- 192.168.10.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.134/0.134/0.134/0.000 ms mininet> h3 ping h2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. 64 bytes from 192.168.10.2: icmp_seq=1 ttl=63 time=0.118 ms ^C --- 192.168.10.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.118/0.118/0.118/0.000 ms mininet> ``` 執行後,雖然可以進行互 ping,但對於 router 這樣的 link 而言,還需要多一個 interface 去配置,這樣的方法不太實用,因此下方的實驗將 r1 的 link 變為一個,並具有能相互通訊的功能。 --- ### 在 router + bridge 的環境中結合 vlan & trunk 去實現單臂路由的功能 在開始這個實驗之前,我們需要先安裝`vlan`,使用`apt install vlan`去進行安裝。 其中 vlan 最大的優點在於,可以建立虛擬介面,因此 bridge 的 br1-eth4 的介面會多了 “.10” 以及 “.20” 的虛擬介面,同理在 r1 的 r1-eth0 的介面中也會有兩個虛擬介面 “.10” 以及 “.20”,我們可以對 r1-eth0 的虛擬介面進行 IP addr 的設定。 而 router 以及 bridge 所連接的 link 稱為***單臂路由***。 拓樸如下: ![](https://i.imgur.com/DgwIyKo.png) 我們將`7.py`複製一份為`8.py` ``` #! /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") 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() ``` 執行後,開啟 r1, br1 終端機,執行`ifconfig`除了可以看到實體介面之外,虛擬介面 “.10”, “.20” 也會根據 vlan 去建立起來。 ![](https://i.imgur.com/wNFipMO.png) 除此之外,我們可以開啟 wireshark,去監控 br1-eth4。 結果可以看到,在 192.168.10.1 發送封包到 192.168.20.1 時,會在封包內打上一個 “10” 的標籤,同理,當 192.168.20.1 發送封包回 192.168.10.1 時,也會被打上一個 “20” 的標籤。 ![](https://i.imgur.com/1IFXdNu.png) ![](https://i.imgur.com/MmcEERW.png) 其中要注意的是,**透過單臂路由去連接 bridge,也被稱為 trunk link**,**封包在經過 trunk link 時會被打上標籤**,**而 br1 與 host 們相連的 link 稱為 access link**,**是不帶標籤的**。而 vlan 在 bridge 與 router 相互連接的 interface 中,能夠產生出虛擬介面 “.10”, ".20",進而去實現單一條 link 進行不同網域的轉發以及相互通訊功能。 --- ## sed 縮排程式的空白行 當你的程式碼是從網路上進行複製,而程式碼在編輯時會出現每行都有空白行,要解決這種問題可以使用`sed -i '/^$/d' test.py`去將空白行刪除,並縮排好程式碼,讓開發人員能夠更便利的去開發、撰寫程式。 > 1. `/^$`: ^: 起始,$: 結尾,**正則匹配**用法。 > 2. 當`^$`中間沒有任何符號或數字,代表匹配空白行,並且刪除它。 --- ## Reference 1. Youtube video (Mininet ep.1 ~ ep.6): https://www.youtube.com/user/smallko2007/videos 2. bridge & switch & hub 介紹: https://notfalse.net/66/repeater-hub-bridge-switch 3. access link & trunk link: https://kknews.cc/zh-tw/code/zpnbozl.html 4. 單臂路由: https://www.itread01.com/content/1539320530.html