2024년 6월 21일 금요일

DPDK와 FD.io VPP로 고성능 Security Gateway 만들기(세번째 시간)

이번 posting에서는 지난 시간에 이어 open source project인 DPDK와 FD.io VPP를 이용하여 고성능 WireGuard VPN 장비를 만드는 3가지 방법을 소개해 보고자 한다. 😎




목차
1. VPP on the Intel Appliance
2. VPP WireGuard
3. VPP Linux Control Plane Plugin
4. VPP와 WireGuard-Go 연동하기
5. VPP와 L2 WireGuard 연동하기
6. References


VPP의 WireGuard가 어딘지 모르게 좀 문제가 있는 것 같다. 이번 시간에는 종전의 불안한 문제를 모두 해결하고 제대로 동작하는 VPP WireGuard를 소개하고자 한다. 또한 지난 시간에 다루었던 WireGuard-Go와 L2 WireGuard를 VPP와 연계시키는 방법도 고민해 보고자 한다.

WireGuard & VPP forever !

1. VPP on the Intel Appliance
알리바바(alibaba.com)에서 4 포트 짜리 소형 라우터(Barebone 장비)를 하나 구입했다($83). 이번 시간에는 여기에 VPP를 설치하고, VPP와 연계하는 3가지 유형의 WireGuard를 동작시켜 보도록 하자. 😎

 
[그림 1.1] 4 ports mini router(Intel appliance) [그림 출처 - 참고문헌 11]


  • (A) VPP 기반의 WireGuard - 2, 3장
  • (B) VPP와 Original WireGuard-Go 연동하기 - 4장
  • (C) VPP와 L2 WireGuard 연동하기 - 5장

1) Ubuntu Server 24.04 설치
먼저 Ubuntu server를 설치하도록 하자. Ubuntu server 설치 절차는 (너무나 간단하므로) 별도로 설명하지는 않는다.


[그림 1.2] Intel 2.5G ethernet driver - 4 x RJ45 LAN(10/100/1000/ intel 211AT Gigabits Ethernet)
📌 다행히도 Intel에서 나오는 왠만한 NIC은 DPDK를 지원한다.
📌 Alpine linux를 사용하고 싶었지만, FD.io VPP가 아직 Alpine linux(musl libc)를 지원하지 않는 관계로, 일단 Ubuntu server를 설치하는 것으로 한다.

아래와 같이 ip 설정을 추가/변경하도록 하자. LAN1은 LAN(static ip 설정) 용으로, LAN4는 WAN(dhcp 설정)용으로 사용하도록 설정한다.

[그림 1.3] /etc/netplan/50-cloud-init.yaml 파일 수정

sudo netplan apply
📌 Ubuntu의 network 설정 방식이 자주 바뀐다.

chyi@vppbox:~$ ifconfig -a
 => LAN1(enp1s0)와 LAN4(enp4s0)를 사용하여 gateway 구성을 하도록 하자.

enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
       inet 192.168.3.1  netmask 255.255.255.0  broadcast 192.168.3.255
       inet6 fe80::2e0:1dff:fe6b:bb44  prefixlen 64  scopeid 0x20<link>
       ether 00:e0:1d:6b:bb:44  txqueuelen 1000  (Ethernet)
       RX packets 417  bytes 31023 (31.0 KB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 31  bytes 1762 (1.7 KB)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
       device memory 0xd1000000-d10fffff   

enp2s0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
       ether 00:e0:1d:6b:bb:45  txqueuelen 1000  (Ethernet)
       RX packets 0  bytes 0 (0.0 B)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 0  bytes 0 (0.0 B)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
       device memory 0xd0d00000-d0dfffff   

enp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
       inet 192.168.10.1  netmask 255.255.255.0  broadcast 192.168.10.255
       inet6 fe80::2e0:1dff:fe6b:bb46  prefixlen 64  scopeid 0x20<link>
       ether 00:e0:1d:6b:bb:46  txqueuelen 1000  (Ethernet)
       RX packets 148  bytes 13464 (13.4 KB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 53  bytes 7826 (7.8 KB)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
       device memory 0xd0a00000-d0afffff   

enp4s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
       inet 192.168.8.132  netmask 255.255.255.0  broadcast 192.168.8.255
       inet6 fe80::2e0:1dff:fe6b:bb47  prefixlen 64  scopeid 0x20<link>
       ether 00:e0:1d:6b:bb:47  txqueuelen 1000  (Ethernet)
       RX packets 435  bytes 27085 (27.0 KB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 34  bytes 2858 (2.8 KB)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
       device memory 0xd0700000-d07fffff   

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
       inet 127.0.0.1  netmask 255.0.0.0
       inet6 ::1  prefixlen 128  scopeid 0x10<host>
       loop  txqueuelen 1000  (Local Loopback)
       RX packets 84  bytes 6352 (6.3 KB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 84  bytes 6352 (6.3 KB)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

📌 오래된(?) 사람이라 그런가, ip 명령 보다는 ifconfig, route 명령이 좀 더 익숙하다^^.
 ___________________________________________________________

[그림 1.4] 4 포트 mini 라우터 연결 모습
📌 장비 외관은 그리 예쁘지(?) 않지만, 집에서 사용하기에는 나름 쓸만하다.

2) VPP stable/2406 version 설치
$ git clone https://github.com/FDio/vpp
$ cd vpp
$ git checkout stable/2406
  => 반드시 stable version을 사용하도록 하자. 
make build
make pkg-deb
cd build-root

$ ls -l *.deb
-rw-r--r-- 1 chyi chyi   163486  6월 18 11:18 libvppinfra-dev_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi   198266  6월 18 11:18 libvppinfra_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi    28818  6월 18 11:18 python3-vpp-api_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi 96408338  6월 18 11:18 vpp-dbg_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi  1364866  6월 18 11:18 vpp-dev_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi  6017888  6월 18 11:18 vpp-plugin-core_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi   409128  6월 18 11:18 vpp-plugin-devtools_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi  5251560  6월 18 11:18 vpp-plugin-dpdk_24.06-rc2~1-g624463342_amd64.deb
-rw-r--r-- 1 chyi chyi  5296820  6월 18 11:18 vpp_24.06-rc2~1-g624463342_amd64.deb


VPP 관련 자세한 설치 및 환경 설정 과정은 이전 blog post를 참조하기 바란다.



지금 부터는 4 포트 mini router에 VPP를 올리고, 3가지 유형의 WireGuard가 정상 동작하는지를 확인해 보도록 하자.



2. VPP WireGuard
이번 장에서는 VPP WireGuard(vpp wireguard plugin)를 다시 집중 시험해 보고자 한다. 이번이 3번째 시도다. 제발 이번에는 정상 동작해야 한다. 😭


[그림 2.1] VPP WireGuard 시험 환경(상단: VPP 탑재 mini router, 우측 하단: NanoPi R2S Plus - OpenWrt 탑재)


[그림 2.2] VPP WireGuard 시험 구성도


Kernel WireGuard(vpn ip: 10.1.1.100) <==> VPP WireGuard(vpn ip: 10.1.1.200)


먼저 위의 그림 우측의 VPP 장비 설정을 진행하도록 하자.

<VPP 장비 설정>
$ sudo ifconfig enp1s0 down
$ sudo ifconfig enp4s0 down

$ sudo /usr/bin/dpdk-devbind.py --bind uio_pci_generic 01:00.0
$ sudo /usr/bin/dpdk-devbind.py --bind uio_pci_generic 04:00.0

$ sudo service vpp restart
$ ps aux|grep vpp
root         821  3.4  1.4 85380388 119860 ?     Ssl  02:14   1:54 /usr/bin/vpp -c /etc/vpp/startup.conf

chyi@vppbox:~/workspace$ sudo vppctl
    _______    _        _   _____  ___ 
 __/ __/ _ \  (_)__    | | / / _ \/ _ \
 _/ _// // / / / _ \   | |/ / ___/ ___/
 /_/ /____(_)_/\___/   |___/_/  /_/    

vpp# set int state TwoDotFiveGigabitEthernet1/0/0 up
  => lan port를 up 시킨다.
vpp# set int state TwoDotFiveGigabitEthernet4/0/0 up
  => wan port를 up 시킨다.
vpp# set int ip address TwoDotFiveGigabitEthernet1/0/0 192.168.3.1/24
 => lan port의 ip를 설정한다.
vpp# set int ip address TwoDotFiveGigabitEthernet4/0/0 192.168.8.134/24
 => wan port의 ip를 설정한다.

comment { wireguard create listen-port 51820 src 192.168.8.134 }
vpp# wireguard create listen-port 51820 private-key EI9ujB+gZQakUIA4oQIgGGSNDqIPBAqNWDIQbVam1kE= src 192.168.8.134
wg0
📌 위의 comment 처리해 둔 명령을 사용하게 되면, 명령 사용시마다 curve25519 keypair가 새롭게 생성된다. 따라서 이게 불편할 경우는 위와 같이 하면 된다.
📌 사전 keypair 생성을 위해서는 vpp하고는 무관한, wg 명령을 사용하면 된다.

vpp# show wireguard interface  
[0] wg0 src:192.168.8.134 port:51820
private-key:EI9ujB+gZQakUIA4oQIgGGSNDqIPBAqNWDIQbVam1kE= 108f6e8c1fa06506a4508038a1022018648d0ea20f040a8d
5832106d56a6d641
public-key:NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc= 3550bf6ee5876d3f5953b3a039ba21036697d8ab6e4549276133afe59ecf1807 mac-
key: a1dc7d58a5c05285b029b0c7311bcf683fc31f6ea050e20d58cfc9cbb1c5bc66
  => wireguard interface 설정 상태를 확인한다.

vpp# wireguard peer add wg0 public-key jkOW74X1CRS8fobzmYYPGDkyVhR5rdEa9uh8QA2O/0k= endpoint 192.168.8.182 allowed-ip 0.0.0.0/0 dst-port 51820 persistent-keepalive 15
  => wireguard peer 설정을 추가한다.

vpp# show wireguard peer 
[0] endpoint:[192.168.8.134:51820->192.168.8.182:51820] wg0 keep-alive:15 flags: 0, api-clients count: 0
  adj:
  key:jkOW74X1CRS8fobzmYYPGDkyVhR5rdEa9uh8QA2O/0k= 8e4396ef85f50914bc7e86f399860f183932561479add11af6e87c400d8eff49
  allowed-ips: 0.0.0.0/0
  => peer 설정 상태를 확인한다.  

vpp# set interface state wg0 up
vpp# set interface ip address wg0 10.1.1.200/24
  => wireguard interface wg0를 up 시키고, vpn ip를 할당한다.
vpp# show int addr
TwoDotFiveGigabitEthernet1/0/0 (up):
  L3 192.168.3.1/24
TwoDotFiveGigabitEthernet4/0/0 (up):
  L3 192.168.8.134/24
local0 (dn):
wg0 (up):
  L3 10.1.1.200/24
  => interface 별 ip 설정 상태를 확인한다.

vpp# set interface mtu packet 1420 wg0
  => wg0 interface의 mtu를 1420으로 설정한다.

[그림 2.3] show interface 명령 실행 모습


vpp# ip route add 10.1.1.100/32 via 10.1.1.100 wg0
  => 희한하게도, peer vpn ip랑 ping이 되려면 이렇게 설정해 주어야 한다. 😓 vpn peer가 3000개면 3000개의 routing entry를 추가 ???
📌 via 다음에는 next-hop-ip address를 적어 주어야 한다. 따라서 위 경우는 peer의 vpn ip address를 적어 주는게 맞다.

vpp# ping 10.1.1.100
116 bytes from 10.1.1.100: icmp_seq=1 ttl=64 time=1.2965 ms
116 bytes from 10.1.1.100: icmp_seq=2 ttl=64 time=1.1753 ms
116 bytes from 10.1.1.100: icmp_seq=3 ttl=64 time=1.1436 ms
116 bytes from 10.1.1.100: icmp_seq=4 ttl=64 time=1.1693 ms
116 bytes from 10.1.1.100: icmp_seq=5 ttl=64 time=1.0673 ms

Statistics: 5 sent, 5 received, 0% packet loss

vpp# ping 192.168.2.1
Failed: no egress interface
Failed: no egress interface
Failed: no egress interface
Failed: no egress interface
Failed: no egress interface

Statistics: 0 sent, 0 received, 0% packet loss
vpp# ip route add 192.168.2.0/24 via 10.1.1.100 wg0
  => 역시 peer 쪽 내부망으로 ping이 되려면, 이렇게 해주어야 한다.
vpp# ping 192.168.2.1                              
116 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=1.1416 ms
116 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=1.0501 ms

vpp# ping 192.168.2.163
116 bytes from 192.168.2.163: icmp_seq=1 ttl=63 time=1.7600 ms
116 bytes from 192.168.2.163: icmp_seq=2 ttl=63 time=1.4049 ms
116 bytes from 192.168.2.163: icmp_seq=3 ttl=63 time=1.5987 ms
116 bytes from 192.168.2.163: icmp_seq=4 ttl=63 time=1.4086 ms
116 bytes from 192.168.2.163: icmp_seq=5 ttl=63 time=1.5796 ms

Statistics: 5 sent, 5 received, 0% packet loss
vpp# 

vpp# ping 8.8.8.8
Failed: no egress interface
Failed: no egress interface
Failed: no egress interface
Failed: no egress interface
Failed: no egress interface

Statistics: 0 sent, 0 received, 0% packet loss
vpp# ip route add 0.0.0.0/0 via 10.1.1.100 wg0
  => 이걸 추가해 줄 경우, 모든 패킷이 암호화되어 peer vpn으로 이동한다. 이후 복호화 및 decapsulation 과정을 거쳐 인터넷으로 나가게 된다(이런 것을 Redirection이라고 함).
 
vpp# ping 8.8.8.8                             
116 bytes from 8.8.8.8: icmp_seq=1 ttl=113 time=34.3382 ms
116 bytes from 8.8.8.8: icmp_seq=2 ttl=113 time=33.0499 ms
116 bytes from 8.8.8.8: icmp_seq=3 ttl=113 time=33.5864 ms
116 bytes from 8.8.8.8: icmp_seq=4 ttl=113 time=34.7035 ms
116 bytes from 8.8.8.8: icmp_seq=5 ttl=113 time=33.2864 ms

Statistics: 5 sent, 5 received, 0% packet loss

routing table 내용(FIB: forwarding information base)을 살펴 보자. netstat -nr, ip route show 같은 명령 실행시 출력되는 내용 보다는 좀 더 많은 내용이 출력된다.

[그림 2.4] show ip fib(라우팅 table 확인) 명령 실행 모습

📌 (당연한 거지만) 위의 ping이 정상 동작하기 위해서는, 실제로 아래 NanoPi 쪽 설정이 진행되고 난 이후이다. 내용 전개상 먼저 정리한 것 뿐이다.

다음으로 시험 구성도 좌측의 NanoPi 설정을 할 차례이다. WireGuard 설정 관련해서는 아주 여러 차례 소개한 바 있으므로, 자세한 설명은 생략하기로 한다.

<nanopi r2s plus>
# wg genkey | tee ./privatekey | wg pubkey > ./publickey
# ip link add dev wg0 type wireguard
# ip address add dev wg0 10.1.1.100/24
# ip link set up dev wg0

# wg set wg0 listen-port 51820 private-key ./keys/privatekey peer NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc= allowed-ips 0.0.0.0/0 endpoint 192.168.8.134:51820

# route add -net 192.168.3.0/24 dev wg0

root@nanobox-r2s-plus:~/workspace/l3_wireguard# netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.8.1     0.0.0.0         UG        0 0          0 eth0
10.1.1.0        0.0.0.0         255.255.255.0   U         0 0          0 wg0
192.168.2.0     0.0.0.0         255.255.255.0   U         0 0          0 br-lan
192.168.3.0     0.0.0.0         255.255.255.0   U         0 0          0 wg0
192.168.8.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0
root@nanobox-r2s-plus:~/workspace/l3_wireguard# 

wireguard 설정 상태를 확인해 보도록 하자.

[그림 2.5] wg show wg0 명령 실행 모습


이 상태에서 peer 쪽(VPP 장비)으로 ping을 시도해 보니, (드디어) 모두 정상 동작한다. 🏆
[그림 2.6] Server => VPP 방향으로 ping 모습


그 동안 뭐가 달라진 걸까 ?
  • 일단 stable version을 사용한 것이 답이었던 것 같다.
  • 또한 peer vpn ip로 ping을 하기 위해 아래와 같은 routing entry를 추가해 줘야 한다는 깨달음(?)이 있었다.
    • ip route add 10.1.1.100/32 via 10.1.1.100 wg0
암튼, 몇 차례의 시행 착오 끝에 드디어 VPP WireGuard가 정상 동작하는 것을 확인할 수 있었다. 앞으로 이걸 이용해 상용화 제품을 만들어 보아야 겠다. 🌈



3. VPP Linux Control Plane Plugin
일반적으로 ASIC으로 switch/router 등을 만들어 사용하는 경우를 보면, ASIC은 data plane(data 송/수신 처리)의 역할을 담당하고, linux(host or CPU)는 이를 제어하는 control plane의 역할을 하게 된다. 이 경우, ASIC에서 제공하는 physical interface는 (적절한) linux driver를 통해 control plane에 표출(virtual interace)되고, linux 쪽에서는 해당 interface를 이용하여 network 구성을 하는 경우가 일반적이다. 즉, 일반적인 NIC을 장착했을 경우나 ASIC을 사용하는 경우나 linux 입장에서는 동일한 방식으로 처리하게 된다.

data plane <=> physical interface <=> control plane

[그림 3.1] Control plane(좌측)과 Data plane(우측)의 예
📌 오래 전에 만들었던, switching hub의 architecture이다. 물론 이 그림에서 control plane에 linux가 설치된 것은 아니나, control plane과 data plane의 개념을 파악하는 차원에서 추가해 보았다. 😋 고속의 패킷 처리가 필요한 부분은 우측의 ASIC에서 처리하고, ASIC에서 처리가 불가한 것들(예: DHCP)은 control plane(CPU)으로 올려 처리를 하는 구조로 이해하면 된다.

[그림 3.2] Control plane(CPU)과 Data plane(Switch)의 관계 [그림 출처 - 참고문헌 13]

흔히들 VPP를 S/W ASIC에 비유하곤 한다. 하지만, 이런 비유하고는 걸맞지 않게 지금까지 (2장에서) 설명한 내용은 vppctl CLI를 통해서 VPP가 제공하는 interface를 기반으로 설정을 진행하는 방식이었다. 이 경우, linux(host or CPU) 쪽에는 관련하여 아무런 network interface 정보가 보이지 않기 때문에, linux shell 상태에서는 network 동작을 직접적으로 확인할 수는 있는 방법이 없었다.

이번 장에서는 이러한 불편함을 해소하기 위해, VPP에서 제공(21.06 버젼 이후에 추가)하는 Linux Control Plane Plugin에 관하여 소개하고자 한다. 


[그림 3.3] VPP Linux Control Plane [그림 출처: 참고문헌 1]

📌 주의) lcp plugin을 사용하려면 /etc/vpp/startup.conf의 plugins section에 아래 내용을 추가해 주어야 한다.

📌 이제 부터는 create tap 명령을 사용할 필요 없이, lcp create 명령을 사용하는 것만으로 충분하다. lcp create도 내부적으로는 tap interface를 기반으로 동작한다.

1) Linux Control Plane 설정 
2장에서 설정한 내용을 유지한 상태에서, lcp 관련 설정을 추가해 보도록 한다.

<VPP 장비 설정>
<vpp 설정>
vpp# lcp create TwoDotFiveGigabitEthernet1/0/0 host-if eth0
 => vpp physical interface에 대한 host interface(eth0)를 생성한다. 이 경우 vpp 쪽에는 tap1 interface가 생성되고, host 쪽에는 eth0가 생성된다. 
vpp# lcp create TwoDotFiveGigabitEthernet4/0/0 host-if eth3
 => vpp physical interface에 대한 host interface(eth3)를 생성한다. 이 경우 vpp 쪽에는 tap2 interface가 생성되고, host 쪽에는 eth3가 생성된다. 
vpp# lcp create wg0 host-if wg0 tun
  => vpp wireguard interface wg0에 대한 host interface wg0를 생성한다. vpp 쪽에는 tun3 interface가 생성되고, host 쪽에는 wg0가 생성된다.
vpp# show interface

📌 lcp(linux control plane) create 명령을 사용하면 tap interface가 자동으로 생성된다. 단, 명령 마지막에 tun option을 줄 경우는 tap 대신, tun interface가 생성된다. tap/tun interface는 linux host와 통신하는 용도로 사용된다.

data plane <=> tap/tun interface <=> control plane


<Linux host 설정>
$ sudo ip link set eth0 up mtu 9000
$ sudo ip addr add 192.168.3.1/24 dev eth0
📌  lcp lcp-sync on 명령을 사용하게 되면, mtu, ip 설정을 추가로 할 필요가 없다. 여기서는 lcp-sync off 상태라고 가정하고 설정 작업을 한다.

$ sudo ip link set eth3 up mtu 9000
$ sudo ip addr add 192.168.8.134/24 dev eth3

$ sudo ip link set wg0 up mtu 1420
$ sudo ip addr add 10.1.1.200/24 dev wg0

$ sudo route add default gw 192.168.8.1
or
$ sudo route add default gw 10.1.1.100 dev wg0
 => default gw를 지정해야만 peer 쪽 PC에서 ssh 연결시 접속이 가능해진다.

다음으로 위의 그림 좌측의 NanoPi 설정을 할 차례이다(2장에서 설정한 내용과 동일하다).

<nanopi r2s plus>
wg genkey | tee ./privatekey | wg pubkey > ./publickey
ip link add dev wg0 type wireguard
ip address add dev wg0 10.1.1.100/24
# ip link set up dev wg0


wg set wg0 listen-port 51820 private-key ./keys/privatekey peer NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc= allowed-ips 0.0.0.0/0 endpoint 192.168.8.134:51820

route add -net 192.168.3.0/24 dev wg0

와우, 지금까지는 vpp cli 상에서만 wireguard 동작을 확인할 수 있었다. 하지만, 이제 부터는 linux(host)에서도 동작 확인이 가능하다. 😁


[그림 3.4] Linux Control Plane을 활용하여 원격 ssh 접속하는 모습


chyi@vppbox:~$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.1.1.0        0.0.0.0         255.255.255.0   U         0 0          0 wg0
192.168.3.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0
192.168.8.0     0.0.0.0         255.255.255.0   U         0 0          0 eth3
192.168.10.0    0.0.0.0         255.255.255.0   U         0 0          0 enp3s0
📌 기존에는 없던, eth0, eth3, wg0 interface가 눈에 보인다. 심지어 이를 통해 통신도 가능하다.

chyi@vppbox:~$ ping 10.1.1.100
PING 10.1.1.100 (10.1.1.100) 56(84) bytes of data.
64 bytes from 10.1.1.100: icmp_seq=1 ttl=64 time=1.38 ms
64 bytes from 10.1.1.100: icmp_seq=2 ttl=64 time=1.32 ms
64 bytes from 10.1.1.100: icmp_seq=3 ttl=64 time=1.18 ms
^C
--- 10.1.1.100 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 1.177/1.294/1.384/0.086 ms

chyi@vppbox:~$ ping 192.168.3.1
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
64 bytes from 192.168.3.1: icmp_seq=1 ttl=64 time=0.036 ms
64 bytes from 192.168.3.1: icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from 192.168.3.1: icmp_seq=3 ttl=64 time=0.045 ms
^C
--- 192.168.3.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2052ms
rtt min/avg/max/mdev = 0.036/0.041/0.045/0.003 ms

chyi@vppbox:~$ ping 192.168.3.100
PING 192.168.3.100 (192.168.3.100) 56(84) bytes of data.
64 bytes from 192.168.3.100: icmp_seq=1 ttl=64 time=0.504 ms
64 bytes from 192.168.3.100: icmp_seq=2 ttl=64 time=0.258 ms
64 bytes from 192.168.3.100: icmp_seq=3 ttl=64 time=0.238 ms
^C
--- 192.168.3.100 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2068ms
rtt min/avg/max/mdev = 0.238/0.333/0.504/0.120 ms

chyi@earth:~$ ssh chyi@192.168.3.1
chyi@192.168.3.1's password:  
  => ssh 접속도 가능하다.
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-35-generic x86_64)

