2020년 9월 20일 일요일

ESPRESSObin Ultra 보드와 MACCHIATObin 보드의 Switch & Ethernet Device Driver 분석(2)

이번 시간에는 지난 시간에 이어, Marvell chip을 사용하는 보드 중 두번째인 MACCHIATObin 보드에 관한 이야기(network 중심)를 해 보고자 한다.


 


목차
1. Docker 환경 설정
2. ESPRESSObin Ultra 보드 소개
3. ESPRESSObin Ultra 보드의 Switching Device Driver 분석
4. MACCHIATObin 보드 소개
5. MACCHIATObin 보드의 Ethernet Device Driver 분석
6. 응용편: MACCHIATObin 보드를 SoftEther VPN Gateway로 만들기
7. References



4. MACCHIATObin 보드 소개
MACCHIATObin은 Marvell ARMADA 8040(88F8040, Quad core Cortex-A72, 2GHz) processor(ARMv8 고성능 CPU + PPv2라는 network processor로 구성)를 사용하고, 10Gb Ethernet(Copper or SFP) 2개/2.5Gb Ethernet(SFP) 1개, 1Gb Ethernet(Copper)를 장착한 (고성능 network 장비로 사용 가능한) community board이다. 2년 전 쯤에 한 대를 구매해 두었었는데, 이제와서 꺼내 보게 되었다 😓



📌 MACCIATObin은 network interface가 가히 환상적이라고 말할 수 있다.

4.1) MACCHIATObin 보드 개요
MACCHIATObin은 아래 그림과 같이 Single Shot과 Double Shot 두가지 모델이 있는데, 이 중 보다 스펙이 좋은 Double Shot을 가지고 내용 전개를 하도록 하겠다.


[그림 4.1] MACCHIATOBin 보드(1) 

[그림 4.2] MACCHIATOBin 보드(2) - 스펙

[그림 4.3] MACCHIATOBin 보드(2) - Double Shot h/w 블록도

4.2) Docker 환경에서 MACCHIATObin 코드 build하기
지금부터는 MACCHIATObin code를 build하기 위해 docker 상에 Ubuntu 16.04를 설치하고, 다시 그 위에 OpenWrt 17.10 설치해 보도록 하겠다.


vi Dockerfile_ubuntu1604

[그림 4.4] Ubuntu 16.04 설치용 Dockerfile

docker build -f Dockerfile_ubuntu1604 -t u1604 .
  => docker image를 만들어 보자.

[그림 4.5] Ubuntu 16.04 설치용 docker image 생성 모습(1)

[그림 4.6] Ubuntu 16.04 설치용 docker image 생성 모습(2)

docker run -i -t --name mcbin1604 u1604 /bin/bash
root@9c114a442454:/# uname -a
Linux 9c114a442454 5.4.0-45-generic #49~18.04.2-Ubuntu SMP Wed Aug 26 16:29:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
root@9c114a442454:/# cat /etc/issue
Ubuntu 16.04.7 LTS \n \l

root@9c114a442454:/# su - chyi
chyi@9c114a442454:~/$ mkdir workspace; cd workspace
📌 1 ~ 2장에서 설명한 내용과 동일한 내용은 반복해서 언급하지 않도록 하겠다.

chyi@9c114a442454:~/workspace$ git clone https://github.com/MarvellEmbeddedProcessors/openwrt-kernel.git -b openwrt_17.10_release
  => kernel source를 먼저 내려 받도록 한다. openwrt build 시 이 kernel 코드를 활용하기 위해서 이다.

chyi@9c114a442454:~/workspace$ git clone https://github.com/MarvellEmbeddedProcessors/openwrt-dd.git -b openwrt_17.10_release
  => openwrt 17.10 version을 내려 받는다.

