Microsoft MVP성태의 닷넷 이야기
Linux: 73. Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트 [링크 복사], [링크+제목 복사],
조회: 7872
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일

(시리즈 글이 6개 있습니다.)
닷넷: 2270. C# - Hyper-V Socket 통신(AF_HYPERV, AF_VSOCK)을 위한 EndPoint 사용자 정의
; https://www.sysnet.pe.kr/2/0/13657

닷넷: 2272. C# - Hyper-V Socket 통신(AF_HYPERV, AF_VSOCK)의 VMID Wildcards 유형
; https://www.sysnet.pe.kr/2/0/13663

Linux: 73. Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트
; https://www.sysnet.pe.kr/2/0/13665

Linux: 74. C++ - Vsock 예제 (Hyper-V Socket 연동)
; https://www.sysnet.pe.kr/2/0/13666

닷넷: 2273. C# - 리눅스 환경에서의 Hyper-V Socket 연동 (AF_VSOCK)
; https://www.sysnet.pe.kr/2/0/13667

개발 환경 구성: 721. WSL 2에서의 Hyper-V Socket 연동
; https://www.sysnet.pe.kr/2/0/13713




Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트

vsock을 지원하는 socat(SO cket CAT)은 1.7.4 버전부터인데요, (따라서 이것을 테스트하려면 Ubuntu의 경우 22.04 이상이 필요합니다.)

$ sudo apt install socat

자, 그럼 이걸로 Hyper-V 호스트와 리눅스 VM 간의 통신을 테스트해 볼 텐데요, 우선 호스트 측의 윈도우 프로그램은 지난번에 만들어 둔 C# 응용 프로그램으로 대체하겠습니다.

하지만, 그 예제를 그대로 사용할 수는 없고 한 가지 변경을 해야 하는데요, 바로 Service ID를 리눅스 vsock과 호환하도록 맞춰주어야 합니다. 왜냐하면, vsock의 sockaddr 구조체는,

// 버전에 따라 필드의 차이는 있지만 전체적으로 16바이트의 크기는 동일합니다.

struct sockaddr_vm {
	__kernel_sa_family_t svm_family;
	unsigned short svm_reserved1;
	unsigned int svm_port;
	unsigned int svm_cid;
	__u8 svm_flags;
	unsigned char svm_zero[sizeof(struct sockaddr) -
			       sizeof(sa_family_t) -
			       sizeof(unsigned short) -
			       sizeof(unsigned int) -
			       sizeof(unsigned int) -
			       sizeof(__u8)];
};

Guid를 사용하는 윈도우(Hyper-V Socket)와 달리 "unsigned int" 타입의 svm_cid, svm_port를 쓰기 때문입니다. 이러한 차이점을 메우기 위해, 윈도우 측에서는 vsock과 호환하기 위해 특별한 GUID를 소개하고 있습니다.

// Hyper-V Socket Linux guest VSOCK template GUID

struct __declspec(uuid("00000000-facb-11e6-bd58-64006a7986d3")) VSockTemplate{};

 /*
  * GUID example = __uuidof(VSockTemplate);
  * example.Data1 = 2761; // 0x00000AC9
  */

즉, "00000000-facb-11e6-bd58-64006a7986d3" 값을 써야 하고, 앞 부분의 "00000000" 측에 svm_port에 해당하는 값을 16진수로 쓰는 식입니다. 가령, 19000 포트를 쓰고 싶다면 그것의 16진수 값인 0x4a38을 적용해 "00004A38-facb-11e6-bd58-64006a7986d3" 값으로 해야 하는 것입니다.

마지막으로, 저 값을 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices" 하위에 등록하는 것을 잊지 마시고.




실습을 위해, 이제 지난번 소스코드에서 GcsGuid 값만 바꿔주고,

// 19000번 포트를 사용한다고 가정

public static readonly Guid GcsGuid = new Guid("00004A38-facb-11e6-bd58-64006a7986d3");

(레지스트리 등록 잊지 마시고) 빌드 후 서버 모드로 실행해 둔 후,

ConsoleApp1.exe /server any

