Microsoft MVP성태의 닷넷 이야기
Linux: 73. Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트 [링크 복사], [링크+제목 복사],
조회: 7901
글쓴 사람
정성태 (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

비밀번호

댓글 작성자
 




... 31  32  33  34  35  36  37  38  39  [40]  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
12936정성태1/22/202215348.NET Framework: 1138. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 멀티미디어 파일의 메타데이터를 보여주는 예제(metadata.c)파일 다운로드1
12935정성태1/22/202216018.NET Framework: 1137. ffmpeg의 파일 해시 예제(ffhash.c)를 C#으로 포팅파일 다운로드1
12934정성태1/22/202215449오류 유형: 788. Warning C6262 Function uses '65564' bytes of stack: exceeds /analyze:stacksize '16384'. Consider moving some data to heap. [2]
12933정성태1/21/202215933.NET Framework: 1136. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 MP2 오디오 파일 디코딩 예제(decode_audio.c)파일 다운로드1
12932정성태1/20/202217031.NET Framework: 1135. C# - ffmpeg(FFmpeg.AutoGen)로 하드웨어 가속기를 이용한 비디오 디코딩 예제(hw_decode.c) [2]파일 다운로드1
12931정성태1/20/202213552개발 환경 구성: 632. ASP.NET Core 프로젝트를 AKS/k8s에 올리는 과정
12930정성태1/19/202214793개발 환경 구성: 631. AKS/k8s의 Volume에 파일 복사하는 방법
12929정성태1/19/202214751개발 환경 구성: 630. AKS/k8s의 Pod에 Volume 연결하는 방법
12928정성태1/18/202214572개발 환경 구성: 629. AKS/Kubernetes에서 호스팅 중인 pod에 shell(/bin/bash)로 진입하는 방법
12927정성태1/18/202215091개발 환경 구성: 628. AKS 환경에 응용 프로그램 배포 방법
12926정성태1/17/202215020오류 유형: 787. AKS - pod 배포 시 ErrImagePull/ImagePullBackOff 오류
12925정성태1/17/202215668개발 환경 구성: 627. AKS의 준비 단계 - ACR(Azure Container Registry)에 docker 이미지 배포
12924정성태1/15/202217176.NET Framework: 1134. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c) [2]파일 다운로드1
12923정성태1/15/202215961개발 환경 구성: 626. ffmpeg.exe를 사용해 비디오 파일을 MPEG1 포맷으로 변경하는 방법
12922정성태1/14/202214769개발 환경 구성: 625. AKS - Azure Kubernetes Service 생성 및 SLO/SLA 변경 방법
12921정성태1/14/202212524개발 환경 구성: 624. Docker Desktop에서 별도 서버에 설치한 docker registry에 이미지 올리는 방법
12920정성태1/14/202213843오류 유형: 786. Camtasia - An error occurred with the camera: Failed to Add Video Sampler.
12919정성태1/13/202213374Windows: 199. Host Network Service (HNS)에 의해서 점유되는 포트
12918정성태1/13/202213837Linux: 47. WSL - shell script에서 설정한 환경 변수가 스크립트 실행 후 반영되지 않는 문제
12917정성태1/12/202213026오류 유형: 785. C# - The type or namespace name '...' could not be found (are you missing a using directive or an assembly reference?)
12916정성태1/12/202212299오류 유형: 784. TFS - One or more source control bindings for this solution are not valid and are listed below.
12915정성태1/11/202212912오류 유형: 783. Visual Studio - We didn't find any interpreters
12914정성태1/11/202216120VS.NET IDE: 172. 비주얼 스튜디오 2022의 파이선 개발 환경 지원
12913정성태1/11/202216534.NET Framework: 1133. C# - byte * (바이트 포인터)를 FileStream으로 쓰는 방법 [1]
12912정성태1/11/202216524개발 환경 구성: 623. ffmpeg.exe를 사용해 비디오 파일의 이미지를 PGM(Portable Gray Map) 파일 포맷으로 출력하는 방법 [1]
12911정성태1/11/202212998VS.NET IDE: 171. 비주얼 스튜디오 - 더 이상 만들 수 없는 "ASP.NET Core 3.1 Web Application (.NET Framework)" 프로젝트
... 31  32  33  34  35  36  37  38  39  [40]  41  42  43  44  45  ...