2020년 10월 25일 일요일

DPDK와 FD.io VPP로 고성능 Security Gateway 만들기

이번 posting에서는 open source project인 DPDK와 FD.io VPP(Vector Packet Processing)를 이용하여 고성능 네트워크 장비를 만드는 방법을 소개해 보고자 한다. 이제 더 이상 ASIC이나 FPGA 방식은 잊어라~ S/W만으로도 충분하다.  😎




목차
1. DPDK와 FD.io VPP 소개
2. MACCHIATObin 보드(ARM64)에서 VPP 돌려 보기
3. Intel PC(x86_64)에서 VPP 돌려 보기
4. VPP Wireguard plugin 시험하기
5. VPP 관련 그 밖의 관심있는 주제
6. References



1. DPDK와 FD.io VPP 소개
Intel or AMD CPU 기반의 산업용 network appliance(값싼 장비)를 사용하면서도 ASIC이나 FPGA 등으로 무장한 h/w network 장비(고가의 장비)에 필적하는 성능을 낼 수 있다면 얼마나 좋을까 ?  사실 이 질문에 답을 찾기 위한 노력은 그동안 꾸준히 진행(지난 10여년간 ...)되어 왔는데, 이에 대한 확실한 답을 제시하고 있는 두가지 open source project가 있어 여기에서 소개하고자 한다.

Intel DPDK and FD.io VPP
[그림 1.1] SUPERMICRO 5019-FTN4 [출처 - 참고문헌 6]

📌 참고로 위의 Appliance 장비는 AMD EPYC 3251 CPU(8-Core)를 사용하고, 4개의 GbE(Intel i350-AM4) 포트가 장착되어 있다. 이 정도면 Ubuntu server(18.04)를 설치하고, 그 위에서 DPDK & VPP를 돌리기에 무리가 없을 듯 보인다.

우선 DPDK(Data Plane Development Kit)는 아래 그림과 같이 Linux kernel의 고질적인 네트워크 성능 문제(대용량 network traffic 처리시 interrupt & system call 등에 의한 속도 저하)를 해결하기 위해 Intel이 주도하여 개발하고 있는 project로 NIC driver(주로 Intel, Marvell, Mellanox 등 중심) 개선과 아울러, kernel이 아닌 user space에서 packet을 처리(polling 방식)하도록 함으로써 network 성능을 획기적으로 향상시키고 있다.


[그림 1.2] DPDK 아키텍쳐 1 [출처 - 참고문헌 3]

📌 User space에서 packet을 처리하기 위해 linux에서 제공하는 UIO(User level i/o) driver가 사용된다.

[그림 1.3] DPDK 아키텍쳐 2 [출처 - 참고문헌 3]

📌 DPDK는 국내에서도 KAIST, ETRI 등을 중심으로 연구가 활발이 진행되고 있으며, 일반 IT 기업에서도 네트워크 장비 개발에 많이 활용하고 있는 듯 보인다.

DPDK를 사용하면 분명 특정 network adapter(예: Intel 82576 Gigabit Ethernet Controller, Intel® 82599 10-Gigabit Ethernet Controller)를 사용한다는 조건하에서 상당한 성능 개선 효과를 얻을 수  있는게 사실이다. 하지만, user space에서 패킷을 처리한다는 것은 kernel에서 제공하는 다양하고 안정성이 검증된 network 기능(예: TCP/IP stack, L2 bridge, L3 routing, Netfilter, IPsec, Wireguard ...)을 전혀 사용할 수가 없다는 얘기가 된다. 물론 DPDK에는 user space에서 사용할 수 있는 몇가지 간단한  예제도 함께 제공되고 있기는 하지만, 이를 상용 제품에 활용하기에는 무리가 있다. 따라서 linux kernel에서 제공하는 수준의 안정적이면서도 다양한 network 기능을 구현해야 하는 숙제가 남게 된다. 과연 이를 어찌하면 좋을까 ? 

눈치채셨겠지만, 이를 한방에 해결해 줄 수 있는 후보가 바로  FD.io VPP이다. FD.io VPP는 (network 장비 업계의 최강자) Cisco가  2002년 부터 오랫동안 개발해 오던 것을 open source화한 것으로 아래와 같은 두가지 특징을 갖는다.

1. Vector Packet Processing 기법을 이용하여  획기적인 성능 개선
2. 상용 제품으로 바로 사용 가능한 다양한 기능 제공


FD.io VPP(Cisco)에서 말하는 Vector Packet Processing은 
packet을 한번에 하나씩 처리하는 기존의 Scalar Packet Processing과 대비되는 개념으로, 아래 그림 1.4 ~ 1.6과 같이 여러개의 packet을 모아 한번(동시)에 처리(이를 위해 packet processing graphpacket vector라는 개념이 구현되어 있음)함으로써 packet 처리 속도를 크게 향상시켜준다는 것을 기본 concept으로 하고 있다.