Hyper-V에 설치한 Ubuntu 22.04 VM에서 socat을 이용해 다음과 같이 테스트할 수 있습니다.

// socat 실행 후, "test" 입력하고 enter 키를 누르면 ConsoleApp1.exe 측에서 반환하는 "Hello: test"가 출력됩니다.

$ socat - VSOCK-CONNECT:2:19000
test
Hello: test
$

VSOCK-CONNECT 인자와 함께 "2:19000" 값을 주었는데요, 여기서 2는 VMADDR_CID_HOST로 정의된 상수입니다.

/* Use this as the destination CID in an address when referring to the host
 * (any process other than the hypervisor).  VMCI relies on it being 2, but
 * this would be useful for other transports too.
 */

#define VMADDR_CID_HOST 2

즉, VM에서 호스트 측으로 연결 시 svm_cid 필드에 설정해야 하는 값으로, Hyper-V Socket의 "HV_GUID_PARENT(a42e7cda-d03f-480c-9cc2-a4de20abb878)"에 해당한다고 보면 됩니다.




리눅스 측의 vsock 연결을 클라이언트로 했으니 이제 반대로 서버로써도 테스트해야겠죠? ^^

이를 위해 socat을 서버 모드로 실행해 두는데요,

$ socat - VSOCK-LISTEN:19000

역으로 Hyper-V 호스트 측에서는 (전과 다름없이) VM ID를 통해 접속하면 됩니다.

// socat을 실행한 Linux VM의 VM ID가 "f952c5ef-ea6c-4c83-b52c-38f31cf68b61"인 경우,

ConsoleApp1.exe /client f952c5ef-ea6c-4c83-b52c-38f31cf68b61

ConsoleApp1.exe 코드에서는 어차피 Service ID를 "00004A38-facb-11e6-bd58-64006a7986d3"로 사용해 19000 포트로 연결할 것이므로, 결국 필요한 것은 VM ID뿐입니다.

참고로, 윈도우의 경우 Server 측 바인딩이 HV_GUID_WILDCARD와 HV_GUID_LOOPBACK이 가능했는데요, 리눅스도 그와 유사하게 VMADDR_CID_ANY와 (한때 VMADDR_CID_RESERVED였던) VMADDR_CID_LOCAL이 있습니다.

/* The vSocket equivalent of INADDR_ANY.  This works for the svm_cid field of
 * sockaddr_vm and indicates the context ID of the current endpoint.
 */
#define VMADDR_CID_ANY -1U

/* Use this as the destination CID in an address when referring to the
 * local communication (loopback).
 * (This was VMADDR_CID_RESERVED, but even VMCI doesn't use it anymore,
 * it was a legacy value from an older release).
 */
#define VMADDR_CID_LOCAL 1

socat이 어떤 값과 바인딩하는지는 모르겠지만, 위의 설명만 봐서는 VMADDR_CID_ANY인 듯합니다. 이런 경우, 역시나 윈도우에서처럼 같은 VM 내에서는 VMADDR_CID_LOCAL로 연결할 수 있는데요, 따라서 같은 VM 내에서 2개의 터미널을 열어두고 각각 다음과 같이 테스트하면 서로 연결이 됩니다.

// 리눅스 VM의 터미널 A

$ socat - VSOCK-LISTEN:19000

// 리눅스 VM의 터미널 B

$ socat - VSOCK-CONNECT:1:19000

"1:19000"에서 "1"은 VMADDR_CID_LOCAL 값에 해당합니다. 그런 의미에서 본다면 VMADDR_CID_ANY와 VMADDR_CID_LOCAL은 Hyper-V Socket으로 매핑한다면 각각 HV_GUID_WILDCARD와 HV_GUID_LOOPBACK이 됩니다.




참고로, Linux 측에서 vsock 지원 여부를 모듈 열거를 통해 확인할 수 있다고 합니다.

$ lsmod | grep vsock
vsock_loopback                      12288   0
vmw_vsock_virtio_transport_common   61440   1 vsock_loopback
vmw_vsock_vmci_transport            45056   0
vsock                               61440   4 vmw_vsock_virtio_transport_common,vsock_loopback,hv_sock,vmw_vsock_vmci_transport
vmw_vmci                            106496  1 vmw_vsock_vmci_transport