* Documentation:  https://help.ubuntu.com
* Management:     https://landscape.canonical.com
* Support:        https://ubuntu.com/pro

System information as of Wed Jun 19 03:16:35 AM UTC 2024

 System load:  0.68               Swap usage:  0%       Users logged in: 1
 Usage of /:   11.7% of 56.88GB   Temperature: 58.0 C
 Memory usage: 29%                Processes:   120

* Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
  just raised the bar for easy, resilient and secure K8s cluster deployment.

  https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

35 updates can be applied immediately.
To see these additional updates run: apt list --upgradable

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Wed Jun 19 09:06:03 2024 from 192.168.2.163
chyi@vppbox:~$

___________________________________________________________________________________

지금까지 lcp 기능을 이용하여, linux host에서도 일반 network 설정 및 wireguard가 정상 동작하는 것을 확인하였다.

끝으로, 2장 및 3장에서 설정한 내용이 vpp restart 시에 자동으로 적용되도록 하고 싶다면, 아래와 같이 /etc/vpp/startup.conf 파일에 1줄을 추가해 주기 바란다.

startup-config /etc/vpp/setup.gate

[그림 3.5] /etc/vpp/startup.conf 파일 내용 수정

지금까지 테스트한 /etc/vpp/setup.gate 파일 내용은 다음과 같다.

