# DPDK 安裝 & 環境架設 DPDK 安裝流程、VM 部署、官方 sample 運行。 ###### tags: `dpdk` ## 安裝、配置 ### 檢查&設定 hugepage ```shell # xxxx 視 kernel 版本而定 (按 tab 自動補齊) grep -i huge /boot/config-......... grep -i huge /proc/meminfo ``` * 有下列兩行表示支援目前的系統 hugepage ``` CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y ``` **配置 hugepage (暫時配置,每次重新開機後須重新設定)** ```shell echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages # 檢查 cat /proc/meminfo | grep Huge sudo mkdir /mnt/huge sudo mount -t hugetlbfs nodev /mnt/huge sudo sysctl -w vm.nr_hugepages=1024 ``` **每次開機後自動掛載(未設定成功,原因不明,每次開機後仍然執行上方暫時配置的指令)** ```shell vim /etc/fstab # 加入 nodev /mnt/huge hugetlbfs defaults 0 0 ``` ### 安裝 & 編譯 DPDK **若使用 vmware(等虛擬機),必須先使用修補檔** - 先下載 [patch](http://patches.dpdk.org/patch/11622/) - [patch 使用說明](https://blog.longwin.com.tw/2013/08/linux-diff-patch-learn-note-2013/),以 `patch -p0 < xxx.patch` 啟動並輸入要更新的檔案路徑。 - 路徑: `/home/yen/dpdk-stable-18.11.2/kernel/linux/igb_uio/igb_uio.c` **安裝相關套件** ```shell sudo apt-get update sudo apt-get install -y python libpcap-dev build-essential linux-headers-`uname -r` libnuma-dev pkg-config gcc libnuma-dev libpcre3 libpcre3-dev libssl-dev ``` **下載 & 編譯(這邊使用的是 dpdk-18.11.2 版本)** ```shell ### 下載 wget http://fast.dpdk.org/rel/dpdk-18.11.2.tar.xz tar -xvf dpdk-18.11.2.tar.xz ### 環境變數設 export DPDK_DIR=$HOME/dpdk-stable-18.11.2 export DPDK_TARGET=x86_64-native-linuxapp-gcc export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET export LD_LIBRARY_PATH=$DPDK_DIR/x86_64-native-linuxapp-gcc/lib export RTE_SDK=$HOME/dpdk-stable-18.11.2 export RTE_MACHINE="native" export RTE_TARGET=x86_64-native-linuxapp-gcc ## 安裝 cd $DPDK_DIR && sudo make install T=$DPDK_TARGET DESTDIR=install sudo sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/g' ${DPDK_DIR}/config/common_base ``` ### 載入 kernel module & 綁定網卡 DPDK 提供的核心模組內包含了部分網路卡的驅動,利用此核心模組所提供的 API (DPDK library),可以使開發者直接控制網路卡的行為。 ```shell sudo modprobe uio sudo modprobe vfio-pci sudo insmod $HOME/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko sudo insmod $HOME/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko kthread_mode=multiple carrier=on # 使用 usertools 內的工具進行設定 cd $HOME/dpdk-stable-18.11.2/usertools # 查看目前網路卡搭載的驅動狀態 sudo $HOME/dpdk-stable-18.11.2/usertools/dpdk-devbind.py --status # 卸載指定網卡當前所搭載的驅動 sudo $HOME/dpdk-stable-18.11.2/usertools/dpdk-devbind.py -u 00:08.0 # 指定驅動與網卡做綁定 sudo $HOME/dpdk-stable-18.11.2/usertools/dpdk-devbind.py -b igb_uio 0000:00:08.0 # 最後檢查 sudo $HOME/dpdk-stable-18.11.2/usertools/dpdk-devbind.py --status ``` **卸載 module** ```shell sudo rmmod /home/yen/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko sudo rmmod /home/yen/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko ``` ### 設定 shared file (library) 若執行 DPDK 程式出現 shared file error 等訊息,依照下列指令將編譯後的 dpdk 函式庫加入 shared file。 編輯 `/etc/ld.so.conf` ,加入 DPDK library。 ``` $ sudo vim /etc/ld.so.conf # 加入 /home/使用者名稱/dpdk-stable-18.11.2/install/lib /home/使用者名稱/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/lib $ sudo ldconfig ``` ### 簡易操作腳本 - 5,6 做 Bind 的部分需要按照的裝置自行調整 ```shell while((1));do echo "1. Set hugepage" echo "2. Insert modules" echo "3. Remove modules" echo "4. Show NIC driver status" echo "5. Bind NIC (ens38) with igb_uio" echo "6. Bind NIC (ens38) with e1000" echo "7. Set vEth0 up" echo "U. Install dependencies" echo "D. Remove dpdk directory and unzip again" echo "R. Recompile DPDK package" read -p "Action ?" n case "$n" in 1) echo 1024 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages cat /proc/meminfo | grep Huge sudo mount -t hugetlbfs nodev /mnt/huge sudo sysctl -w vm.nr_hugepages=1024 ;; 2) sudo modprobe uio sudo modprobe vfio-pci sudo insmod /home/$(whoami)/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko sudo insmod /home/$(whoami)/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko kthread_mode=multiple carrier=on ;; 3) sudo rmmod /home/$(whoami)/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko sudo rmmod /home/$(whoami)/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/kmod/rte_kni.ko ;; 4) sudo /home/$(whoami)/dpdk-stable-18.11.2/usertools/dpdk-devbind.py --status ;; 5) sudo ifconfig ens38 down sudo /home/$(whoami)/dpdk-stable-18.11.2/usertools/dpdk-devbind.py -b igb_uio 0000:02:06.0 ;; 6) sudo /home/$(whoami)/dpdk-stable-18.11.2/usertools/dpdk-devbind.py -b e1000 0000:02:06.0 sudo ifconfig ens38 up ;; 7) sudo ip addr add 192.168.0.254/24 dev vEth0 sudo ip -6 addr add 2001:0db8:0:f101::1/64 dev vEth0 sudo ip link set vEth0 up ;; U) sudo apt-get update sudo apt-get install -y python libpcap-dev build-essential linux-headers-`uname -r` libnuma-dev pkg-config gcc libnuma-dev make ;; D) sudo rm -rf /home/$(whoami)/dpdk-stable-18.11.2 tar -xvf dpdk-18.11.2.tar.xz ;; R) export DPDK_DIR=/home/$(whoami)/dpdk-stable-18.11.2 export DPDK_TARGET=x86_64-native-linuxapp-gcc export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET export LD_LIBRARY_PATH=$DPDK_DIR/x86_64-native-linuxapp-gcc/lib export RTE_SDK=$HOME/dpdk-stable-18.11.2 export RTE_MACHINE="native" export RTE_TARGET=x86_64-native-linuxapp-gcc cd $DPDK_DIR && sudo make -j4 install T=$DPDK_TARGET DESTDIR=install sudo sed -i 's/CONFIG_RTE_BUILD_SHARED_LIB=n/CONFIG_RTE_BUILD_SHARED_LIB=y/g' ${DPDK_DIR}/config/common_base esac done ``` ### lcore 隔離 `sudo vim /etc/default/grub` 加入 `isolcpus=2,3,4` 後重新開機。 --- ## 範例程式練習 ### 1. hello world 這個範例程式會根據執行時選定的 core mask 啟用對應的 core,並讓每個 core 執行 hello world。 ```shell #刪除所有 export 的環境變數 #$ unset GNUPLOT_DRIVER_DIR cd examples/helloworld/ export RTE_SDK=$HOME/dpdk-stable-18.11.2 export RTE_TARGET=x86_64-native-linuxapp-gcc make && sudo ./build/helloworld -c 3 -n 2 ``` - `-c`: core mask,3 表示啟用 core 0,1(3 = 00000011) - `-n`: memory channel 的數量 執行結果: ![](https://i.imgur.com/xTpiQN9.png) ### 2. 以 KNI (虛擬網卡)進行封包轉發 KNI 模擬 Linux network interface 的功能,會和 kernel 做溝通,讓使用者可以操作 ethtools。 1. 編譯&執行 ```shell cd examples/kni/ export RTE_SDK=$HOME/dpdk-stable-18.11.2 export RTE_TARGET=x86_64-native-linuxapp-gcc make && sudo ./build/kni -c 0xf0 -n 2 -- -P -p 0x1 --config="(0,4,5)" ``` - `-c`: core mask,0xf 表示使用 core 0,1,2,3 (4 = 00001111) - `-n`: memory channel 的數量 - `-P`: 混雜模式 - `-p`: port mask,0x3 表示使用 2個 ports(兩張網卡) - `--config=`"(port_ID,TX_coreID,RX_coreID)" 2. 設定 vEth 網卡的 IP 並啟動 ```shell sudo ip addr add 192.168.0.254/24 dev vEth0 sudo ip -6 addr add 2001:0db8:0:f101::1/64 dev vEth0 sudo ip link set vEth0 up sudo ip addr add 192.168.1.254/24 dev vEth1 sudo ip link set vEth1 up ``` * 設定後 `ifcofig` 觀察目前網路介面,經由 KNI 建立的網路經面為: vEth0 ![](https://i.imgur.com/YG7HPYa.png) * 使用 tcpdump 查看流經 vEth0 的封包(ping 測試) ![](https://i.imgur.com/PnoBmZ0.png) ### 3. nDPI + l3fwd - 需使用2張網路卡(2個 port 1. 編譯,因為使用了 nDPI 和 DPDK 的 libraries ,所以必須 export 兩個 libraries 的位置 ```shell ### 設置環境變數(找不到環境變數時就要設定一次) export RTE_SDK=$HOME/dpdk-stable-18.11.2 export RTE_TARGET=x86_64-native-linuxapp-gcc export nDPI_src=$HOME/nDPI ### 使用 --eth-dest 指定 port 連接目標的 MAC make && sudo ./build/nDPIexe -c 0xf -n 4 -- -L -p 0x7 --config="(0,0,0),(1,0,1),(2,0,2)" --parse-ptyp --eth-dest=0,68:b5:99:b6:d3:5d --eth-dest=1,68:b5:99:b6:d3:75 --eth-dest=2,b4:96:91:65:62:ab -- -n2 make && sudo ./build/nDPIexe -c 0xf -n 4 -- -L -p 0x7 --config="(0,0,0),(1,0,1)" --parse-ptyp --eth-dest=0,68:b5:99:b6:d3:5d --eth-dest=1,68:b5:99:b6:d3:75 --eth-dest=2,b4:96:91:65:62:ab -- -n2 ### tcpreplay tcpprep -a bridge -i filtered/slowdownload.pcap -o processed/input.cache tcprewrite --enet-dmac=B4:96:91:65:62:A8,B4:96:91:65:62:A9 --enet-smac=68:b5:99:b6:d3:5d,68:b5:99:b6:d3:75 --endpoints=192.168.1.100:192.168.2.100 -m1500 -i filtered/slowdownload.pcap -o processed/out.pcap -c processed/input.cache sudo tcpreplay -l10 -t -c processed/input.cache -i enp5s0f1 -I enp4s0f1 processed/out.pcap ### tshark tshark -n -r"packets_default.pcap" -Y "tcp.stream > 0 and tcp.stream < 100" -w tmp.pcap ### perf ps aux | grep "nDPI" | awk 'NR==2{print $2}' | xargs sudo perf top -p ### kill process ps aux | grep "nDPI" | awk 'NR==2{print $2}' | xargs sudo kill -9 ``` 目前連線狀況: ![](https://i.imgur.com/Aeh0CO8.png) 2. 設定 static arp 跟 route 因為目前的轉發程式內沒有支援 ARP reply 與 ARP cache 的功能,所以需要透過設定 static ARP。 - 設定路由 (netplan 設置、route -n 檢查) - 設定 static ARP **netplan 設置(路由設定參考)** client-1 ``` network: ethernets: ens33: addresses: [192.168.44.130/24] nameservers: addresses: [8.8.8.8,8.8.4.4] dhcp4: no ens38: dhcp4: no addresses: [192.168.0.101/24] routes: - to: 192.168.1.0/24 via: 192.168.0.10 version: 2 ``` **Static ARP 設置** - 指令: `arp -s target_IP target_MAC_addr` - 需確定與主機連線的 port 與 MAC addr client_1 ```shell sudo arp -s 192.168.0.10 B4:96:91:65:62:A8 ``` 3. 使用 `tcpreplay` 發送封包進行測試 - `tcpprep` 將封包進行分流並存成 cache 檔 - `rewrite` 依據 cache 檔的分流紀錄改寫封包內容 - `tcpreplay` 將指定的 pcap 檔從指定的介面發送 ## 函式介紹 ```C static uint16_t rte_eth_tx_burst( uint16_t port_id, uint16_t queue_id, struct rte_mbuf ** tx_pkts, uint16_t nb_pkts ) ``` - port_id: 識別網路介面的編號 - queue_id: 識別各介面底下佇列的編號 - tx_pkts: 欲傳送封包所在的記憶體地址(可能多個封包,因此是一陣列用於紀錄多個記憶體地址) - nb_pkts: 欲傳送的封包數量上限 [pcre 函式說明](http://man7.org/linux/man-pages/man3/pcre_compile.3.html)