Try   HackMD

DPDK 安裝 & 環境架設

DPDK 安裝流程、VM 部署、官方 sample 運行。

tags: dpdk

安裝、配置

檢查&設定 hugepage

# xxxx 視 kernel 版本而定 (按 tab 自動補齊)
grep -i huge /boot/config-......... 
grep -i huge /proc/meminfo
  • 有下列兩行表示支援目前的系統 hugepage
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y

配置 hugepage (暫時配置,每次重新開機後須重新設定)

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

每次開機後自動掛載(未設定成功,原因不明,每次開機後仍然執行上方暫時配置的指令)

vim /etc/fstab
# 加入
nodev /mnt/huge hugetlbfs defaults 0 0

安裝 & 編譯 DPDK

若使用 vmware(等虛擬機),必須先使用修補檔

  • 先下載 patch
  • patch 使用說明,以 patch -p0 < xxx.patch 啟動並輸入要更新的檔案路徑。
  • 路徑:
    /home/yen/dpdk-stable-18.11.2/kernel/linux/igb_uio/igb_uio.c

安裝相關套件

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 版本)

### 下載
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),可以使開發者直接控制網路卡的行為。

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

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 的部分需要按照的裝置自行調整
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。

#刪除所有 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 的數量
    執行結果:

2. 以 KNI (虛擬網卡)進行封包轉發

KNI 模擬 Linux network interface 的功能,會和 kernel 做溝通,讓使用者可以操作 ethtools。

  1. 編譯&執行

    ​​​​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 並啟動

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

    • 使用 tcpdump 查看流經 vEth0 的封包(ping 測試)

3. nDPI + l3fwd

  • 需使用2張網路卡(2個 port
  1. 編譯,因為使用了 nDPI 和 DPDK 的 libraries ,所以必須 export 兩個 libraries 的位置
### 設置環境變數(找不到環境變數時就要設定一次)
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

目前連線狀況:

  1. 設定 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

    ​​​​sudo arp -s 192.168.0.10 B4:96:91:65:62:A8
    
  2. 使用 tcpreplay 發送封包進行測試

  • tcpprep 將封包進行分流並存成 cache 檔
  • rewrite 依據 cache 檔的分流紀錄改寫封包內容
  • tcpreplay 將指定的 pcap 檔從指定的介面發送

函式介紹

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 函式說明