[그림 3.6] /etc/vpp/setup.gate 파일 내용
📌 lcp lcp-sync on 명령은 vpp에서 설정/변경한 lcp 명령이 linux host에서도 그대로 적용되도록 sync를 맞추고 싶은 경우에 사용한다.

<여기서 잠깐 !>
앞서서, vpp 구동 시 기존 설정 내용을 적용하는 방법을 살펴 보았다. 그렇다면, vppctl로 현재까지 설정한 내용을 file로 저장하고 싶은 경우에는 어찌해야 할까 ? 아무리 찾아 보아도, 아직 vpp에서는 공식적으로 이런 기능을 제공하지 않는 것 같다. 다만 (lcp plugin 개발자가 만든) 아래와 같은 재밌는 project가 진행 중이니, 참조해 보기 바란다.

__________________________________________________________________

VPP에서 lcp plugin이 왜 중요하나면, 지금까지 설명한 userspace wireguard-go 뿐만 아니라, linux userspace에서 동작하는 다양한 application(예를 들어, snort, nginx, HA proxy ...)을 자유롭게 사용(VPP 환경에서 사용)할 수 있기 때문이다.


2) Packet Filtering
걱정했던 것과는 달리, wireguard는 물론이고, lcp를 이용한 network 통신에 문제가 없다(아무런 걱정이 없다). 따라서 이제 남은 걱정(?)은 오직 filtering 뿐이다.