chyi@9c114a442454:~/workspace$ cd openwrt-dd/
chyi@9c114a442454:~/workspace/openwrt-dd$ ls -la
total 104
drwxrwxr-x 11 chyi chyi  4096 Sep  9 11:35 .
drwxrwxr-x  3 chyi chyi  4096 Sep  9 11:34 ..
drwxrwxr-x  8 chyi chyi  4096 Sep  9 11:35 .git
-rw-rw-r--  1 chyi chyi     8 Sep  9 11:35 .gitattributes
-rw-rw-r--  1 chyi chyi   224 Sep  9 11:35 .gitignore
-rw-rw-r--  1 chyi chyi   179 Sep  9 11:35 BSDmakefile
-rw-rw-r--  1 chyi chyi   576 Sep  9 11:35 Config.in
-rw-rw-r--  1 chyi chyi 17992 Sep  9 11:35 LICENSE
-rw-rw-r--  1 chyi chyi  2670 Sep  9 11:35 Makefile
-rw-rw-r--  1 chyi chyi  1272 Sep  9 11:35 README
drwxrwxr-x  2 chyi chyi  4096 Sep  9 11:35 config
drwxrwxr-x  2 chyi chyi  4096 Sep  9 11:35 docs
-rw-rw-r--  1 chyi chyi   457 Sep  9 11:35 feeds.conf.default
drwxrwxr-x  3 chyi chyi  4096 Sep  9 11:35 include
drwxrwxr-x 11 chyi chyi  4096 Sep  9 11:35 package
-rw-rw-r--  1 chyi chyi 12237 Sep  9 11:35 rules.mk
drwxrwxr-x  4 chyi chyi  4096 Sep  9 11:35 scripts
drwxrwxr-x  6 chyi chyi  4096 Sep  9 11:35 target
drwxrwxr-x 12 chyi chyi  4096 Sep  9 11:35 toolchain
drwxrwxr-x 58 chyi chyi  4096 Sep  9 11:35 tools

chyi@9c114a442454:~/workspace/openwrt-dd$ ./scripts/feeds update -a
chyi@9c114a442454:~/workspace/openwrt-dd$ ./scripts/feeds install -a
chyi@9c114a442454:~/workspace/openwrt-dd$ make menuconfig
  => 아래 내용을 참조하여 적절히 config를 조정하도록 한다.


[그림 4.7] openwrt menuconfig 모습

chyi@88e6a5c10d5f:~/workspace/openwrt-dd$ make -j4
  => build를 시작한다.

[그림 4.8] openwrt build 결과물

chyi@88e6a5c10d5f:~/workspace/openwrt-dd$ exit
root@9c114a442454:/# exit

docker commit -a "chunghan <chunghan.yi@gmail.com>" -m "add openwrt codes" mcbin1604 u1604
  => 지금까지 작업한 내용을 commit 하자.


4.3) Target board에서 돌려 보기 
이 절에서는 아래 site의 내용을 참조하여 MACCHIATObin 보드를 부팅해 보도록 하겠다.


부팅 가능한 microSD를 만드는 방법은 생략하였다. 관련해서는 위의 site 내용을 참조하기 바란다.

<Target board>
Marvell>> setenv image_name boot/openwrt-armada-a8k-MACHIATOBin-Image
Marvell>> setenv fdt_name boot/armada-8040-mcbin.dtb

Marvell>> setenv bootmmc 'mmc dev 1; ext4load mmc 1:1 $kernel_addr $image_name;ext4load mmc 1:1 $fdt_addr $fdt_name;setenv bootargs $console root=/dev/mmcblk1p1 rw rootwait; booti $kernel_addr - $fdt_addr'

Marvell>> saveenv
Marvell>> reset

[그림 4.9] MACCHIATObin 보드 부팅 모습(1) - minicom 115200 8N1

[그림 4.10] MACCHIATObin 보드 부팅 모습(2)

아래 그림은 MACCHIATObin의 port가 u-boot 및 linux에서 인식되는 내용을 보여준다.

[그림 4.11] MACCHIATObin 보드 Ethernet Port 구성
(egiga0 => eth0, egiga1 => eth1, egiga2 => eth2)

[그림 4.12] /etc/config/network 설정 내용 - LAN(bridge): eth0, eth1, eth3, WAN: eth2


[그림 4.13] 동작 중인 MACCHIATObin 보드(LAN: 검정색 선, WAN: 파란색 선)

📌 팬이 하나 달려 있어, 오래 틀어 놓으니 좀 시끄럽다.
📌 10G Ethernet을 위해서는 Cat6A 이상의 UTP cable을 사용해야 한다.

[그림 4.14] 동작 중인 MACCHIATObin 보드 - routing table

