# 網路模擬與分析(3/08):透過 Python 進行自動化運維 & 在 Mininet 中使用 Iperf (封包測量工具) + gnuplot (繪圖套件) ###### tags: `Mininet`、`Iperf`、`Ansible`、`EVE-NG`、`gnuplot` ## 安裝 python 套件 : pip & 安裝 paramiko 安裝 ppa ``` add-apt-repository ppa:deadsnakes/ppa ``` 更新套件&升級套件 ``` apt-get update && apt-get upgrade -y ``` 檢查 python 版本 ``` root@vm2:/home/user# python3 --version Python 3.5.2 ``` 使用`curl`下載 pip 安裝包 ``` root@vm2:/home/user# curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o get-pip.py % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1863k 100 1863k 0 0 283k 0 0:00:06 0:00:06 --:--:-- 460k ``` 並使用`sudo python3 get-pip.py --force-reinstall`進行安裝 **若有出現以下問題,代表你下載的套件包與 python 版本不符,需要下載正確的版本** ``` root@vm2:/home/user# sudo python3 get-pip.py --force-reinstall ERROR: This script does not work on Python 3.5 The minimum supported Python version is 3.6. Please use https://bootstrap.pypa.io/pip/3.5/get-pip.py instead. ``` 下載 paramiko ``` pip install paramiko ``` --- ## 使用 EVE-NG 建立拓樸 在VMWare 開啟 EVE 虛擬機,並登入給予的網址`192.168.102.158` ![](https://i.imgur.com/LCB50cX.png) 在瀏覽器輸入該網址並建立一個 lab,即可看到以下畫面。 ![](https://i.imgur.com/pVrREdS.png) 新增一個節點 Router,其配置如下 ![](https://i.imgur.com/utIdJ9e.png) 新增一個網路,其配置如下 ![](https://i.imgur.com/QTD3z88.png) 最後我們在新增2個節點,而該拓樸圖如下 ![](https://i.imgur.com/qFD6mjH.png) --- ### 設定 R1 的 dhcp/ssh 功能 將 Router 設定成 dhcp,並且查看該 IP ``` Router>en Router#conf t Router(config)#hostname R1 R1(config)#int e0/2 R1(config-if)#ip addr dhcp R1(config-if)#no sh R1(config-if)# *Dec 31 23:01:48.082: %DHCP-6-ADDRESS_ASSIGN: Interface Ethernet0/2 assigned DHCP address 192.168.102.159, mask 255.255.255.0, hostname R1 R1(config-if)#do show ip int brief Interface IP-Address OK? Method Status Protocol Ethernet0/0 unassigned YES unset administratively down down Ethernet0/1 unassigned YES unset administratively down down Ethernet0/2 192.168.102.159 YES DHCP up up Ethernet0/3 unassigned YES unset administratively down down R1(config-if)# Translating "pnpntpserver.localdomain"...domain server (192.168.102.2) ``` 開啟一台虛擬機,與 R1 進行 ping 的傳輸 ``` root@vm2:/home/user# ping 192.168.102.159 PING 192.168.102.159 (192.168.102.159) 56(84) bytes of data. 64 bytes from 192.168.102.159: icmp_seq=1 ttl=255 time=0.903 ms 64 bytes from 192.168.102.159: icmp_seq=2 ttl=255 time=2.87 ms ^C --- 192.168.102.159 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.903/1.888/2.874/0.986 ms root@vm2:/home/user# ``` 回到 R1 設定 ssh 的帳號、密碼 ``` R1(config-if)#username cisco privilege 15 password ci sco R1(config)#ip domain-name test.com R1(config)#crypto key generate rsa The name for the keys will be: R1.test.com Choose the size of the key modulus in the range of 360 to 4096 for your General Purpose Keys. Choosing a key modulus greater than 512 may take a few minutes. How many bits in the modulus [512]: 1024 % Generating 1024 bit RSA keys, keys will be non-exportable... [OK] (elapsed time was 0 seconds) R1(config)# *Dec 31 23:11:23.368: %SSH-5-ENABLED: SSH 1.99 has been enabled R1(config)#ip ssh version 2 R1(config)#line vty 0 4 R1(config-line)#login local R1(config-line)#transport input ssh R1(config-line)# ``` 設定完後,可以回到虛擬機進行 ssh 測試 ``` root@vm2:/home/user# ssh cisco@192.168.102.159 The authenticity of host '192.168.102.159 (192.168.102.159)' can't be established. RSA key fingerprint is SHA256:RWmcEorbsP+ib7reGDGQNFogzE3rFRt8GMev9E36eMQ. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.102.159' (RSA) to the list of known hosts. Password: Password: R1# ``` --- ## 透過 ansible 進行多台 host 的部署 ### 在 ubuntu 下載 Ansible 下載 ansible 相關指令 ``` $ sudo apt update $ sudo apt install software-properties-common $ sudo add-apt-repository --yes --update ppa:ansible/ansible $ sudo apt install ansible ``` 下載完後,在 EVE 建立該拓樸,由於上一個實驗有先建立相同的拓樸,我們只需要重啟 R1,並重新設定 ssh 規則 ![](https://i.imgur.com/Ynx2xXd.png) 設定完後,再重新進行 ssh 連線,接著就會發生以下問題。 ``` root@vm2:/home/user# ssh cisco@192.168.102.159 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the RSA key sent by the remote host is SHA256:qeGdNCj60VTspA1GqXjpny0PGmd0vPO+IO6TWQsH9B8. Please contact your system administrator. Add correct host key in /root/.ssh/known_hosts to get rid of this message. Offending RSA key in /root/.ssh/known_hosts:3 remove with: ssh-keygen -f "/root/.ssh/known_hosts" -R 192.168.102.159 RSA host key for 192.168.102.159 has changed and you have requested strict checking. Host key verification failed. ``` > 解法: ssh-keygen -f "/root/.ssh/known_hosts" -R 192.168.102.159 確認連線成功並`exit`後,先創建一個資料夾`cisco`,並且創建兩個檔案名叫 ‘hosts’, ‘config_cisco.yml’ 1. 'hosts' ``` [cisco] 192.168.102.159 ansible_connection=local ``` > **設定要管理的機器,這邊我們使用的是"Router"** 2. 'config_cisco.yml' ``` - hosts: 192.168.102.159 # R1 的 ip gather_facts: yes vars: - cisco_host_ip: 192.168.102.159 ssh_username: cisco ssh_password: cisco enable_open: yes enable_password: cisco roles: - config_cisco ``` > **設定該機器的相關變數** 設定完之後,我們接著要根據 cicso_playbook 的格式進行設定 ![](https://i.imgur.com/ojagQwO.png) 因此我們在當前目錄下再創建資料夾`config_cisco`,進入後再創建`tasks`去建立 ansible-playbook 的樹狀圖 再當前目錄下建立檔案 ‘main.yml’ 3. 'main.yml' ``` - name: cisco_description_ssh_certification set_fact: cisco_verification: host: "{{cisco_host_ip}}" username: "{{ssh_username}}" password: "{{ssh_password}}" authorize: "{{enable_open}}" auth_pass: "{{enable_password}}" - name: config e0/0 ios_config: provider: "{{cisco_verification}}" parents: interface Ethernet 0/0 lines: - ip addr 192.168.1.254 255.255.255.0 - no shut - name: config e0/1 ios_config: provider: "{{cisco_verification}}" parents: interface Ethernet 0/1 lines: - ip addr 192.168.2.254 255.255.255.0 - no shut - name: show ip interface ios_command: provider: "{{cisco_verification}}" commands: show ip interface brief register: show_ip_log - name: show_ip_log debug: var: show_ip_log.stdout_lines with_items: show_ip_log.results ``` > **根據 Router 下的 Hosts 去管理多台主機的配置&設定** 儲存後,回到`cisco`的路徑下,使用`tree`查看該樹狀圖 ``` root@vm2:/home/user/cisco/config_cisco# cd .. root@vm2:/home/user/cisco# tree . ├── config_cisco │   └── tasks │   └── main.yml ├── config_cisco.yml └── hosts 2 directories, 3 files ``` > **若未安裝 `tree`,可使用`apt install tree`** 使用`ansible-playbook config_cisco.yml -i hosts`進行配置 ``` PLAY [192.168.102.159] ********************************************************* TASK [Gathering Facts] ********************************************************* [DEPRECATION WARNING]: Distribution Ubuntu 16.04 on host 192.168.102.159 should use /usr/bin/python3, but is using /usr/bin/python for backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for this host. See https://docs.ansible.com/ansible /2.9/reference_appendices/interpreter_discovery.html for more information. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg. ok: [192.168.102.159] TASK [config_cisco : cisco_description_ssh_certification] ********************** ok: [192.168.102.159] TASK [config_cisco : config e0/0] ********************************************** changed: [192.168.102.159] TASK [config_cisco : config e0/1] ********************************************** changed: [192.168.102.159] TASK [config_cisco : show ip interface] **************************************** ok: [192.168.102.159] TASK [config_cisco : show_ip_log] ********************************************** ok: [192.168.102.159] => (item=show_ip_log.results) => { "ansible_loop_var": "item", "item": "show_ip_log.results", "show_ip_log.stdout_lines": [ [ "Interface IP-Address OK? Method Status Protocol", "Ethernet0/0 192.168.1.254 YES manual up up ", "Ethernet0/1 192.168.2.254 YES manual up up ", "Ethernet0/2 192.168.102.159 YES DHCP up up ", "Ethernet0/3 unassigned YES unset administratively down down" ] ] } PLAY RECAP ********************************************************************* 192.168.102.159 : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` 接著可以回到 Router 進行配置檔是否成功? ``` R1(config)#do show ip int brief Interface IP-Address OK? Method Status Protocol Ethernet0/0 192.168.1.254 YES manual up up Ethernet0/1 192.168.2.254 YES manual up up Ethernet0/2 192.168.102.159 YES DHCP up up Ethernet0/3 unassigned YES unset administratively down down ``` --- ## 在 Mininet 環境下使用 Iperf + gnuplot 若未安裝 mininet 可以用`sudo apt-get install mininet` 在家目錄創建資料夾`mininet`,進入後使用`mn`創建拓樸 ``` root@vm2:/home/user/mininet# mn *** Creating network *** Adding controller *** Adding hosts: h1 h2 *** Adding switches: s1 *** Adding links: (h1, s1) (h2, s1) *** Configuring hosts h1 h2 *** Starting controller c0 *** Starting 1 switches s1 ... *** Starting CLI: mininet-wifi> ``` 1. net:查看拓樸資訊 ``` h1 h1-eth0:s1-eth1 h2 h2-eth0:s1-eth2 s1 lo: s1-eth1:h1-eth0 s1-eth2:h2-eth0 c0 ``` 2. xterm s1 h1 h2:在 mininet 開啟 s1, h1, h2 虛擬機 ![s1](https://i.imgur.com/TjAIghA.png) ![h1 h2](https://i.imgur.com/SNh2ZU9.png) > 預設 IP 是 `10.0.0.0/24` 網域 3. pingall:測試該拓樸連線 ``` mininet-wifi> pingall *** Ping: testing ping reachability h1 -> h2 h2 -> h1 *** Results: 0% dropped (2/2 received) ``` 4. h1 ping 10.0.0.2 -c 3:在 Mininet 環境下進行封包測試 ![](https://i.imgur.com/GAeKtaq.png) > `-c(count): + [變數]` --- ### Mininet 進行 HTTP 測試 * 對於 Mininet 的環境下,每一個 Host 都可以視為獨立的主機,因此我們可以做一個簡單的測試。 將 h1 設為 HTTPServer,使用該指令`python -m SimpleHTTPServer 80` ![h1](https://i.imgur.com/htyXHIr.png) 而 h2 可以切換成一般使用者進行 firefox 的測試,去查看 HTTPServer。 ![](https://i.imgur.com/cUrc3Yl.png) h1 的網頁伺服器情形 ![](https://i.imgur.com/j1WMAYv.png) 5. 我們也可以透過封包傳遞的過程,去執行`link h1 s1 down`來模擬網路連線中斷的情形。 ![](https://i.imgur.com/gvEe8jY.png) 使用`link h1 s1 up`可以將 link 重新連線,因此可以看到封包中斷後又重新發送封包到 h2 了。 ![](https://i.imgur.com/CFZeOXT.png) 6. 在 Mininet 執行終端機的內容,可以在 mininet 使用`sh + command`,ex:`sh pwd` ![](https://i.imgur.com/cuV0spX.png) --- ### Iperf 進行網路效能檢測 Iperf 一共有兩種傳輸方式:TCP/UDP,在實驗中,我們將 h1 當作 Client,h2 當作 Server。 1. TCP 封包 h2 [server] 執行`iperf -s -i 1` > `-s`: server > `-i(interval) 1`: 計算吞吐量,週期是一秒一次 h1 [client] 執行`iperf -c 10.0.0.2 -t 15` > `-c`: client > `10.0.0.2`: 指定 server 的 ip,這邊我們使用 h2 的 ip > -t(time/duration): 根據傳輸時間去發送 TCP 封包,預設值是10秒,這邊我們設定15秒。 ![](https://i.imgur.com/xYZsgOE.png) 當 Client 發送後,可以看到 Server 收到了每一秒封包的值,還有0-15秒封包平均值。 ![](https://i.imgur.com/bFgqkGA.png) 2. UDP 封包 h2 [server] 執行`iperf -s -i 1 -u` > `-u`: 指定 UDP 封包 h1 [client] 執行`iperf -c 10.0.0.2 -t 15 -u -b 100M` > `-u`: 指定 UDP 封包 > `-b(badnwidth) 100M`: 封包傳送速率為100M > * TCP 與 UDP 不同在於,TCP 是根據你網路的傳輸速率有多快就會給多快。 ![](https://i.imgur.com/bEJeWhl.png) 我們回到 Server,一樣可以看到每筆封包的數值以及平均。 ![](https://i.imgur.com/glEUP3n.png) 3. 多台 Server 設定 假設你的環境需要多個 Server 測試封包的流量,你可以使用`-p`去區分每個 Server 所屬的埠號。 因此我們可以在 Mininet 在新增一台 h1, h2,使用`xterm h1 h2` h2 [server] 執行`iperf -s -t 1 -u -p 5555` h2 [server] 執行`iperf -s -t 1 -u -p 6666` ![](https://i.imgur.com/xTZHy0T.png) 因此現在2台 Server 有了不同的 port 號後,我們的 Client 就可以對於不同的 Server 去進行連線。 ![](https://i.imgur.com/W4XBjn5.png) --- ### 將數值利用 gnuplot 進行繪圖 上一個實驗我們利用了 Iperf 取得了封包的數值,若你想將數值繪成圖,便可以使用這個套件 gnuplot 將數值繪圖起來。 但是在繪圖之前,我們需要將數據記錄起來,因此我們可以使用`>`將數據導向到所指定的檔案內。 h2 [server] 執行`iperf -s -t 1 -u -p 5555 > udp5555` > udp5555: 所指定的檔案 ‘udp5555’ 而 h1 一樣發送 UDP 封包到 Server`iperf -c 10.0.0.2 -t 10 -b 100M -p 5555` 當 h1 結束後,h2 使用`ctrl + C`結束執行,並且查看 ‘udp5555’ 的檔案內是否有 UDP 的資料? ![](https://i.imgur.com/QXah3Ay.png) 結果可以看到資料進來了,代表 UDP 封包的數據已經記錄起來了 ![](https://i.imgur.com/7oph5pR.png) **接著我們可以使用3個 linux 的文字處理:grep, tr, awk 去取得數據的時間跟吞吐量。** 我們可以從 h2 得知數據後,再近一步的過濾出想要的結果。 因此 “udp5555” 過濾結果的過程會如下方所示 ``` 1. cat udp5555 | grep sec // 過濾出“時間”、“吞吐量”共通有的特徵 2. cat udp5555 | grep sec | head -n 20 // 取前20筆資料 3. cat udp5555 | grep sec | head -n 20 | tr "-" " " // 用空格取代每一筆時間軸的 “-” 4. cat udp5555 | grep sec | head -n 20 | tr "-" " " | awk '{print $4, $8}' // 取出“時間”、“吞吐量”的數值 5. cat udp5555 | grep sec | head -n 20 | tr "-" " " | awk '{print $4, $8}' > result.txt // 將結果映射到 “result.txt” ``` 取出結果後,我們可以在終端機使用`gnuplot`的指令進入到 ‘gnuplot’ 內 ``` root@vm2:/home/user# gnuplot G N U P L O T Version 5.0 patchlevel 3 last modified 2016-02-21 Copyright (C) 1986-1993, 1998, 2004, 2007-2016 Thomas Williams, Colin Kelley and many others gnuplot home: http://www.gnuplot.info faq, bugs, etc: type "help FAQ" immediate help: type "help" (plot window: hit 'h') Terminal type set to 'qt' gnuplot> ``` 接著選擇 result.txt 進行繪圖`plot "result.txt"` 接著依照你的結果去設定 x 軸, y 軸,以我的例子是: ``` set yrange [0:30] set ytics 0,5,30 replot set xrange [0:20] set xtics 0,1,20 replot plot "result.txt" with linespoints set xlabel "tine (sec)" set ylabel "throughput (Mbis/sec)" replot set title "udp throughput" replot ``` > `xrange`,`yrange`: x 軸, y 軸參數的範圍 > `xtics`,`ytics`: x 軸, y 軸每個參數之間的間隔 > `xlabel`,`ylabel`: x 軸, y 軸的 label > `title`: 圖片的 title > `replot`: 更新 繪製完圖片後,將格式轉為 gif 檔`set terminal "gif"` 將圖片儲存成 gif 檔`set output "result.gif"`,並且`replot`。 最後你就可以得到一份完整的結果圖了 ![](https://i.imgur.com/0F6AnkK.png) --- ## Reference 1. iperf intro : https://m1016c.pixnet.net/blog/post/145780230 2. iperf command : https://linuxhint.com/iperf_command_usage/ 3. p4-bmv2 download : https://github.com/p4lang/behavioral-model 4. p4c download : https://github.com/p4lang/p4c