우선, lcp 기능 덕에 iptables 명령이 먹힐 것 같은데, 시도해 보자.

chyi@vppbox:~$ sudo iptables -I INPUT -p tcp -s 0.0.0.0/0 -d 192.168.3.1 --dport 22 -j DROP
  => OK, 예상대로 이건 제대로 먹힌다.
chyi@vppbox:~$ sudo iptables -I INPUT -p icmp -s 0.0.0.0/0 -d 192.168.3.1 -j DROP
  => 이건 VPP에서 응답을 해주는 까닭에 안 먹힌다.


그렇다면, 지금부터는 지난번  posting에서 완성하지 못한 ACL plugin을 다시 들여다 볼 차례이다.

vpp# set acl-plugin ?
 set acl-plugin acl                       set acl-plugin acl [index <idx>] <permit|deny|permit+reflect> src <PREFIX> dst
<PREFIX> [proto X] [sport X[-Y]] [dport X[-Y]] [tcpflags <int> mask <int>] [tag FOO] {use comma separated list for multipl
e rules}
 set acl-plugin interface                 set acl-plugin interface <interface> <input|output> <acl INDEX> [del]  
 set acl-plugin                           set acl-plugin session timeout {{udp idle}|tcp {idle|transient}} <seconds>


vpp# set acl-plugin acl deny src 192.168.2.0/24 dst 192.168.8.134 proto 1   
ACL index:0
  => 192.168.2.0/24 -> 192.168.8.134로 향하는 icmp packet을 차단하는 rule을 추가한다.       
vpp# set acl-plugin interface TwoDotFiveGigabitEthernet4/0/0 input acl 0
  => acl index:0 rule을 WAN interface(input 방향)에 적용한다. 이 상태에서 ping test를 해 보니 차단된다.

vpp# set acl-plugin interface TwoDotFiveGigabitEthernet4/0/0 input acl 0 del
  => 위의 규칙을 제거해 본다. 이 상태에서 ping test를 해 보니 동작한다.

vpp# set acl-plugin acl deny src 192.168.2.0/24 dst 192.168.8.134 proto 6 dport 22
ACL index:1
vpp# set acl-plugin interface TwoDotFiveGigabitEthernet4/0/0 input acl 1           
vpp# set acl-plugin interface TwoDotFiveGigabitEthernet4/0/0 input acl 1 del
vpp# set acl-plugin interface TwoDotFiveGigabitEthernet4/0/0 input acl 1   
  => 비슷하게, tcp 22(ssh)의 경우도 테스트해 보니, 정상 동작한다.

vpp# show acl-plugin acl  
acl-index 0 count 1 tag {cli}
         0: ipv4 deny src 192.168.2.0/24 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535
 applied inbound on sw_if_index:  
 used in lookup context index:  
acl-index 1 count 1 tag {cli}
         0: ipv4 deny src 192.168.2.0/24 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535
 applied inbound on sw_if_index: 2
 used in lookup context index: 0

vpp# show acl-plugin interface                                
sw_if_index 0:
sw_if_index 1:
sw_if_index 2:
 input acl(s): 1
_______________________________________________________________

헐, acl 기반 packet filtering이 정상 동작한다. 역시 stable version 문제였다는 얘긴가 ! 😎



4. VPP와 WireGuard-Go 연동하기
이번 장에서는 3장에서 언급한 linux control plane을 기반으로, VPP와 original WireGuard-Go를 연동시키는 방법을 소개해 보고자 한다. VPP WireGuard와 비교하여 성능적인 측면에서 어떨지 우려되는 부분도 있으나, 그래도 시도해 볼만한 가치가 있다. 도전해 보기 전에는 결코 알 수가 없다. 💢


[그림 4.1] VPP와 WireGuard-Go를 연동시키기(1)

<기본 idea>
  • lcp create 명령을 사용하여 physical interface(TwoDotFiveGigabitEthernet1/0/0, TwoDotFiveGigabitEthernet4/0/0)에 상응하는 Linux host 쪽 virtual interface(eth0, eth3)를 생성한다.
  • (일반적으로 하듯이) wireguard-go를 WAN 쪽(eth3)에서 구동시킨다.
  • WAN 쪽에 bridge(bvi1) interface를 하나 만들고, TwoDotFiveGigabitEthernet4/0/0 및 tap2(eth3과 연결되는 tap interface) interface를 bridge에 포함시킨다. 즉, bridge bvi1 = { TwoDotFiveGigabitEthernet4/0/0 + tap2 } 형태가 되도록 ...
  • tap2는 eth3와 연결되어 있기 때문에 이를 bridge에 추가시키는 것으로 wireguard-go 구동되는 조건이 만들어 진다.

[그림 4.2] VPP와 WireGuard-Go를 연동시키기(2) - WAN bridge 구성

먼저, VPP 장비 쪽 설정을 진행하도록 하자.

<우측 VPP 장비 설정>
<vpp 설정>
$ sudo vppctl
# set int state TwoDotFiveGigabitEthernet1/0/0 up
# set int state TwoDotFiveGigabitEthernet4/0/0 up
# set int ip address TwoDotFiveGigabitEthernet1/0/0 192.168.3.1/24
# set int ip address TwoDotFiveGigabitEthernet4/0/0 192.168.8.134/24

# lcp create TwoDotFiveGigabitEthernet1/0/0 host-if eth0
# lcp create TwoDotFiveGigabitEthernet4/0/0 host-if eth3
# lcp lcp-sync on

# bvi create instance 1
# set int l2 bridge bvi1 2 bvi
# set int ip address bvi1 10.1.1.200/24
# set int state bvi1 up
  => l2 bridge interface bvi1을 생성하고, vpn ip 10.1.1.200을 할당해 준다.

# set int l2 bridge TwoDotFiveGigabitEthernet4/0/0 2
# set int l2 bridge tap2 2
  => bridge interface에  
TwoDotFiveGigabitEthernet4/0/0와 tap2를 추가한다.

<wireguard-go 설정>
sudo ./wireguard-go wg0

sudo ip address add dev wg0  10.1.1.200/24
sudo ip link set up dev wg0
sudo wg set wg0 listen-port 51820 private-key /home/chyi/workspace/keys/privatekey peer jkOW74X1CRS8fobzmYYPGDkyVhR5rdEa9u
h8QA2O/0k= allowed-ips 0.0.0.0/0 endpoint 192.168.8.182:51820

$ sudo route add default gw 10.1.1.100 dev wg0
 => default gw를 지정해야만 peer 쪽 PC에서 ssh 연결시 접속이 가능해진다.
------------------------------------------------------------------------

다음으로 위의 그림 좌측의 NanoPi 설정을 할 차례이다(앞서 2장에서 설정한 내용과 동일하다).