OK, 이 상태에서 인터넷을 연결해 보니, 정상 동작한다.

[그림 4.15] 동작 중인 MACCHIATObin 보드 - ps 명령 실행 모습

이상으로 MACCHIATObin 보드에 OpenWrt 17.10을 올리고, 간단히 network 동작 테스트를 진행해 보았다. 


5. MACCHIATObin 보드의 Ethernet Device Driver 분석
이 장의 내용은 [참고문헌 4]에서 영감을 받아 작성하였다.




[그림 5.1] Ethernet Link Layer 개념도 [출처: 참고문헌 4]


5.1) MACCHIATObin의 네트워크 인터페이스 
아래 그림은 MACCHIATObin 보드의 Ethernet 구성 요소를 전체적으로 보여주고 있다.

[그림 5.2] MACCHIATObin 보드 MAC/PHY 구성도 [출처: 참고문헌 4]

📌 SFP는 small form-factor pluggable transceiver를 뜻한다. SFP는 주로 광 케이블을 연결할 때 많이 사용되지만, copper cable을 연결하는 용도로도 사용될 수 있다.

먼저 eth2(그림 4.11 기준 가장 왼쪽, 위의 그림 5.2 기준 가장 아래쪽) 1G interface는 아래와 같이 가장 일반적인 MAC(PPv2.2)과 PHY(88E1512) 연결 형태로 구성되어 있다.

[그림 5.3] MACCHIATObin 보드 eth2 1G Interface [출처: 참고문헌 4]

다음으로 eth0, eth1 10G interface(그림 4.11 기준 가운데 두쌍 - SFP+ and Copper -)는 다음과 같이 MAC(PPv2.2)와 PHY(88X3310) 연결 형태로 구성되어 있다. SFP+의 경우는 내부에 i2c device가 포함되어 있어 i2c controller(SoC 내부)와 연결되어 있다(SFP+에 대한 레지스터 설정은 i2c를 통해 이루어짐).

[그림 5.4] MACCHIATObin 보드 eth0/1 10G Interface [출처: 참고문헌 4]

마지막으로 eth3(그림 4.11 기준 맨 우측 포트)은 2.5G interface를 지원하며, 중간에 별도의 PHY를 거치지 않고 곧바로 MAC(PPv2.2)과 연결되어 있다(즉, MAC to MAC 통신을 한다는 뜻). 경우에 따라서는 SFP+ 내에 PHY가 있는 경우도 있는데, 이 경우는 일반적인 MAC to PHY 통신으로 이어지게 된다.

[그림 5.5] MACCHIATObin 보드 eth3 2.5G MAC to MAC Interface [출처: 참고문헌 4]

5.2)  MACCHIATObin의 Ethernet Device Driver 분석
이런, 4.2~4.3 절에서 설치한 linux kernel(4.4.52)에는 [참고문헌 4]에서 말하는 kernel code가 보이질 않는다. 이 내용은 오히려 1장에서 설치한 linux kernel(4.19.62)에 보인다.

<device tree>
arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
<TBD>

[그림 5.6] armada-8040-mcbin.dts 내용 중 일부 발췌