또한, 윈도우의 Hyper-V에서 호스팅하는 것이 아닌, Linux를 호스트로 Linux VM을 돌리는 경우에는 svm_cid 값을 VM 시작 시의 인자로 전달해야 합니다. 가령 qemu의 경우,

// https://github.com/stefano-garzarella/socat-vsock/blob/be46eaf169eea1c63b3d90772610a8733a346e30/EXAMPLES#L236

//////////////////////////////////////////////////////////////////////////////
// VSOCK
# start a linux VM with cid=21
#    qemu-system-x86_64 -m 1G -smp 2 -cpu host -M accel=kvm \
#     -drive if=virtio,file=/path/to/fedora.img,format=qcow2  \
#     -device vhost-vsock-pci,guest-cid=21

# guest listens on port 1234 and host connects to it
guest$ socat - VSOCK-LISTEN:1234
host$ socat - VSOCK-CONNECT:21:1234

# host (well know CID_HOST = 2) listens on port 4321 and guest connects to it
host$ socat - VSOCK-LISTEN:4321
guest$ socat - VSOCK-CONNECT:2:4321

# ssh over vsock (guest-cid = 21)
guest$ socat VSOCK-LISTEN:22,reuseaddr,fork TCP:localhost:22
host$ socat TCP4-LISTEN:22222,reuseaddr,fork VSOCK-CONNECT:21:22
host$ ssh -p 22222 user@localhost

guest-cid 값을 통해 CID를 지정할 수 있습니다.

마지막으로, vsock이 지원되면 /dev/vsock 파일이 열거되는데요,

$ ls /dev/vsock -l
crw-rw-rw- 1 root root 10, 118  7월  2 09:33 /dev/vsock

이 파일에 대해 IOCTL_VM_SOCKETS_GET_LOCAL_CID 명령을 보내면 (qemu의 경우 guest-cid 값으로 전달한) CID 값을 얻는 것이 가능합니다.

#!/usr/bin/env python3
import socket
import struct
import fcntl

with open("/dev/vsock", "rb") as fd:
    r = fcntl.ioctl(fd, socket.IOCTL_VM_SOCKETS_GET_LOCAL_CID, "    ")
    cid = struct.unpack("I", r)[0]

    print("Local CID: {}".format(cid))

# https://gist.github.com/stefano-garzarella/b4971c2bed3c632b48c5e2a823c1cbe1

(qemu 등으로 guest-cid를 설정하지 않은) VM 또는 호스트의 경우에는 CID 값이 4294967295로 나옵니다.




Ubuntu 20.04에서 기본 설치하는 socat은,

$ apt show socat
Package: socat
Version: 1.7.3.3-2
...[생략]...

$ sudo apt install socat

1.7.3 버전인데요, vsock을 지원하지 않습니다.

SOCAT now supports AF_VSOCK
; https://stefano-garzarella.github.io/posts/2021-01-22-socat-vsock/

22.04 우분투 repo의 deb 파일을 직접 다운로드해,

socat_1.7.4.1-3ubuntu4_amd64.deb
; https://ubuntu.pkgs.org/22.04/ubuntu-main-amd64/socat_1.7.4.1-3ubuntu4_amd64.deb.html
; http://archive.ubuntu.com/ubuntu/pool/main/s/socat/socat_1.7.4.1-3ubuntu4_amd64.deb

설치하면,

$ wget http://archive.ubuntu.com/ubuntu/pool/main/s/socat/socat_1.7.4.1-3ubuntu4_amd64.deb
$ sudo apt install ./socat_1.7.4.1-3ubuntu4_amd64.deb

이런 오류가 발생할 것입니다.

$ sudo apt install ./socat_1.7.4.1-3ubuntu4_amd64.deb
...[생략]...

The following packages have unmet dependencies:
 socat : Depends: libc6 (>= 2.34) but 2.31-0ubuntu9.16 is to be installed
         Depends: libssl3 (>= 3.0.0~~alpha1) but it is not installable
E: Unable to correct problems, you have held broken packages.