<nanopi r2s plus>
wg genkey | tee ./privatekey | wg pubkey > ./publickey
ip link add dev wg0 type wireguard
ip address add dev wg0 10.1.1.100/24
# ip link set up dev wg0

wg set wg0 listen-port 51820 private-key ./keys/privatekey peer NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc= allowed-ips 0.0.0.0/0 endpoint 192.168.8.134:51820

route add -net 192.168.3.0/24 dev wg0
 => 192.168.3.0/24 network에 접근 시, wireguard를 타도록 하기 위해 추가한다.

이 상태에서 좌측(NanoPi)에서 우측(VPP Box)로 ping 및 ssh를 시도해 보자. 와우 모두 정상이다. 😀

chyi@earth:~$ ping 10.1.1.200
PING 10.1.1.200 (10.1.1.200) 56(84) bytes of data.
64 bytes from 10.1.1.200: icmp_seq=1 ttl=63 time=2.03 ms
64 bytes from 10.1.1.200: icmp_seq=2 ttl=63 time=4.34 ms
64 bytes from 10.1.1.200: icmp_seq=3 ttl=63 time=1.88 ms
^C
--- 10.1.1.200 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 1.884/2.749/4.335/1.123 ms

chyi@earth:~$ ping 192.168.3.1
PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
64 bytes from 192.168.3.1: icmp_seq=1 ttl=63 time=2.07 ms
64 bytes from 192.168.3.1: icmp_seq=2 ttl=63 time=2.11 ms
64 bytes from 192.168.3.1: icmp_seq=3 ttl=63 time=1.87 ms
64 bytes from 192.168.3.1: icmp_seq=4 ttl=63 time=1.82 ms
64 bytes from 192.168.3.1: icmp_seq=5 ttl=63 time=1.91 ms
^C
--- 192.168.3.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 1.823/1.957/2.114/0.115 ms


chyi@earth:~$ ssh chyi@192.168.3.1
chyi@192.168.3.1's password:  
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-35-generic x86_64)

* Documentation:  https://help.ubuntu.com
* Management:     https://landscape.canonical.com
* Support:        https://ubuntu.com/pro


그렇다면, 이 상태에서 반대 방향 즉, 우측 VPP Box에서 좌측 NanoPi 쪽으로 ping과 ssh 등을 시도해 보자. 어라, 안된다. 😈  뭐가 문제일까 ?
가만히 생각해 보니, 앞서 설정한 내용만 가지고서는 내부망의 PC에서 VPP를 타고 외부로 나가는 packet이 wireguard-go를 탈 이유가 없어 보인다(wireguard-go는 userspace에 위치하고 있기 때문).

내부 PC(Notebook) => TwoDotFiveGigabitEthernet1/0/0 => VPP(forwarding) =>  TwoDotFiveGigabitEthernet4/0/0

(다각도로 시도해 보았으나) 결국, vpp 외부에 wireguard-go를 두고 운영하는 방법은 Gateway 방식은 불가하며, standalone server로 구성할 경우 의미가 있어 보인다.

인터넷을 뒤져 보니, wireguard-go를 VPP와 연동시키는 project가 보인다. 이 방법을 다시한번 시도해 보아야겠다. 😂






5. VPP와 L2 WireGuard 연동하기
이번 장에서는 지난 post에서 다루었던, L2 WireGuard를 VPP와 연동시키는 방법을 소개해 보고자 한다. 이름하여 VPP L2 WireGuard가 되겠다. 😎

[그림 5.1] L2 WireGuard와 VPP 연동하기(1)

1) Ubuntu server용 wireguard kernel build 하기
우선 Ubuntu용 linux kernel build가 시급하다. 개발 중인 PC는 Ubuntu desktop 22.04 LTS이고, mini router의 버젼은 Ubuntu Server 24.04 LTS이다. 어찌하는게 답일지 고민이 된다. 😨 Linux PC에서 빠르게 build 후, wireguard.ko만 교체해 보았으나, 아래 문제가 발생한다. kernel을 한번은 교체해야 해결되는 문제인데, 어쩔 수가 없다. 일단 매우 느릴 것이 예상되지만, target machine(ubuntu server)에서 build를 진행해 보도록 하자. 아니면, PC에서 빠르게 build 후, 전체 linux kernel directory를 묶어 server로 올린 후, 설치(kernel 교체)해야 하나 ?

[ 2565.493990] wireguard: disagrees about version of symbol module_layout


<ubuntu 24.04 server>
$ sudo sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
 => ubuntu 24.04 부터 kernel source를 내려 받는 방법이 좀 바뀌었다.

$ sudo apt build-dep linux linux-image-$(uname -r) 
  => 얘를 수행하면 에러가 발생하는데, 무시해도 된다.

$ sudo apt install libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev \
   libudev-dev libpci-dev libiberty-dev autoconf llvm build-essential libncurses5-dev gcc bc dwarves
$ sudo apt-get update


$ sudo su

# apt source linux-image-unsigned-$(uname -r)
  => linux kernel source를 내려 받는다.

# ls -l
drwxr-xr-x 29 root root      4096 Jun 20 14:02 linux-6.8.0
-rw-r--r--  1 root root   1616761 May 23 20:58 linux_6.8.0-35.35.diff.gz
-rw-r--r--  1 root root      9267 May 23 20:58 linux_6.8.0-35.35.dsc
-rw-r--r--  1 root root 230060117 Mar 15 15:29 linux_6.8.0.orig.tar.gz

# cd linux-6.8.0
# chmod a+x debian/scripts/*
# chmod a+x -R ./scripts

cp /boot/config-6.8.0-35-generic ./.config
 => ubuntu server의 kernel config를 복사해 온다.

# make oldconfig

# make -j4
  => 상당한 시간이 경과한 후, 결국 build되었다.

# make modules_install
# make install

[그림 5.2] ubuntu server용 linux kernel install 모습

# reboot

부팅 후, wireguard를 수동으로 올려 보니, 정상 구동된다.

[그림 5.3] wireguard 구동 모습


2) L2 WireGuard와 VPP 연동하기
이전 posting 내용을 참고하여, l2 wireguard code를 porting 한 후, VPP 환경에서 돌려 보도록 하자.



l2 wireguard code를 적용한 wireguard.ko를 교체하도록 한다.

chyi@vppbox:~/workspace/ubuntu/linux-6.8.0/drivers/net/wireguard$ sudo cp ./wireguard.ko /lib/modules/6.8.4/kernel/
drivers/net/wireguard/
chyi@vppbox:~/workspace/ubuntu/linux-6.8.0/drivers/net/wireguard$ ls -l /lib/modules/6.8.4/kernel/drivers/net/wireg
uard/
total 12236
-rw-r--r-- 1 root root 6318560 Jun 22 08:32 wireguard.ko
-rw-r--r-- 1 root root 6208945 Jun 22 07:07 wireguard.ko.ORIG