<device drivers>
<Ethernet MAC controller>
drivers/net/ethernet/marvell/mvpp2/*
drivers/net/ethernet/marvell/mvmdio.c

<PHY driver>
drivers/net/phy/marvell.c
drivers/net/phy/marvell10g.c
<TBD>

Device Tree 및 device driver(ethernet MAC & PHY 관련)에 대한 분석은 추후 다시 하기로 하자.

<여기서 잠깐 !>
    => MUSDK와 ODP를 이용한 고속 패킷 처리 방법에 관하여 ...

Marvell User-Space SDK(a.k.a MUSDK)와 ODP(Open Data Plane)를 사용하면 고속 패킷 처리(linux kernel을 경유한 slow path가 아니라 PPv2.2를 이용한 fastpath)가 가능하다고 한다. 이 내용 자체도 하나의 커다른 주제가 될 듯한데, 자세한 사항은 아래 site를 참고하도록 하자.



[그림 5.7] MUSDK를 이용하여 PPv2 활용하기


[그림 5.8] ODP를 이용하여 PPv2 활용하기

이 장의 내용은 (아쉬움이 많이 남는 관계로) 추후 시간을 내어 좀 더 상세히 분석해 보아야 할 것 같다. 😂


6. 응용편: MACCHIATObin 보드를 SoftEther VPN Gateway로 만들기
이 장에서는 MACCHIATObin 보드를 VPN Gateway(SoftEther VPN 기반)로 만드는 과정을 소개하고자 한다. SoftEther VPN과 관련해서는 아래 blog post를 통해 이미 한 차례 소개한 바 있다.


위의 내용을 보면 알겠지만, SoftEther VPN을 cross-compile하는 과정은 연관 library가 많은 관계로 생각처럼 간단하지가 않다. x86_64 환경 처럼 arm64 개발 환경이 준비되어 있다면, cross-compile 없이 native compile 과정만으로도 원하는 결과를 얻을 수 있을텐데, 주변에서 arm64를 기반으로한 PC를 구하는 것은 매우 어렵다. 그렇다면 어떻게 해야 할까 ? 
📌 (비용은 좀 들겠지만) arm64를 지원하는 AWS EC2(or Google Cloud, Azure)를 활용하는 것도 하나의 방법이 될 수는 있다.

지금부터는 이 물음에 대한 대답으로, docker와 QEMU의 도움을 받아 x86 환경에서 arm64 개발 환경을 꾸미고, 그 위에서 SoftEther VPN을 build하는 방법을 소개하고자 한다. 물론 build가 성공한 후에는 target board 상에 올려 정상 동작하는지를 직접 확인해 볼 생각이다.


[그림 6.1] x86 위에 ARM emulation 환경 구축 [출처 - 참고문헌 10]

📌 물론 PINE64, ESPRESSObin 등 arm64 보드를 준비하고 그 위에서 직접 compile하는 방법도 하나의 대안이 될 수 있다. 하지만, 필요할 때마나 개발 보드를 하나씩 준비할 수는 없는 노릇이다.

6.1)  arm64v8(ubuntu 16.04)에서 SoftEther VPN build하기
지금부터는 arm64 emulation 환경을 만들고, 그 위에서 SoftEther VPN를 build해 보도록 하자.

<x86_64 Desktop PC>
sudo apt-get install qemu binfmt-support qemu-user-static
  => qemu, binfmt 등을 설치한다.
$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
  => multi architecture를 지원하는 qemu container를 실행하자.
Unable to find image 'multiarch/qemu-user-static:latest' locally
latest: Pulling from multiarch/qemu-user-static
61c5ed1cbdf8: Pull complete 
6957fb4d1698: Pull complete 
ed8a5179ae11: Pull complete 
1ec39da9c97d: Pull complete 
2901bd4ab058: Pull complete 
Digest: sha256:28ebe2e48220ae8fd5d04bb2c847293b24d7fbfad84f0b970246e0a4efd48ad6
Status: Downloaded newer image for multiarch/qemu-user-static:latest
Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha
Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm
Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb
Setting /usr/bin/qemu-sparc-static as binfmt interpreter for sparc
Setting /usr/bin/qemu-sparc32plus-static as binfmt interpreter for sparc32plus
Setting /usr/bin/qemu-sparc64-static as binfmt interpreter for sparc64
Setting /usr/bin/qemu-ppc-static as binfmt interpreter for ppc
Setting /usr/bin/qemu-ppc64-static as binfmt interpreter for ppc64
Setting /usr/bin/qemu-ppc64le-static as binfmt interpreter for ppc64le
Setting /usr/bin/qemu-m68k-static as binfmt interpreter for m68k
Setting /usr/bin/qemu-mips-static as binfmt interpreter for mips
Setting /usr/bin/qemu-mipsel-static as binfmt interpreter for mipsel
Setting /usr/bin/qemu-mipsn32-static as binfmt interpreter for mipsn32
Setting /usr/bin/qemu-mipsn32el-static as binfmt interpreter for mipsn32el
Setting /usr/bin/qemu-mips64-static as binfmt interpreter for mips64
Setting /usr/bin/qemu-mips64el-static as binfmt interpreter for mips64el
Setting /usr/bin/qemu-sh4-static as binfmt interpreter for sh4
Setting /usr/bin/qemu-sh4eb-static as binfmt interpreter for sh4eb
Setting /usr/bin/qemu-s390x-static as binfmt interpreter for s390x
Setting /usr/bin/qemu-aarch64-static as binfmt interpreter for aarch64    <=== 이걸 지원한다 !
Setting /usr/bin/qemu-aarch64_be-static as binfmt interpreter for aarch64_be
Setting /usr/bin/qemu-hppa-static as binfmt interpreter for hppa
Setting /usr/bin/qemu-riscv32-static as binfmt interpreter for riscv32
Setting /usr/bin/qemu-riscv64-static as binfmt interpreter for riscv64
Setting /usr/bin/qemu-xtensa-static as binfmt interpreter for xtensa
Setting /usr/bin/qemu-xtensaeb-static as binfmt interpreter for xtensaeb
Setting /usr/bin/qemu-microblaze-static as binfmt interpreter for microblaze
Setting /usr/bin/qemu-microblazeel-static as binfmt interpreter for microblazeel
Setting /usr/bin/qemu-or1k-static as binfmt interpreter for or1k

$ docker run -i -t --name arm64 arm64v8/ubuntu:16.04 /bin/bash
  => arm64v8 용 ubuntu 16.04를 실행(container)하자.
root@b2940a44a2ca:/# uname -a
Linux 88ab315a52ad 5.4.0-47-generic #51~18.04.1-Ubuntu SMP Sat Sep 5 14:35:50 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux
root@88ab315a52ad:/# cat /etc/issue
Ubuntu 16.04.7 LTS \n \l

root@b2940a44a2ca:/# apt-get update
root@b2940a44a2ca:/# apt -y install cmake gcc g++ libncurses5-dev libreadline-dev libssl-dev make zlib1g-dev
  => SoftEther VPN build에 필요한 몇가지 package를 설치한다. 추가로 필요한 패키지가 있다면, 적절히 설치해 주면 된다.

📌 예상대로 docker + QEMU 구조이다 보니, 전체적으로 느린 느낌이다.

<SoftEther VPN build>
  => SoftEther VPN s/w와 관련해서는 아래 site 내용을 참조하자.


root@b2940a44a2ca:/# mkdir ~/workspace; cd workspace
root@b2940a44a2ca:/# git clone https://github.com/SoftEtherVPN/SoftEtherVPN.git
root@b2940a44a2ca:/# cd SoftEtherVPN
root@b2940a44a2ca:/# git submodule init && git submodule update
root@b2940a44a2ca:/# ./configure
📌 SoftEther VPN build를 위해서는 cmake 3.7 이상이 필요한데, Ubuntu 16.04는 3.6.1을 사용하고 있어 update해 주었다(자세한 과정은 생략).

root@b2940a44a2ca:/# make -C build
root@b2940a44a2ca:/# make -C build install

[그림 6.2] softether vpn build 결과물

root@b2940a44a2ca:/# tar cvzf sebin.tar.gz /usr/local/lib/lib*.so /usr/local/libexec/softether/
 => build 결과물을 tar.gz 파일로 묶어 보자.
/usr/bin/tar: Removing leading `/' from member names
/usr/local/lib/libcedar.so
/usr/bin/tar: Removing leading `/' from hard link targets
/usr/local/lib/libmayaqua.so
/usr/local/libexec/softether/
/usr/local/libexec/softether/vpnclient/
/usr/local/libexec/softether/vpnclient/vpnclient
/usr/local/libexec/softether/vpnclient/hamcore.se2
/usr/local/libexec/softether/vpncmd/
/usr/local/libexec/softether/vpncmd/hamcore.se2
/usr/local/libexec/softether/vpncmd/vpncmd
/usr/local/libexec/softether/vpnserver/
/usr/local/libexec/softether/vpnserver/hamcore.se2
/usr/local/libexec/softether/vpnserver/vpnserver
/usr/local/libexec/softether/vpnbridge/
/usr/local/libexec/softether/vpnbridge/hamcore.se2
/usr/local/libexec/softether/vpnbridge/vpnbridge

SoftEther VPN에 대한 build가 이루어졌으니, 이제부터는 build 결과 파일을 target board에 올린 후, vpnserver를 구동시켜 볼 차례이다. 편의상 지금부터는 (4장에서 설치한) OpenWrt 대신 Ubuntu 16.04를 사용하도록 하겠다.
📌 물론 OpenWrt에서도 SoftEther VPN을 구동시킬 수 있다. 이와 관련해서는 아래 site 내용이 도움이 될 것 같다.

6.2)  MACCHIATObin 보드에 Ubuntu 16.04 설치 후, SoftEther VPN vpncmd 실행하기
Ubuntu 16.04 설치와 관련해서는 MACCHIATObin wiki page에 상세히 소개되어 있다. 따라서 아래 site의 내용을 반드시 읽어보기 바란다. 여기에서는 꼭 필요한 내용을 중심으로 간략히 정리하고 넘어가도록 하겠다.


<Desktop PC>
$ gunzip -c ./ubuntu-xenial-mcbin_u-boot_sd.img_.gz | sudo dd of=/dev/sdb
7577600+0 레코드 들어옴
7577600+0 레코드 나감
3879731200 bytes (3.9 GB, 3.6 GiB) copied, 1773.49 s, 2.2 MB/s
📌 시간이 매우 오래 걸릴 수 있으니 주의하기 바란다.

<Target board>
Marvell>> setenv bootmmc 'mmc dev 0; ext4load mmc 1:2 $kernel_addr $image_name;ext4load mmc 1:2 $fdt_addr $fdt_name;setenv bootargs $console root=/dev/mmcblk1p2 rw rootwait; booti $kernel_addr - $fdt_addr'
📌 부트로더의 몇가지 설정을 변경해 준다. 자세한 사항은 위의 wiki page를 참조하도록 하자.

[그림 6.3] Ubuntu 16.04 부팅 모습

Ubuntu 16.04.3 LTS localhost.localdomain ttyS0

localhost login: root

root@localhost:~# apt-get update
root@localhost:~# apt-get install libncurses5-dev
root@localhost:~# apt-get install libreadline-dev
root@localhost:~# apt-get install libssl-dev
root@localhost:~# apt-get install zlib1g-dev
📌 SoftEther VPN 실행을 위해 필요한 몇가지 library를 설치해 주자. 설치가 불가한 경우에는 위의 library 파일을 docker 환경(6.1 절)에서 가져올 수도 있겠다.

root@localhost:~# su - chyi
  => user chyi를 사전에 추가하였다.
chyi@localhost:~$ mkdir workspace; cd workspace

<Desktop PC>
chyi@mars:/var/lib/tftpboot$ scp sebin.tar.gz chyi@192.168.2.1:~/workspace
chyi@192.168.1.1's password: 
sebin.tar.gz                                                               100%   14MB  63.6MB/s   00:00

<Target board>
chyi@localhost:~/workspace$ tar xvzf sebin.tar.gz 
usr/local/lib/libcedar.so
usr/local/lib/libmayaqua.so
usr/local/libexec/softether/
usr/local/libexec/softether/vpnclient/
usr/local/libexec/softether/vpnclient/vpnclient
usr/local/libexec/softether/vpnclient/hamcore.se2
usr/local/libexec/softether/vpncmd/
usr/local/libexec/softether/vpncmd/hamcore.se2
usr/local/libexec/softether/vpncmd/vpncmd
usr/local/libexec/softether/vpnserver/
usr/local/libexec/softether/vpnserver/hamcore.se2
usr/local/libexec/softether/vpnserver/vpnserver
usr/local/libexec/softether/vpnbridge/
usr/local/libexec/softether/vpnbridge/hamcore.se2
usr/local/libexec/softether/vpnbridge/vpnbridge

chyi@localhost:~/workspace$ export LD_LIBRARY_PATH=/home/chyi/workspace/usr/local/lib:$LD_LIBRARY_PATH
chyi@localhost:~/workspace$ cd usr/local/libexec/softether/vpncmd
  => OK, vpncmd가 동작한다.

[그림 6.4] softether vpncmd 실행 모습

6.3)  SoftEther VPN 연결 시험하기
이 절에서는 MACCHATObin 보드에 VPN server를 설치하고, (인터넷 반대편에 있는) Windows10 PC에 VPN Client를 설치한 후, 이를 서로 연결하는 시험을 진행해 보도록 하겠다. 시험용 Testbed는 다음과 같다.

<Testbed>
PC(VPN Client) => LTE Router <=== Internet ===> KT AP <= Small AP(repeater mode) <= MACCHATObin(VPN Server) <= Linux PC

VPN server  구동에 앞서, MACCHIATObin을 gateway로 만들기 위해 kernel의 Netfilter 기능을 enable하는 작업을 먼저 진행해야 한다. 

Kernel code download & build 방법은 역시 아래 page에 잘 정리되어 있으니 이를 참조하도록 한다.


$ export PATH=/home/chyi/workspace/mcbin/toolchain/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin:$PATH

$ git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell .
$ git checkout linux-4.4.52-armada-17.10
$ git branch
  linux-3.10.70-15t1
* linux-4.4.52-armada-17.10

$ export ARCH=arm64
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ make mvebu_v8_lsp_defconfig
$ make menuconfig
  => Netfilter 관련 설정은 꽤나 다양하니, 내용을 일일히 살펴본 후 적절히 enable시켜 주도록 한다(상세 내용 생략).

[그림 6.5] Netfilter enable하기

$ make -j4

Kernel compile이 완료되었으니, arch/arm64/boot/Image 파일을 target board에 올린 후, 부팅을 시도해 보자.

<Target board>
root@localhost:~# echo 1 > /proc/sys/net/ipv4/ip_forward
root@localhost:~# iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE
  => 시스템 부팅 후에는 ip_forwarding을 1로 설정하고, masquerading NAT rule을 하나 추가해 준다.

[그림 6.6] iptables masquerading rule 설정

OK, 이 상태에서 정상적으로 인터넷 접속이 되는 것을 확인했다면, 이제 부터는 vpnserver & vpncmd 설정을 시작할 준비할 차례다.

<Target board>
# export LD_LIBRARY_PATH=/home/chyi/workspace/usr/local/lib:$LD_LIBRARY_PATH
# cd usr/local/libexec/softether/vpnserver/
./vpnserver start

[그림 6.7] vpnserver 실행 모습

# cd ../vpncmd
# ./vpncmd
  => 여기서는 VPN Server admin password만을 설정하도록 한다. 나머지 복잡한 설정은 VPN Server manager를 통해 진행할 것이다.

[그림 6.8] vpncmd 실행 후 VPN Server admin password 지정 모습

다음으로 VPN Server Manager를 이용하여 VPN Server에 대한 상세 설정을 진행한다(자세한 설정 과정은 생략).
Windows 10 PC(VPN Server Manager) ==> MACCHIATObin board(LAN port)
📌  VPN Server Manager  & VPN Client Manager 상세 설정 방법은 아래 site에 자세히 정리해 두었으니, 이를 참조하도록 하자(같은 내용을 반복해서 설명하지는 않겠음^^).

VPN Server 설정이 끝난 후에는 아래와 같이 bridge 및 dhcp server 설정을 진행하도록 하자.

<Target board>
  => 먼저 bridge 설정을 해 준다. bridge 설정 대상은 eth0와 tap_vpn(VPN server 설정시 생성되는 tap 기반 interface)이다.
root@localhost:~# ifconfig eth0 0.0.0.0
root@localhost:~# brctl addbr br0
root@localhost:~# brctl addif br0 eth0
root@localhost:~# brctl addif br0 tap_vpn
   => 얘는 VPN Server Manager에서 설정해 주어야만 생성이 된다.
root@localhost:~# ifconfig br0 192.168.2.1 netmask 255.255.255.0 up
root@localhost:~# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.005182112200       no              eth0
                                                                             tap_vpn

다음으로 br0 interface(LAN interface)를 대상으로 dhcp server를 구동시켜 주어야 한다. 
📌  dhcp server가 없으면, vpn client가 vpn server에 연결한 후, ip 주소 & default gw 설정을 못하게 되어 vpn 연결이 완성되지 못하는 문제가 발생한다.

root@localhost:~# apt-get install isc-dhcp-server
root@localhost:~# vi /etc/dhcp/dhcpd.conf 
  => 기존 내용을 모두 지우고, 아래 정보를 입력하도록 한다.

[그림 6.9] /etc/dhcp/dhcpd.conf 수정 내용
root@localhost:~# vi /etc/default/isc-dhcp-server
  => 아래와 같이 br0 interface 정보를 추가한다.
...
INTERFACES="br0"
~
root@localhost:~# systemctl restart isc-dhcp-server
  => dhcp server를 재구동시킨다.

지금까지 설정한 내용(vi 편집 내용 제외)을 하나의 shell script로 정리해 보면 다음과 같다. 부팅시 이 파일이 실행되도록 만들어 주면 편리할 것이다.

[그림 6.10] MACCHIATObin network 설정 내용 정리

자, 모든 것(VPN Server 설정)이 준비되었으니, VPN Client(Windows 10)에서 VPN Client Manager를 통해 vpn 연결을 시도해 보기로 하자(VPN client manager 설정 화면에 대한 설명은 생략).

               Windows 10 PC(VPN Client Manager) => 인터넷 => MACCHIATObin board(WAN port)

VPN 연결이 성공한 후 ip  정보를 확인해 보니, 마치 VPN Gateway 내부에 위치한 것 처럼 ip: 192.168.2.101이고, default gateway: 192.168.2.1 임을 알 수 있다.

[그림 6.11] VPN 연결 후, VPN Client ip 주소 할당 내용 확인

C:\> ping www.google.co.kr
  => OK, ping도 정상이다.

C:\> ssh chyi@192.168.2.1
  => Target board로 ssh login도 가능하다.

[그림 6.12] VPN Client PC에서 VPN Server에 ssh login 모습 

📌  SoftEther VPN(a.k.a SSL VPN)은 Ethernet Frame을 통째로 tunnel에 넣어 전달하기 때문에, (VPN Client가 설치된 PC 입장에서 볼 때) 마치 긴 LAN cable을 VPN Gateway의 LAN port에 연결한 듯한 착각을 일으키게 하는 특징(장점)이 있다. 쉽게 말해 집에 있지만 사무실 망에 연결되어 있는 것과 동일한 효과를 내게 해준다.

끝으로 아래 그림은 VPN client PC에서 (VPN server를 경유하여) internet 접속(web browser)을 할 경우의 최대 CPU 사용량(max: 50% 육박)을 보여주고 있다. 50%는 최악의 상황인 듯 보이며, (편차가 있기는 하지만) 대략 20 ~ 30% 정도의 CPU 점유율을 보여준다(생각보다 좀 많이 먹는 느낌이다).

[그림 6.13] VPN Server의 CPU 점유율 

이상으로 MACCHIATObin 보드에 SoftEther VPN server를 올리고, VPN Client로 접속(Remote access)하는 시험을 해 보았다. 실험 결과, 성능 좋은 Intel CPU 보다는 못하지만, MACCHIATObin을 SoftEther VPN Gateway로 사용하지 못할 이유는 없어  보인다^^.

______________________________

지금까지 MACCHIATObin 보드를 가지고, 이런 저런 시험을 진행해 보았다. 제목에서 보듯이 이번 blog post의 원래 의도는 5장(Ethernet device driver 분석)을 상세히 소개하는 것이었으나, 내용 정리를 하다보니 docker와 SoftEther VPN(6장)에 관한 내용으로 설명이 편중된 느낌이다.

언제나 그렇듯 미흡한 부분은 추후 좀 더 보충할 것을 기약하며 이번 글을 마치도록 하겠다. 이 글이 어느 누군가에게 조금이라도 도움이 되었으면 하는 바램을 가져본다. 😋



7. References
[2] ESPRESSObin ULTRA- Quick Start Guide -Rev 03
[3] Ethernet switch support in the Linux kernel, Alexandre Belloni, Bootlin
[4] From the Ethernet MAC to the link partner, Maxime Chevallier, Antoine Ténart, Bootlin
[6] marvell-link-street-88E6341-product-brief.pdf
[7] http://wiki.macchiatobin.net/tiki-index.php?page=BSP+HowTo
[8] https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04
[9] http://pyrasis.com/Docker/Docker-HOWTO#ps
[10] https://www.stereolabs.com/docs/docker/building-arm-container-on-x86/


SlowBoot

댓글 1개:

  1. 블로그에 많은 공들이 녹아 있는 것 같습니다. 아낌없이 모든 정보를 공유해주시는데, 역시 고수시다. 정보를 통해서 여러동양과 시야를 배우고 갑니다. 감사합니다.

    답글삭제