아마도 저게 동작하려면, socat 빌드를 glibc 2.34 버전을 대상으로, libssl3도 함께 빌드해 링크해야 할 것입니다. 저야 리눅스 초보자라... ^^;




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/6/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 16  17  18  19  20  21  22  23  24  [25]  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13312정성태4/8/202311630Windows: 244. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (개선된 버전)파일 다운로드1
13311정성태4/7/202312850C/C++: 163. Visual Studio 2022 - DirectShow 예제 컴파일(WAV Dest)
13310정성태4/6/202311974C/C++: 162. Visual Studio - /NODEFAULTLIB 옵션 설정 후 수동으로 추가해야 할 library
13309정성태4/5/202312440.NET Framework: 2107. .NET 6+ FileStream의 구조 변화
13308정성태4/4/202312482스크립트: 47. 파이썬의 time.time() 실숫값을 GoLang / C#에서 사용하는 방법 [1]
13307정성태4/4/202311613.NET Framework: 2106. C# - .NET Core/5+ 환경의 Windows Forms 응용 프로그램에서 HINSTANCE 구하는 방법
13306정성태4/3/202311600Windows: 243. Win32 - 윈도우(cbWndExtra) 및 윈도우 클래스(cbClsExtra) 저장소 사용 방법
13305정성태4/1/202312881Windows: 242. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (쉬운 버전) [1]파일 다운로드1
13304정성태3/31/202313226VS.NET IDE: 181. Visual Studio - C/C++ 프로젝트에 application manifest 적용하는 방법
13303정성태3/30/202311469Windows: 241. 환경 변수 %PATH%에 DLL을 찾는 규칙
13302정성태3/30/202312189Windows: 240. RDP 환경에서 바뀌는 %TEMP% 디렉터리 경로
13301정성태3/29/202312761Windows: 239. C/C++ - Windows 10 Version 1607부터 지원하는 /DEPENDENTLOADFLAG 옵션 [1]파일 다운로드1
13300정성태3/28/202311910Windows: 238. Win32 - Modal UI 창에 올바른 Owner(HWND)를 설정해야 하는 이유
13299정성태3/27/202311715Windows: 237. Win32 - 모든 메시지 루프를 탈출하는 WM_QUIT 메시지
13298정성태3/27/202311691Windows: 236. Win32 - MessageBeep 소리가 안 들린다면?
13297정성태3/26/202313151Windows: 235. Win32 - Code Modal과 UI Modal
13296정성태3/25/202312232Windows: 234. IsDialogMessage와 협업하는 WM_GETDLGCODE Win32 메시지 [1]파일 다운로드1
13295정성태3/24/202312391Windows: 233. Win32 - modeless 대화창을 modal처럼 동작하게 만드는 방법파일 다운로드1
13294정성태3/22/202312359.NET Framework: 2105. LargeAddressAware 옵션이 적용된 닷넷 32비트 프로세스의 가용 메모리 - 두 번째
13293정성태3/22/202311767오류 유형: 853. dumpbin - warning LNK4048: Invalid format file; ignored
13292정성태3/21/202312511Windows: 232. C/C++ - 일반 창에도 사용 가능한 IsDialogMessage파일 다운로드1
13291정성태3/20/202312754.NET Framework: 2104. C# Windows Forms - WndProc 재정의와 IMessageFilter 사용 시의 차이점
13290정성태3/19/202312469.NET Framework: 2103. C# - 윈도우에서 기본 제공하는 FindText 대화창 사용법파일 다운로드1
13289정성태3/18/202311423Windows: 231. Win32 - 대화창 템플릿의 2진 리소스를 읽어들여 자식 윈도우를 생성하는 방법파일 다운로드1
13288정성태3/17/202311619Windows: 230. Win32 - 대화창의 DLU 단위를 pixel로 변경하는 방법파일 다운로드1
13287정성태3/16/202311608Windows: 229. Win32 - 대화창 템플릿의 2진 리소스를 읽어들여 윈도우를 직접 띄우는 방법파일 다운로드1
... 16  17  18  19  20  21  22  23  24  [25]  26  27  28  29  30  ...