chyi@vppbox:~/workspace/ubuntu/linux-6.8.0/drivers/net/wireguard$ sudo modprobe wireguard

chyi@vppbox:~/workspace/ubuntu/linux-6.8.0/drivers/net/wireguard$ lsmod | grep wireguard
wireguard             118784  0
curve25519_x86_64      36864  1 wireguard
libchacha20poly1305    16384  1 wireguard
libcurve25519_generic    49152  2 curve25519_x86_64,wireguard
ip6_udp_tunnel         16384  1 wireguard
udp_tunnel             32768  1 wireguard

___________________________________________________________________________

wireguard.ko가 l2 wireguard로 교체되었으니, l2 wireguard와 VPP를 연동할 차례이다.

<기본 idea>
  • lcp create 명령을 사용하여 physical interface(TwoDotFiveGigabitEthernet1/0/0, TwoDotFiveGigabitEthernet4/0/0)에 상응하는 Linux host 쪽 virtual interface(eth0, eth3)를 생성한다.
  • l2 wireguard는 LAN 쪽(eth0)에서 bridge에 추가되어야 한다.
  • LAN 쪽에 bridge(bvi0) interface를 하나 만들고, TwoDotFiveGigabitEthernet1/0/0, tap1(eth0과 연결되는 tap interface) interface를 bridge에 포함시킨다. 즉, bridge bvi0 = { TwoDotFiveGigabitEthernet1/0/0 + tap1 } 형태가 되도록 ...
  • linux host에서는 brctl을 이용하여 br-lan interface를 하나 만들고, 여기에 eth0와 wg1(l2 wireguard)를 추가시킨다. 즉, br-lan = { eth0 + wg1 }
  • 2번의 bridge 생성 과정을 통해 최종 bridge = { TwoDotFiveGigabitEthernet1/0/0 + tap1 + eth0 + wg1 }가 완성되고, bridge를 통해 l2 wireguard 자연스럽게 구동된다.

[그림 5.4] L2 WireGuard와 VPP 연동하기(2)


조금은 난해하지만, 아래와 같은 개념도를 생각해 볼  수 있다.

[그림 5.5] L2 WireGuard와 VPP 연동하기(3)
📌 l2 vpn은 한쪽 network이 다른 쪽 network으로 이동(?)하는 시험이다. 여기서는 편의상 우측 vpp network이 좌측 NanoPi network으로 이동하는 시험을 할 것이다.

먼저, VPP 장비 쪽 설정을 진행하도록 하자.

<우측 VPP 장비 설정>

<vpp 설정>
sudo vppctl
set int state TwoDotFiveGigabitEthernet1/0/0 up
set int state TwoDotFiveGigabitEthernet4/0/0 up
set int ip address TwoDotFiveGigabitEthernet1/0/0 192.168.3.1/24
set int ip address TwoDotFiveGigabitEthernet4/0/0 192.168.8.134/24

lcp create TwoDotFiveGigabitEthernet1/0/0 host-if eth0
lcp create TwoDotFiveGigabitEthernet4/0/0 host-if eth3
lcp lcp-sync on

bvi create instance 0
set int l2 bridge bvi0 1 bvi
set int state bvi0 up
  => l2 bridge interface bvi0를 생성한다.

set int l2 bridge TwoDotFiveGigabitEthernet1/0/0 1
set int l2 bridge tap1 1
  => bridge interface에 
TwoDotFiveGigabitEthernet1/0/0와 tap1을 추가한다.

# ip route add 0.0.0.0/0 via 192.168.8.1 TwoDotFiveGigabitEthernet4/0/0
 => default gateway 설정을 추가한다.

<l2 wireguard 설정>
sudo wg genkey | tee ./privatekey | wg pubkey > ./publickey
  => curve25519 keypair를 생성한다.

sudo ip link add dev wg1 type l2wireguard
=> l2wireguard를 지정해 주어야 ethernet frame을 통째로 tunneling할 수 있다.

sudo ip link set dev wg1 address 00:e0:1d:6b:bb:47
  => l2 wireguard의 경우는 ethernet device 형태이기 때문에 MAC 주소를 반드시 지정해 주어야 한다.

sudo ip link set wg1 up
  => l2 wireguard interface를 up시킨다.

sudo wg set wg1 listen-port 51820 private-key ./keys/privatekey peer jkOW74X1CRS8fobzmYYPGDkyVhR5rdEa9u
h8QA2O/0k= allowed-ips 0.0.0.0/0 endpoint 192.168.8.182:51820
  => l2 wireguard peer 설정을 한다.

$ sudo ifconfig br-lan down
$ sudo brctl delbr br-lan
  => 기존에 설정되어 있는 br-lan bridge interface를 내린다.

$ sudo ifconfig eth0 0.0.0.0
$ sudo ifconfig wg1 0.0.0.0
  => bridge에 포함시킬 interface의 ip 주소를 없앤다. openwrt의 경우 eth0은 LAN interface임.

$ sudo brctl addbr br-lan
$ sudo brctl addif br-lan eth0
$ sudo brctl addif br-lan wg1
  => br-lan interface를 새로 생성하고, eth0과 wg1 interface를 bridge에 포함시킨다.

$ brctl setfd br-lan 1
$ brctl stp br-lan 1

$ sudo ip link set br-lan up
  => bridge interface를 up 시킨다.

$ sudo route add default gw 192.168.8.1 dev eth3
  => default gateway를 추가한다.
_______________________________________________________________

vpp# show interface  
             Name               Idx    State  MTU (L3/IP4/IP6/MPLS)     Counter          Count      
TwoDotFiveGigabitEthernet1/0/0    1      up          9000/0/0/0     tx-error                       1
TwoDotFiveGigabitEthernet4/0/0    2      up          9000/0/0/0     rx packets                     3
                                                                   rx bytes                     310
                                                                   tx packets                     5
                                                                   tx bytes                     500
                                                                   drops                          1
                                                                   ip4                            1
                                                                   tx-error                       2
bvi0                              5      up          9000/0/0/0     rx packets                     1
                                                                   rx bytes                      76
                                                                   drops                          1
                                                                   ip6                            1
local0                            0     down          0/0/0/0       drops                          1
tap1                              3      up          9000/0/0/0     rx packets                     1
                                                                   rx bytes                      90
                                                                   drops                          1
tap2                              4      up          9000/0/0/0     rx packets                     5
                                                                   rx bytes                     530
                                                                   tx packets                     2
                                                                   tx bytes                     250
                                                                   drops                          1
                                                                   ip4                            1
                                                                   ip6                            3