[그림 1.4] Vector Packet  Processing 개념 1 [출처 - https://fd.io/vppproject/vpptech/]

📌 때로는 장황한 설명보다 하나의 그림이 더 효과적일 때가 있다.

[그림 1.5] Vector Packet  Processing 개념 2 [출처 - 참고문헌 2]


[그림 1.6] Vector Packet  Processing 개념 3 [출처 - 참고문헌 5]

📌 DPDK와 VPP 조합은 10G, 40G 정도의 ethernet 환경 쯤은 되어야 효과를 극대화할 수 있다.

이렇듯 DPDK와 VPP를 적절히 활용한다면, 값싸고 우수한 성능의 network 장비(L2 bridge, L3 router, IPsec Gateway, MPLS 장비, Cloud Load Balancer ...)를 쉽게 개발할 수가 있게 된다. 어떤가 한번 도전해 보고 싶은 마음이 들지 않는가 ?


[그림 1.7] DPDK and VPP [출처 - 참고문헌 4 및 12]

📌 DPDK + VPP와 유사한 project로는 DPDK + ODP(Open Data Path), DPDK + OVS(Open vSwitch) 및 XDP 등이 있다.


<여기서 잠깐 ! - eBPF & XDP project에 관하여>
Linux(kernel) 진영에서는 (꼭 그런 것은 아니지만) DPDK에 대한 대항마로 (아직 초기 단계이기는 하지만) kernel에서 동작하는 XDP(eXpress Data Path)를 밀고 있다. 향후 이 둘(XDP vs DPDK) 간의 경쟁 관계도 지켜볼만한 내용이 될 것 같다. eBPF & XDP에 관해서는 필자의 아래 문서를 참고하기 바란다.




2. MACCHIATObin 보드(ARM64)에서 VPP 돌려 보기
이번 장에서는 지난 번 blog posting에서 소개했던 MACCHIATObin 보드에 FD.io VPP를 올리고, 몇가지 네트워크 동작 시험을 진행해 보고자 한다.

MACCHIATObin 보드는 지난 번에도 소개한 바와 같이 network interface(dual 10G copper, dual 10G SFP, 2.5G SFP, 1G copper)가 예술(?)이다. 또한 MACCHIATObin 보드(정확하게 말하자면 Marvell)는 DPDK에 해당하는 MUSDK라는 녀석(SDK)이 존재한다. 따라서 VPP가 제대로된 성능 효과를 누리기 위해서는 이를 사용하도록 porting해 주어야 한다.

[그림 2.1] MACCHATObin 위에 VPP 올리기

[그림 2.2] Marvell MUSDK [출처 - http://macchiatobin.net/]

지금부터 소개하는 내용은 아래 site 내용을 기반으로 정리한 것이다. 


Docker 환경에서 build를 하는 방법도 있으나, (CPU 속도가 충분히 빠르니) 이번에는 target board에서 직접 build를 해 보도록 하자.

<MUSDK (part 1) download 하기>
  => MUSDK를 download 한다.

# cd /root
# git clone https://github.com/MarvellEmbeddedProcessors/musdk-marvell.git -b musdk-armada-17.10 musdk-marvell

<Kernel build 하기>
  => kernel을 download 후 build하도록 한다.

# cd /root
# git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10 linux-marvell

# git am /home/chyi/workspace/VPP/musdk-marvell/patches/linux/*.patch
# make mvebu_v8_lsp_defconfig
# make -j4 Image dtbs modules
# make modules_install
# cp arch/arm64/boot/Image arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtb /boot/

# cd /boot
# ls -la
total 43508
drwxr-xr-x  2 root root     4096 Oct 17 07:42 .
drwxr-xr-x 21 root root     4096 Oct 17 06:54 ..
-rwxr-xr-x  1 root root 12783616 Feb 12  2018 Image
-rw-r--r--  1 root root  2654470 Oct 17 07:42 System.map-4.4.52-armada-17.10.4-g8ac9c68
-rw-r--r--  1 root root    36904 Feb 12  2018 armada-8040-mcbin.dtb
-rw-r--r--  1 root root    88315 Oct 17 07:42 config-4.4.52-armada-17.10.4-g8ac9c68
-rw-r--r--  1 root root  3243678 Oct 17 07:42 initrd.img-4.4.52-armada-17.10.4-g8ac9c68
-rw-r--r--  1 root root 12899840 Oct 17 07:42 vmlinuz-4.4.52-armada-17.10.4-g8ac9c68

kernel image와 dtb가 교체되었으니, 이 상태에서 target board를 재부팅해 준다.

<MUSDK (part 2) build 하기>
  => 이제, 앞서 받아 두었던 MUSDK를 build하도록 한다.

# cd musdk-marvell
# export KDIR=/root/linux-marvell
# ./bootstrap
# ./configure --enable-shared --enable-bpool-dma=64 --enable-bpool-cookie=32 --enable-sam --prefix=/usr
# make -j4
# make install
# cd modules
for i in dmax2 neta pp2 sam uio; do cd $i; make; make -C $KDIR M=`pwd` modules_install; cd -; done

# ls -l /lib/modules/4.4.52-armada-17.10.4-g2a0096d/extra
total 1172
drwxr-xr-x 2 root root   4096 Oct 16 03:26 .
drwxr-xr-x 4 root root   4096 Oct 16 03:24 ..
-rw-r--r-- 1 root root 269232 Oct 16 03:26 musdk_uio.ko
-rw-r--r-- 1 root root 227240 Oct 16 03:24 mv_dmax2_uio.ko
-rw-r--r-- 1 root root 228592 Oct 16 03:25 mv_neta_uio.ko
-rw-r--r-- 1 root root 226792 Oct 16 03:25 mv_pp_uio.ko
-rw-r--r-- 1 root root 232432 Oct 16 03:25 mv_sam_uio.ko

<pp2-sysfs driver build 하기>
  => mvpp2-sysfs driver를 build한다.

# cd /root
git clone https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell.git -b mvpp2x-armada-17.10 pp2_sysfs
cd pp2_sysfs/sysfs/
# cp Makefile_sysfs Makefile
export KDIR=/root/linux-marvell
# export KERNEL_SOURCES=1
# make
# make -C $KDIR M=`pwd`  modules_install

# ls -l /lib/modules/4.4.52-armada-17.10.4-g2a0096d/extra
total 5752
drwxr-xr-x 2 root root    4096 Oct 16 03:31 .
drwxr-xr-x 4 root root    4096 Oct 16 03:24 ..
-rw-r--r-- 1 root root  269232 Oct 16 03:26 musdk_uio.ko
-rw-r--r-- 1 root root  227240 Oct 16 03:24 mv_dmax2_uio.ko
-rw-r--r-- 1 root root  228592 Oct 16 03:25 mv_neta_uio.ko
-rw-r--r-- 1 root root  226792 Oct 16 03:25 mv_pp_uio.ko
-rw-r--r-- 1 root root  232432 Oct 16 03:25 mv_sam_uio.ko
-rw-r--r-- 1 root root 4689232 Oct 16 03:31 mvpp2x_sysfs.ko

<DPDK (Extract Marvell patches only) download후 patch 파일 생성하기>
  => Marvell에서 작업한 dpdk source를 download 한 후, marvell에서 작업한 부분(patch)만을 추려내도록 한다. 이 내용은 VPP build시 사용된다.

# cd /root
# git clone https://github.com/MarvellEmbeddedProcessors/dpdk-marvell.git -b dpdk-17.05-armada-17.10 dpdk-marvell
# mkdir /root/dpdk-patches/
# cd dpdk-marvell/
# git format-patch 2225554..HEAD -o /root/dpdk-patches

<VPP build 하기>
  => Marvell에서 작업한 vpp code를 내려 받아 build한다.

# cd /root
# git clone https://github.com/MarvellEmbeddedProcessors/vpp-marvell.git -b vpp-devel vpp-marvell
# cd vpp-marvell/
# export DPDK_VERSION=17.05
# export AESNI=n
# export LIBMUSDK_PATH=/usr
# make install-dep
  => vpp build 및 install에 필요한 다양한 package를 설치한다. 어라, 근데 설치 중 아래와 같은 에러가 발생한다.
sudo: unable to resolve host localhost.localdomain
Hit:1 http://ports.ubuntu.com/ubuntu-ports xenial InRelease
Hit:2 http://ports.ubuntu.com/ubuntu-ports xenial-security InRelease
Hit:3 http://ports.ubuntu.com/ubuntu-ports xenial-updates InRelease
Reading package lists... Done                     
sudo: unable to resolve host localhost.localdomain
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Package python-virtualenv is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Package cscope is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Unable to locate package dh-systemd
E: Unable to locate package libconfuse-dev
E: Unable to locate package git-review
E: Package 'cscope' has no installation candidate
E: Unable to locate package lcov
E: Unable to locate package chrpath
E: Unable to locate package nasm
E: Package 'python-virtualenv' has no installation candidate
E: Unable to locate package python-pip
E: Unable to locate package check
Makefile:266: recipe for target 'install-dep' failed
make: *** [install-dep] Error 100
root@localhost:~/vpp-marvell# sudo
sudo: unable to resolve host localhost.localdomain

# apt-get install software-properties-common
# add-apt-repository universe
  => 이걸 실행 후, 다시 시도해 본다.

# make install-dep
# make bootstrap
# groupadd vpp
# cp /root/dpdk-patches/* dpdk/dpdk-17.05_patches/
  => 앞서 준비해둔 dpdk patch를 적용해 준다.
# make -j4 build-release

여기까지 조금은 복잡한 과정을 통해 vpp build가 완료되었다.

<VPP 구동하기>
그럼, 지금부터 본격적으로 vpp를 실행해 보도록 하자. 참고로, vpp를 구동하는 방법은 아래와 같이 두가지가 있다.

1. debian package로 만들어 설치(설치 즉시 구동됨)
2. make run-release or make run 등으로 실행
 
VPP는 꽤나 덩치가 큰 project이므로, VPP 구동에 필요한 관련 파일을 사전에 파악해 보는 것이 순서일 듯 싶다. 사실 외관상으로만 보면 vpp는 일반적인 user space program의 구성(daemon, 관련 library, config file, control program)과 크게 다를 바가 없다.
--------------------------------------------------------------------------------------------------
1) vpp 실행 파일(daemon)
     - build-root/install-vpp-native/vpp => /usr/bin

2) vpp library 및 plugins 파일 
     - build-root/install-vpp-native/vpp/lib/* => /usr/lib/aarch64-linux-gnu/
     - build-root/install-vpp-native/vpp/lib/vpp_plugins/* => /usr/lib/aarch64-linux-gnu/vpp_plugins

3) vpp config 파일
     - src/scripts/mrvl/mrvl_demo_startup.conf => /etc/vpp/startup.conf
     - 이 파일은 사용 전에 적절히 수정해 줄 필요가 있다.

4) vpp CLI 파일 
     build-root/build-vpp-native/vpp/bin/vppctl => /usr/bin

5) 기타 system 설정 파일 변경
    - /etc/sysctl.d/80-vpp.conf (hugepage, shared memory 크기 조정)
-------------------------------------------------------------------------------------------------

여기에서는 make run-release를 이용하여 vpp를 구동시켜 보도록 하자.

mkdir -p /etc/vpp/
cp src/scripts/mrvl/mrvl_demo_startup.conf /etc/vpp/startup.conf
📌 startup.conf 설정 내용과 관련해서는 다음 장에서 자세히 소개해 보도록 하겠다.

modprobe -a musdk_uio mv_dmax2_uio mv_pp_uio mv_sam_uio mvpp2x_sysfs
=> 앞서 build해 둔 kernel module(marvell driver)을 구동시킨다.

# echo 1000 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
  => hugepage 갯수를 조정한다.

# cd /root/vpp-marvell
# export STARTUP_CONF=/etc/vpp/startup.conf
# make run-release &
vlib_plugin_early_init:356: plugin path /usr/lib/vpp_plugins
load_one_plugin:184: Loaded plugin: acl_plugin.so (Access Control Lists)
load_one_plugin:184: Loaded plugin: dpdk_plugin.so (Data Plane Development Kit (DPDK))
load_one_plugin:184: Loaded plugin: flowprobe_plugin.so (Flow per Packet)
load_one_plugin:184: Loaded plugin: gtpu_plugin.so (GTPv1-U)
load_one_plugin:184: Loaded plugin: ila_plugin.so (Identifier-locator addressing for IPv6)
load_one_plugin:184: Loaded plugin: ioam_plugin.so (Inbound OAM)
load_one_plugin:83: Not a plugin: ixge_plugin.so
load_one_plugin:184: Loaded plugin: lb_plugin.so (Load Balancer)
load_one_plugin:184: Loaded plugin: libsixrd_plugin.so (IPv6 Rapid Deployment on IPv4 Infrastructure (RFC5969))
load_one_plugin:184: Loaded plugin: memif_plugin.so (Packet Memory Interface (experimetal))
load_one_plugin:184: Loaded plugin: nat_plugin.so (Network Address Translation)
load_one_plugin:184: Loaded plugin: pppoe_plugin.so (PPPoE)
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_export_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/gtpu_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/memif_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/flowprobe_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_pot_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_vxlan_gpe_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/nat_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/pppoe_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/vxlan_gpe_ioam_export_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/udp_ping_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_trace_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/dpdk_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/acl_test_plugin.so
/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/lb_test_plugin.so
/usr/bin/vpp[2491]: dpdk_config:1214: EAL init args: -c 1 -n 4 --huge-dir /run/vpp/hugepages --file-prefix vpp --master-l 
EAL: VFIO support initialized
EAL: cannot open /proc/self/numa_maps, consider that all memory is in socket_id 0
DPDK physical memory layout:
Segment 0: phys:0x89800000, len:268435456, virt:0x7eb2800000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0

📌 위의 명령 대신  /usr/bin/vpp -c /etc/vpp/startup.conf & 를 직접 실행해도 된다.

vpp가 구동되었으니, vppctl을 이용하여 CLI mode로 진입해 본다.

# ifconfig eth0 up
# ifconfig eth1 up
  => 먼저 (이후 설정을 대비하여) eth0, eth1 interface를 up 시키자.

root@localhost:~# telnet 127.0.0.1 5002
  => telnet을 통해 vpp 5002 port에 연결한다. 
    _______    _        _   _____  ___ 
 __/ __/ _ \  (_)__    | | / / _ \/ _ \
 _/ _// // / / / _ \   | |/ / ___/ ___/
 /_/ /____(_)_/\___/   |___/_/  /_/    

vpp#

이 상태에서 곧 바로, l2 bridge 설정을 해 보도록 한다.

<l2 bridge 설정>
vpp# set interface state TenGigabitEthernet0 up
vpp# set interface state TenGigabitEthernet1 up
vpp# create bridge-domain 1
vpp# set interface l2 bridge TenGigabitEthernet0 1
vpp# set interface l2 bridge TenGigabitEthernet1 1

📌 위의 설정 내용이 뭘 의미하는지에 대해서도 다음 장에서 자세히 설명하도록 한다.

l2 bridge 설정이 완료되었으니, 인터넷 연결 테스트를 해 보자. 

Windows 10 PC => LAN port[MACCHIATObin board]WAN port => Access Point => Internet

OK, 정상 동작한다.

L2 bridge가 정상 동작하는 것을 확인하였으니, 다음 차례는 L3 NAT gateway 설정을 해볼 차례이다.

<l3 NAT 설정>
vpp# set int state TenGigabitEthernet1 up
vpp# set dhcp client intfc TenGigabitEthernet1 hostname vppgate
vpp# loop create
vpp# set int l2 bridge loop0 1 bvi
vpp# set int ip address loop0 192.168.2.1/24
vpp# set int state loop0 up
vpp# set int l2 bridge TenGigabitEthernet0 1
vpp# set int state TenGigabitEthernet0 up
vpp# nat44 add interface address TenGigabitEthernet1
vpp# set interface nat44 in loop0 out TenGigabitEthernet1 

Windows 10 PC(192.168.2.100) => LAN port(192.168.2.1)[MACCHIATObin board]WAN port => Access Point => Internet

이 상태에서 인터넷 연결을 시도해 보자. 어라, 연결이 안된다. 

$ ping 192.168.2.1
  => 이것도 안된다. 왜 그럴까 ?

심지어 vppctl를 이용해 CLI 명령 설정 중 vpp daemon이 이유 없이 자주 죽는다. 또한 죽는 시점도 제각각이다. 뭔가 매우 불안정한 느낌이다. 아래 내용은 vpp를 debug mode로 build한 후, gdb로 죽는 상황을 잡아본 것이다.

# gdb /usr/bin/vpp
(gdb) run -c /etc/cpp/startup.conf

[그림 2.3] vpp를 gdb로 실행하기

(gdb) bt
[그림 2.4] gdb backtrace 실행 모습

vpp가 죽는 원인을 파악해 보아야 하는데, 아직은 쉽지가 않다(vpp에 익숙해지는데 좀더 시간이 필요한다). VPP project 자체의 안정성에 문제가 있는 것인지 확인이 필요하다(의심이 간다). 아무래도 좀 old한 방법이기는 하나, PC에 LAN card를 2개 꽂고 동일한 시험을 해 보아야 겠다. 


3. Intel PC(x86_64)에서 VPP 돌려 보기
MACCHIATObin 보드에 올렸던 VPP에 심각한 문제(L3 routing & NAT 기능 오동작 및 vpp가 죽는 문제)가 있으니, 이를 PC에서 돌려보면 어떨까 ? 집에 있는 PC에 아래와 같이 구형 Intel NIC(Intel® 82574L Gigabit Ethernet Controller) 2개를 장착하고, 그 위에서 VPP를 돌려 보도록 하자.


 
[그림 3.1] Intel CPU PC와 2 x Intel NIC(82574L)

📌 내가 이런 짓(?)을 다시하게 될 줄이야... 정말 옛날 생각이 난다. 😂

아래 내용은 Ubuntu 18.04 LTS(desktop version)를 기준으로 정리한 것이다. Ubuntu 20.04 LTS에서도 테스트해 보았는데, 몇가지 문제가 있었다.

a) VPP build 하기
MACCHAITObin board에서 build하는 것과는 달리 x86_64 환경에서의 build 절차는 아주 간단하다.

$ git clone https://gerrit.fd.io/r/vpp
$ cd vpp
$ make install-dep
$ make build-release


b) VPP 구동하기 1
이번에는 make run-release 대신 debian package를 만들어 설치해 보도록 하자.

$ make pkg-deb
$ cd build-root; ls -al *.deb

[그림 3.2] vpp debian package

$ sudo dpkg -i *.deb
Selecting previously unselected package libvppinfra-dev.
(데이터베이스 읽는중 ...현재 198109개의 파일과 디렉터리가 설치되어 있습니다.)
Preparing to unpack libvppinfra-dev_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking libvppinfra-dev (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package libvppinfra.
Preparing to unpack libvppinfra_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking libvppinfra (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package python3-vpp-api.
Preparing to unpack python3-vpp-api_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking python3-vpp-api (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package vpp-api-python.
Preparing to unpack vpp-api-python_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking vpp-api-python (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package vpp-dbg.
Preparing to unpack vpp-dbg_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking vpp-dbg (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package vpp-dev.
Preparing to unpack vpp-dev_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking vpp-dev (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package vpp-plugin-core.
Preparing to unpack vpp-plugin-core_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking vpp-plugin-core (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package vpp-plugin-dpdk.
Preparing to unpack vpp-plugin-dpdk_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking vpp-plugin-dpdk (21.01-rc0~275-g784bbcce0) ...
Selecting previously unselected package vpp.
Preparing to unpack vpp_21.01-rc0~275-g784bbcce0_amd64.deb ...
Unpacking vpp (21.01-rc0~275-g784bbcce0) ...
libvppinfra-dev (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
libvppinfra (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
dpkg: dependency problems prevent configuration of python3-vpp-api:
 python3-vpp-api 패키지는 다음 패키지에 의존: python3-cffi: 하지만:
  python3-cffi 패키지는 설치하지 않았습니다.
 python3-vpp-api 패키지는 다음 패키지에 의존: python3-pycparser: 하지만:
  python3-pycparser 패키지는 설치하지 않았습니다.

dpkg: error processing package python3-vpp-api (--install):
 의존성 문제 - 설정하지 않고 남겨둠
dpkg: dependency problems prevent configuration of vpp-api-python:
 vpp-api-python 패키지는 다음 패키지에 의존: python-cffi: 하지만:
  python-cffi 패키지는 설치하지 않았습니다.

dpkg: error processing package vpp-api-python (--install):
 의존성 문제 - 설정하지 않고 남겨둠
vpp-dbg (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
vpp-dev (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
vpp (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
* Applying /etc/sysctl.d/10-console-messages.conf ...
kernel.printk = 4 4 1 7
* Applying /etc/sysctl.d/10-ipv6-privacy.conf ...
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
* Applying /etc/sysctl.d/10-kernel-hardening.conf ...
kernel.kptr_restrict = 1
* Applying /etc/sysctl.d/10-link-restrictions.conf ...
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
* Applying /etc/sysctl.d/10-magic-sysrq.conf ...
kernel.sysrq = 176
* Applying /etc/sysctl.d/10-network-security.conf ...
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_syncookies = 1
* Applying /etc/sysctl.d/10-ptrace.conf ...
kernel.yama.ptrace_scope = 1
* Applying /etc/sysctl.d/10-zeropage.conf ...
vm.mmap_min_addr = 65536
* Applying /usr/lib/sysctl.d/50-default.conf ...
net.ipv4.conf.all.promote_secondaries = 1
net.core.default_qdisc = fq_codel
* Applying /etc/sysctl.d/80-vpp.conf ...
vm.nr_hugepages = 1024
vm.max_map_count = 3096
vm.hugetlb_shm_group = 0
kernel.shmmax = 2147483648
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.conf ...
Created symlink /etc/systemd/system/multi-user.target.wants/vpp.service → /lib/systemd/system/vpp.service.
vpp-plugin-core (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
vpp-plugin-dpdk (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
Processing triggers for libc-bin (2.27-3ubuntu1.2) ...
처리하는데 오류가 발생했습니다:
 python3-vpp-api
 vpp-api-python

어라, 2개의 package python3-vpp-api, vpp-api-python(단, 꼭 필요한 package는 아닌 듯 보임)를 설치하는 과정에서 문제가 발생한다. 일단 아래와 같이 해서 이 문제를 해결하고 넘어가도록 하자.

chyi@mars:~/workspace/VPP/vpp$ sudo apt --fix-broken install
패키지 목록을 읽는 중입니다... 완료
의존성 트리를 만드는 중입니다       
상태 정보를 읽는 중입니다... 완료
의존성을 바로잡는 중입니다... 완료
다음의 추가 패키지가 설치될 것입니다 :
  python-cffi python-ply python-pycparser python3-cffi python3-pycparser
제안하는 패키지:
  python-ply-doc
다음 새 패키지를 설치할 것입니다:
  python-cffi python-ply python-pycparser python3-cffi python3-pycparser
0개 업그레이드, 5개 새로 설치, 0개 제거 및 7개 업그레이드 안 함.
2개를 완전히 설치하지 못했거나 지움.
317 k바이트 아카이브를 받아야 합니다.
이 작업 후 2,041 k바이트의 디스크 공간을 더 사용하게 됩니다.
계속 하시겠습니까? [Y/n] y
받기:1 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 python3-pycparser all 2.18-2 [67.7 kB]
받기:2 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 python3-cffi all 1.11.5-1 [67.4 kB]
받기:3 http://kr.archive.ubuntu.com/ubuntu bionic/main amd64 python-ply all 3.11-1 [46.6 kB]
받기:4 http://kr.archive.ubuntu.com/ubuntu bionic/main amd64 python-pycparser all 2.18-2 [67.6 kB]
받기:5 http://kr.archive.ubuntu.com/ubuntu bionic/main amd64 python-cffi all 1.11.5-1 [67.3 kB]
내려받기 317 k바이트, 소요시간 6초 (53.3 k바이트/초)
Selecting previously unselected package python3-pycparser.
(데이터베이스 읽는중 ...현재 199978개의 파일과 디렉터리가 설치되어 있습니다.)
Preparing to unpack .../python3-pycparser_2.18-2_all.deb ...
Unpacking python3-pycparser (2.18-2) ...
Selecting previously unselected package python3-cffi.
Preparing to unpack .../python3-cffi_1.11.5-1_all.deb ...
Unpacking python3-cffi (1.11.5-1) ...
Selecting previously unselected package python-ply.
Preparing to unpack .../python-ply_3.11-1_all.deb ...
Unpacking python-ply (3.11-1) ...
Selecting previously unselected package python-pycparser.
Preparing to unpack .../python-pycparser_2.18-2_all.deb ...
Unpacking python-pycparser (2.18-2) ...
Selecting previously unselected package python-cffi.
Preparing to unpack .../python-cffi_1.11.5-1_all.deb ...
Unpacking python-cffi (1.11.5-1) ...
python-ply (3.11-1) 설정하는 중입니다 ...
python3-pycparser (2.18-2) 설정하는 중입니다 ...
python3-cffi (1.11.5-1) 설정하는 중입니다 ...
python-pycparser (2.18-2) 설정하는 중입니다 ...
python3-vpp-api (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
python-cffi (1.11.5-1) 설정하는 중입니다 ...
vpp-api-python (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...

$ ps aux|grep vpp
  => (앞서 약간의 문제가 있긴 했지만)package 설치 후, vpp가 정상 구동되는 것을 알 수 있다.

[그림 3.3] 구동 중인 vpp daemon 확인

-----------------------[참고: make run-release 로 vpp 구동시키기] ------------------
$ sudo bash
# mkdir -p /etc/vpp/
cp src/scripts/mrvl/mrvl_demo_startup.conf /etc/vpp/startup.conf
# export STARTUP_CONF=/etc/vpp/startup.conf
# make run-release &
--------------------------------------------------------------------------------------

vpp 구동에 사용된 config 파일(/etc/vpp/startup.conf)을 열어 보면 다음과 같다.

# vi /etc/vpp/startup.conf

[그림 3.4] /etc/vpp/startup.conf 파일

📌 startup.conf의 세부 필드의 의미에 대해서는 아래 site의 내용을 참조하기 바란다.

<주의 사항>
VPP 설치 관련 guide 문서를 보면, 아래와 같이 /etc/sysctl.d/80-vpp.conf 파일의 설정(hugepages 갯수, shared memory 최대 크기)을 조정하도록 권고하고 있다. 이는 vpp의 performance를 끌어올리기 위한 조치(vector packet processing 시 활용)인데, desktop 환경에서는 특별히 주의해서 설정해 주어야 한다.

[그림 3.5] /etc/ sysctl.d/80-vpp.conf 파일

root@mars:/etc/sysctl.d# sysctl -p /etc/sysctl.d/80-vpp.conf
vm.nr_hugepages = 4096
vm.max_map_count = 9216
vm.hugetlb_shm_group = 0
kernel.shmmax = 8589934592

즉, 이 설정을 Ubuntu 18.04 LTS(desktop), RAM 8GB 정도의 환경에서 적용하게 되면, 시스템 재 부팅시 Login 화면이 출력 안되고, 결국에는 시스템이 멈춰 버릴 수 있으니 주의하기 바란다.
______________________________________________

드디어 vpp가 구동되었으니, vppctl로 접속해 보자.

# vppctl

[그림 3.6] vppctl로 접속한 모습

📌 앞선 장에서와는 달리 이번에는 telnet을 이용하지 않고 vppctl 명령을 곧 바로 사용하였다. 이는 startup.conf 파일에서 아래와 같이 설정(tcp port 5002가 아니라 domain socket으로 연결)해 주었기 때문이다.
---------------------------------------------
unix {
  nodaemon
  log /var/log/vpp/vpp.log
  full-coredump
  cli-listen /run/vpp/cli.sock  
  gid vpp

  ## run vpp in the interactive mode
  # interactive

  ## do not use colors in terminal output
  # nocolor

  ## do not display banner
  # nobanner
}
---------------------------------------------

근데, 한가지 문제가 있다. show interface 명령을 실행해 보았는데, 생각과는 달리 2개의 ethernet port가 보이질 않는다.

# vppctl
vpp# show int

[그림 3.7] interface 확인 모습

c) VPP 구동하기 2 - dpdk 설치 및 binding
지금까지의 과정으로 vpp가 간단히 구동되면 좋겠으나, 실제로는 한단계 과정이 더 남아 있다. 즉, dpdk driver를 설치하고, network adapter를 dpdk와 binding 시켜주어야만 vpp가 제대로 동작하게 된다.

$ sudo apt install dpdk
📌 물론, 아래 방법으로 dpdk source를 내려 받아 build 후 설치하는 방법도 있다.
git clone https://github.com/DPDK/dpdk

----------------------------- [dpdk source build 하기] ------------------------------
$ sudo apt install python3-pip
$ pip3 install meson ninja
$ sudo apt install meson
$ source ~/.profile

$ git clone https://github.com/DPDK/dpdk
$ cd dpdk
$ meson build
$ cd build
$ ninja
$ sudo ninja install
$ sudo ldconfig
________________________________________________________________________

$ sudo bash
# sudo dpdk-devbind -s
  => dpdk-devbind 명령으로 ethernet adapter가 DPDK에 bind되어 있는지를 확인해 본다. 당연히 처음에는 아무것도 dpdk에 binding되어 있지 않을 것이다.

[그림 3.8] dpdk binding 상태 확인 모습

Network devices using DPDK-compatible driver
============================================
<none>

Network devices using kernel driver
===================================
0000:01:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller 8168' if=enp1s0 drv=r8169 unused=vfio-pci,uio_pci_generic 
0000:02:00.0 '82574L Gigabit Network Connection 10d3' if=enp2s0 drv=e1000e unused=vfio-pci,uio_pci_generic 
0000:03:00.0 '82574L Gigabit Network Connection 10d3' if=enp3s0 drv=e1000e unused=vfio-pci,uio_pci_generic 
...

sudo dpdk-devbind --bind uio_pci_generic 02:00.0
# sudo dpdk-devbind --bind uio_pci_generic 03:00.0
  => 2개의 PCI ethernet controller를 dpdk에 bind시킨다.

[그림 3.9] 2개의 Intel NIC이 dpdk에 binding된 모습

📌 unbind하려면 아래와 같이 해주면 된다.
# sudo dpdk-devbind --unbind 0000:02:00.0
# sudo dpdk-devbind --unbind 0000:03:00.0

# service vpp restart
dpdk binding이 변경되었으니, vpp를 재구동 시킨다.

# vppctl
vpp# show int

[그림 3.10] 2개의 gigabit interface 출력 모습

자, 이제 정말로 vpp를 사용할 수 있는 기본 준비가 모두 완료되었다. 이제 부터 l2 bridge, L3 gateway 설정을 차례로 진행해 보도록 하자.

<참고: Network port 설정>
GigabitEthernet2/0/0 : WAN
GigabitEthernet3/0/0 : LAN

[그림 3.11] L2 bridge 네트워크 구성도

d) L2 bridge 설정하기
vpp# set interface state GigabitEthernet3/0/0 up
vpp# set interface state GigabitEthernet2/0/0 up
 => WAN, LAN interface를 up 시킨다.
vpp# create bridge-domain 1
 => l2 bridge domain(1번 domain)을 하나 생성한다.
vpp# set interface l2 bridge GigabitEthernet3/0/0 1
vpp# set interface l2 bridge GigabitEthernet2/0/0 1
 => l2 bridge domain 1에 WAN, LAN interface를 포함시킨다.

[그림 3.12] L2 bridge 설정 모습

이 정도만 하면 아주 기본적인 L2 bridge가 하나 만들어지게 된다. 이 상태에서 인터넷 연결을 시도해 보도록 하자.

Windows 10 PC => LAN port [Intel PC Gateway] WAN port => Access Point => Internet

예상대로 정상 동작한다. 이 상태에서 CPU 사용량을 체크해 보도록 하자.

[그림 3.13] Intel PC의 CPU 사용량

📌 허걱, CPU 사용률이 100%에 육박한다. 하지만 이건 정상이다. dpdk는 cpu core 중 하나를 packet capture(polling) 용으로만 사용한다. 즉, cpu를 놀리지 않고 열심히 packet capture만 하도록 하여 성능을 향상 시키겠다는 뜻이다. 물론, 이게 맘에 안든다면 startup.conf의 설정을 조정하여 cpu 사용률을 10 ~ 20% 수준으로 떨어뜨릴 수도 있다. 하지만 이렇게 되면 100%의 성능을 내기는 어렵게 된다.

e) L3 NAT 설정하기
# service vpp restart
  => l2 bridge 설정을 날려야 하니, vpp를 재 시작하도록 한다.

# vppctl
vpp# set int state GigabitEthernet2/0/0 up
 => WAN interface를 up시킨다.
vpp# set dhcp client intfc GigabitEthernet2/0/0 hostname vppsg
 => dhcp client를 사용하여 상위 gateway(예: 무선 Access Point)로 부터 ip & dns 정보 등을 할당 받는다.

vpp# loop create
vpp# set int l2 bridge loop0 1 bvi
 => l2 bridge를 하나 생성한다.
vpp# set int ip address loop0 192.168.3.1/24
vpp# set int state loop0 up 
  => l2 bridge에 대표 ip 192.168.3.1/24를 할당하고, interface를 up 시킨다.
vpp# set int l2 bridge GigabitEthernet3/0/0 1
vpp# set interface state GigabitEthernet3/0/0 up
  => LAN interface를 l2 bridge에 포함시키고, interface를 up시킨다.

vpp# nat44 add interface address GigabitEthernet2/0/0
  => NAT44 interface로 WAN port를 등록한다.
vpp# set interface nat44 in loop0 out GigabitEthernet2/0/0
  => l2 bridge(loop0 interface)를 input으로 하고, WAN port를 output으로 하는 NAT44 rule을 추가한다.

vpp# show int addr
  => 지금까지 설정한 내용을 확인해 보면 다음과 같다. WAN port의 경우 DHCP 서버로 부터 ip(192.168.7.207/24)를 정상적으로 받아오고 있음을 알 수 있다.
GigabitEthernet2/0/0 (up):
  L3 192.168.7.207/24
GigabitEthernet3/0/0 (up):
  L2 bridge bd-id 1 idx 1 shg 0  
local0 (dn):
loop0 (up):
  L2 bridge bd-id 1 idx 1 shg 0 bvi
  L3 192.168.3.1/24

[그림 3.14] L3 NAT 설정

기본적인 L3 gateway 설정을 끝냈으니, 역시 이 상태에서 인터넷 연결을 시도해 보도록 하자.

Windows 10 PC(192.168.3.10/24) => LAN port(192.168.3.1/24) [Intel PC Gateway]WAN port => Access Point => Internet

예상대로 정상 동작한다. 2장에서와는 달리 매우 안정적인 느낌이다. 여러가지 설정을 해 보았는데, vpp는 한차례도 죽지를 않았다. 장시간 켜 놓아도 마찬가지다. 이만하면 vpp 꽤나 쓸만한 녀석이라는 생각이 든다. 😃


4. VPP Wireguard Plugin 시험하기
FD.io VPP에는 아주 다양한 기능이 있다. 그 중에서도 (현재 개발 중인 상태이기는 하지만) Wireguard가 눈에 띈다. 제대로 동작할지 어떨지 직접 시험해 보기로 하자.

[그림 4.1] VPP Wireguard 시험 환경

Windows 10 PC => VPP Gateway(WireGuard Plugin) => Access Point => [Internet] <= LTE Egg <= Ubuntu 18.04(WireGuard)

VPP Gateway: 10.1.1.100
Ubuntu 18.04: 10.1.1.200

<VPP Gateway>

[그림 4.2] VPP wireguard 명령 사용법

vpp# wireguard create listen-port 51920 src 10.1.1.100
wg0
  => 재밌게도 wg0 interface가 자동으로 생성된다. wireguard create 명령을 다시 시도하면 wg1이 생성되게 된다.

vpp# show wireguard interface 
[0] wg0 src:10.1.1.100 port:51920 private-key:GAAAADAAAADw7RGUM38AABDtEZQzfwAAk9Gh7jN/AAA= 1800000030000000f0ed1194337f000010ed1194337f000093d1a1ee337f0000 public-key:OlmkEvwpaY40jKiHM7Ntyvn5tf1SvqOC/6A308JEIlc= 3a59a412fc29698e348ca88733b36dcaf9f9b5fd52bea382ffa037d3c2442257 mac-key: da4c390d28bc5307b6ad42d89b8ea57923819d44e4956b9aa3eb85454e1f7f8f
  => index 0번인 wireguard interface의 속성 정보(private, public key)가 출력된다.

vpp# set int state wg0 up
vpp# set int ip address wg0 10.1.1.100/24
  => wg0 interface에 ip 주소를 부여하고 up 시킨다.

vpp# wireguard peer add wg0 public-key oGqQEGdTho5jwoqt3aIiYYXfehQTy83FNYKHC6HBUUs= endpoint 0.0.0.0 port 0 allowed-ip 10.1.1.0/24 persistent-keepalive 25
  => peer 정보를 추가한다.
📌 wireguard peer add 명령 사용법에 bug가 있다. 즉 dst-port [port_dst] 대신 port [port_dst]를 사용해야 한다.

vpp# show wireguard peer 
[0] endpoint:[10.1.1.100:51920->0.0.0.0:0] wg0 keep-alive:25 adj:5
  key:oGqQEGdTho5jwoqt3aIiYYXfehQTy83FNYKHC6HBUUs= a06a90106753868e63c28aaddda2226185df7a1413cbcdc53582870ba1c1514b
  allowed-ips: 10.1.1.0/24
  => peer의 정보를 출력한다.

vpp# ping 10.1.1.200
  => 아래 Ubuntu 18.4에서의 wireguard 설정 후, ping을 시도해 본다.
Statistics: 5 sent, 0 received, 100% packet loss

<Ubuntu 18.04 - WireGuard>
$ wg genkey | tee privatekey | wg pubkey > publickey
$ sudo ip link add dev wg0 type wireguard
$ sudo ip address add dev wg0 10.1.1.200/24
$ sudo ip link set up dev wg0

$ sudo wg set wg0 listen-port 59760 private-key ./privatekey peer OlmkEvwpaY40jKiHM7Ntyvn5tf1SvqOC/6A308JEIlc= allowed-ips 10.1.1.0/24 endpoint X.X.X.X:51920 persistent-keepalive 25

$ ping 10.1.1.100
  => 역시 안된다. 왜 안될까 ? 아직 "Development" 상태라서 그런것 같긴 한데 ... 그래도 이상하다. 안되는 걸 올려 두었을 것 같지는 않은데 .. 😈

네트워크 환경을 Local 망으로 바꾸어 동일한 시험을 해 보았으나, 역시나 동작하지 않았다. 아무래도 VPP에 포함되어 있는 Wireguard plugin code를 분석해 보아야 겠다.

<2024년 들어 3년만에 다시 시도>

아래와 같이 vpp 설정을 다시 진행해 보았더니, 이번엔 정상 동작한다. 😎😎😎 신규 testbed 구성은 다음과 같다. 편의상 반대쪽(wireguard kernel) 설정은 생략하였다.

VPP(LAN: 192.168.10.1/24, WAN: 192.168.3.33/24, vpn ip: 172.16.1.99

<=>

wireguard kernel(LAN: 192.168.5.1/24, WAN: 192.168.3.101/24, vpn ip: 172.16.1.254)
                                                                   
-----------------------

vpp# set interface state TenGigabitEthernet3b/0/0 up    #vpp 장비 LAN port up
vpp# set interface state TenGigabitEthernet3b/0/2 up    #vpp 장비 WAN port up

vpp# set int ip address TenGigabitEthernet3b/0/0 192.168.10.1/24   #vpp LAN ip 설정
vpp# set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24   #vpp WAN ip 설정 

vpp# wireguard create listen-port 59760 src 192.168.3.33       #wireguard interface 생성(keypair 생성 포함)
wg0
vpp# show wireguard interface 
[0] wg0 src:192.168.3.33 port:59760 private-key:EAAAADAAAAAg72qwxn8AAAoAAAAAAAAAwPzoB8d/AAA= 100000003000000020ef6ab0c67f00000a00000000000000c0fce807c77f0000 public-key:Fp57l81Z2RCToioDipRIN54/a+bVeD4Lpc1CDdDyJBo= 169e7b97cd59d91093a22a038a9448379e3f6be6d5783e0ba5cd420dd0f2241a mac-key: 72d149c21d7b81ba57fb201daded7c62775c107a4192a4fc49d1c131ed87bece

vpp# set interface state wg0 up                          #wg0 interface up
vpp# set int ip address wg0 172.16.1.99/24     #wg0 interface ip 설정
vpp# show int addr
TenGigabitEthernet3b/0/0 (up):
TenGigabitEthernet3b/0/1 (dn):
TenGigabitEthernet3b/0/2 (up):
  L3 192.168.3.33/24
TenGigabitEthernet3b/0/3 (dn):
local0 (dn):
wg0 (up):
  L3 172.16.1.99/24

vpp# wireguard peer add wg0 public-key EgJxYfRtnM1iYO4W223wstMy/45iMCRGf/b4qSryzT0= endpoint 192.168.3.101 allowed-ip 0.0.0.0/0 allowed-ip 172.16.1.254/32 dst-port 59760 persistent-keepalive 25    #wireguard peer 설정

vpp# set interface mtu packet 1420 wg0                   #wireguard mtu 설정 
 
vpp# ip route add 0.0.0.0/0 via 172.16.1.99 wg0      #wg0를 이용하는 routing entry 설정

vpp# ping 8.8.8.8    
참고) vpp에서 kernel wireguard 장비를 통해 internet(8.8.8.8)으로 ping 시도
116 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=36.5289 ms
116 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=36.1525 ms

$ sudo tcpdump -i eth2 port 59760     #kernel wireguard 장비에서 wireguard packet capture
19:19:27.564590 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128
19:19:27.600483 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128
19:19:28.564570 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128
19:19:28.600506 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128
...

vpp# ip route del 0.0.0.0/0 via 172.16.1.99 wg0 
vpp# ip route add 192.168.5.0/24 via 172.16.1.99 wg0 

vpp# ping 192.168.5.1
참고) vpp에서 kernel wireguard 장비 LAN ip로 ping 시도
116 bytes from 192.168.5.1: icmp_seq=1 ttl=64 time=.3942 ms
116 bytes from 192.168.5.1: icmp_seq=2 ttl=64 time=.3891 ms

sudo tcpdump -i eth2 port 59760     #kernel wireguard 장비에서 wireguard packet capture
19:21:27.238980 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128
19:21:28.238698 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128
19:21:28.238996 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128
19:21:29.238651 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128
19:21:29.238940 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128
19:21:30.238610 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128
19:21:30.238815 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128

정상적으로 tunneling이 되고 있음을 알 수 있다. 😍

<wireguard kernel 장비의 wireguard wg0 설정 상태>
$ sudo wg show wg0
interface: wg0
  public key: EgJxYfRtnM1iYO4W223wstMy/45iMCRGf/b4qSryzT0=
  private key: (hidden)
  listening port: 59760

peer: 5lHQb8X5i7pzAevP192fbZBBgEqwaCTZboACsdAbE2s=
  endpoint: 192.168.3.33:59760
  allowed ips: 172.16.1.99/32, 192.168.10.0/24
  latest handshake: 31 seconds ago
  transfer: 98.46 KiB received, 321.60 KiB sent
  persistent keepalive: every 10 seconds

주의) 근데, 뭐가 잘 못 되었을까 ? 정작 vpn ip 간에는 ping이 안된다. 즉, ping 172.16.1.254(from 172.16.1.99) 혹은 ping 172.16.1.99(from 172.16.1.254)이 안된다.


5.  VPP 관련 그 밖의 관심있는 주제
VPP는 아래 site에서 볼 수 있듯이 많은 feature를 가지고 있다.


그 중에서 특별히 좀더 테스트해보고 싶은 내용을 열거해 보면 다음과 같다. 앞으로 시간을 두고 하나씩 확인해 보아야 겠다. 😜
  • L2 bridge (full 기능)
  • VxLAN
  • QoS
  • ACL
  • NAT44, NAT46, DS-LITE...
  • Load Balancer
  • IPSec
  • MPLS 등..

To be continued...



6. References
[1] https://fd.io/vppproject/vpptech/
[2] Cisco Ultra Packet Core - High Performance and Features, Aeneas Dodd and Daniel Walton
[3] intel DPDK - Data Plane Development Kit, One Convergence Devices Ptv. LTD, Saif
[4] DPDK Summit - DPDK Architecture And Roadmap Discussion, Kannan Babu Ramia & Deepak Kumar Jain, Intel
[5] https://www.metaswitch.com/blog/fd.io-takes-over-vpp
[6] https://mitxpc.com/products/as-5019d-ftn4
[7] https://github.com/MarvellEmbeddedProcessors/vpp-marvell
[8] https://blog.apnic.net/2020/04/17/kernel-bypass-networking-with-fd-io-and-vpp/
[9] https://software.intel.com/content/www/us/en/develop/articles/build-a-fast-network-stack-with-vpp-on-an-intel-architecture-server.html
[10] https://vpp.flirble.org/master/d4/dc4/md_src_plugins_wireguard__r_e_a_d_m_e.html
[11] https://ettrends.etri.re.kr/ettrends/152/0905002032/
[12] https://media.frnog.org/FRnOG_28/FRnOG_28-3.pdf


Slowboot

댓글 없음:

댓글 쓰기