chyi@vppbox:~/workspace/wireguard/l2_wireguard$ ifconfig wg1
wg1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1406
       ether 00:e0:1d:6b:bb:47  txqueuelen 1000  (Ethernet)
       RX packets 181630  bytes 240785636 (240.7 MB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 49164  bytes 6296094 (6.2 MB)
       TX errors 363  dropped 0 overruns 0  carrier 0  collisions 0

chyi@vppbox:~/workspace/wireguard/l2_wireguard$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.8.1     0.0.0.0         UG        0 0          0 eth3
192.168.8.0     0.0.0.0         255.255.255.0   U         0 0          0 eth3
192.168.10.0    0.0.0.0         255.255.255.0   U         0 0          0 enp3s0

chyi@vppbox:~/workspace/wireguard/l2_wireguard$ sudo wg show wg1
interface: wg1
 public key: NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc=
 private key: (hidden)
 listening port: 51820

peer: jkOW74X1CRS8fobzmYYPGDkyVhR5rdEa9uh8QA2O/0k=
 endpoint: 192.168.8.182:51820
 allowed ips: 0.0.0.0/0
 latest handshake: 39 seconds ago
 transfer: 229.63 MiB received, 6.00 MiB sent
____________________________________________________________________________________

다음으로 그림 좌측의 NanoPi 설정을 할 차례이다.

<nanopi r2s plus>

wg genkey | tee ./privatekey | wg pubkey > ./publickey
  => curve25519 keypair를 생성한다.

# ip link add dev wg1 type l2wireguard
=> l2wireguard를 지정해 주어야 ethernet frame을 통째로 tunneling할 수 있다.

wg set wg1 listen-port 51820 private-key ./keys/privatekey peer                           
NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc= allowed-ips 0.0.0.0/0 endpoint 192.168.8.134:51820
 => device 및 peer 설정을 한다. allowed-ips는 반드시 0.0.0.0/0으로 지정한다.

# ip link set dev wg1 address 02:ca:fe:f0:0e:04
  => wg1 interface에 대해 MAC address를  설정한다. 회사마다 고유의 MAC 주소 대역이 있으므로, 이를 활용하도록 하자.

# ip link set wg1 up
 => wg1 interface를 link up 시킨다.

# ifconfig br-lan down
brctl delbr br-lan
  => 기존에 설정되어 있는 br-lan bridge interface를 내린다.

# ifconfig eth1 0.0.0.0
ifconfig wg1 0.0.0.0
  => bridge에 포함시킬 interface의 ip 주소를 없앤다. openwrt의 경우 eth1은 LAN interface임.

brctl addbr br-lan
brctl addif br-lan eth1
# brctl addif br-lan wg1
  => br-lan interface를 새로 생성하고, eth1과 wg1 interface를 bridge에 포함시킨다.

ip address add dev br-lan 192.168.2.1/24
  => 이렇게 설정해 주어야, 원격 dhcp가 정상 동작하게 된다(기존 설정을 유지).

ip link set br-lan up
  => bridge interface를 up 시킨다.

echo 1 > /proc/sys/net/ipv4/conf/br-lan/proxy_arp
  => 이걸 해 주어야, VPP box에서 요청한 arp request에 대한 arp reply를 받을 수 있다.

root@nanobox-r2s-plus:~/workspace/l2_wireguard/vpp# wg show wg1
interface: wg1
 public key: jkOW74X1CRS8fobzmYYPGDkyVhR5rdEa9uh8QA2O/0k=
 private key: (hidden)
 listening port: 51820

peer: NVC/buWHbT9ZU7OgObohA2aX2KtuRUknYTOv5Z7PGAc=
 endpoint: 192.168.8.134:51820
 allowed ips: 0.0.0.0/0
 latest handshake: 1 minute, 29 seconds ago
 transfer: 5.45 MiB received, 232.27 MiB sent

이 상태에서 우측(VPP Box) => 좌측(NanoPi)로 ping을 시도해 보자. OK, 정상 동작한다.


[그림 5.6] VPP쪽 내부망 notebook의 routing table 

[그림 5.7] VPP쪽 내부망 notebook => internet 및 NanoPi 내부망으로의 ping 모습 

이 상태에서 (NanoPi에서) tcpdump로 wireguard packet이 capture되는지를 확인해 본다. 즉, VPP 쪽에서 외부로 나가는 패킷이 모두 NanoPi로 이동 후, 다시 NanoPi의 WAN(eth0) port로 나가는지를 확인한다. OK, 정상이다. Cool~ 😝

root@nanobox-r2s-plus:~/workspace/l2_wireguard/vpp# tcpdump -i eth0
[ 2697.176491] device eth0 entered promiscuous mode
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:22:14.677490 IP 192.168.8.134.51820 > 192.168.8.182.51820: UDP, length 256
17:22:15.584748 IP 192.168.8.182.51820 > 192.168.8.134.51820: UDP, length 32
17:22:15.681564 IP 192.168.8.134.51820 > 192.168.8.182.51820: UDP, length 256
17:22:16.689792 IP 192.168.8.134.51820 > 192.168.8.182.51820: UDP, length 256
17:22:16.839873 IP 192.168.8.134.51820 > 192.168.8.182.51820: UDP, length 112


_____________________________________________________

이상으로 VPP WireGuard, VPP + WireGuard-Go, VPP + L2 WireGuard의 동작을 확인해 보았다. 


To be continued...

_______________________________________________________

WireGuard® is a registered trademark of Jason A. Donenfeld.

May The Source Be With You


6. References
[1] https://archive.fosdem.org/2022/schedule/event/evolution_of_vpp/attachments/slides/5037/export/events/attachments/evolution_of_vpp/slides/5037/IPng_Networks_FOSDEM22.pdf
[2] https://ipng.ch/s/articles/2021/08/12/vpp-1.html
[3] https://ipng.ch/s/articles/2021/08/13/vpp-2.html
[4] https://ipng.ch/s/articles/2021/08/15/vpp-3.html
[5] https://ipng.ch/s/articles/2021/08/25/vpp-4.html
[6] https://github.com/pimvanpelt/vppcfg
  => vpp linux control plane 관련 내용
  => 4 ports intel appliance
[7] Zero Trust - Zero Trust Reference Architecture, Intel
  => ZTNA 관련
[8] https://davidaugustat.com/linux/how-to-compile-linux-kernel-on-ubuntu
[9] https://askubuntu.com/questions/1435591/correct-way-to-build-kernel-with-hardware-support-fix-patches-ubuntu-22-04-lts
[10] https://pak-j.tistory.com/65
  => Ubuntu linux kernel compilation 관련 
[11] https://www.alibaba.com/product-detail/Mini-Computer-Router-Pfsense-intel-Celeron_1600520478252.html?spm=a2700.wholesale.0.0.15612aa8knw7RZ
 => Intel appliance
[12] https://www.intel.com/content/www/us/en/developer/articles/technical/build-a-fast-network-stack-with-vpp-on-an-intel-architecture-server.html
[13] https://bootlin.com/pub/conferences/2018/elc/belloni-switchdev/belloni-switchdev.pdf
[14] And, Google~



Slowboot