RHEL6 기반 KVM 가상화 시스템 구축하기 – PCI PassThrough 포함

RHEL6 기반 KVM 가상화 시스템 구축하기

작성자 : 서진우 ( alang@clunix.com )
작성일 : 2011년 4월 11일

1. Kernel-based Virtual Machine (KVM) 이란

가상화란 기술에는 많은 방식이 있다. 근래 가상화 기술에 가장 많이 나오는 용어가
full virtualization(전가상화) 와 para-virtualization(반가상화) 이다.

full virtualization 은 물리적인 하드웨어 전체를 hypervisor단에서 가상화시켜
가상머신(GuestOS)에 제공하는 환경이다. 전통적으로 사용되던 하드웨어 에뮬레이터
가상화 방식에 비해 빠르지만, 모든 처리를 hypervisor에서 중계함으로 실제 성능
보다는 낮다. (대표적인 솔루션이 vmware 이다.)

para-virtualization 는 hypervisor를 통해 물리적인 하드웨어에 접근하는 형태는
전가상화 방식과 유사하지만, GuestOS가 hypervisor에 맞게 최적화되어 제공함으로
전가상화에 비해 보다 더 높은 성능을 발휘한다. (대표적인 솔루션이 Xen이다)

KVM의 경우 전가상화의 성능 저하 및 기타 문제를 해결하기 위한 하나의 해법으로
나온 기술이라 볼수 있다.

KVM은 리눅스 커널을 커널 모듈을 이용하여 hypervisor로 전환한다는 점에서
전가상화 방식이라 볼수 있다. 즉 hypervisor가 물리적인 하드웨어 전체에
직접 접근하지만, 이 hypervisor 자체가 실제 리눅스 커널의  모듈 형태로 제공
한다는 점에서 전 가상화에 비해 나은 성능과 가상화 관리 환경을 제공하게
된다.

본 문서는 KVM을 이용하여 가상화 시스템 환경을 구축하고, 운영에 필요한
관리 방법에 대해 알아보도록 한다.

가상화에 대한 자세한 부가 설명은 아래 자료를 참고하길 바란다.

http://blog.syszone.co.kr/2974
http://blog.syszone.co.kr/2884
http://blog.syszone.co.kr/category/85

2. KVM 설치 전 기본 환경 준비

2.1 가상화 확장 기능 확인

KVM을 사용하기 위해서는 장착된 프로세서에서 Intel VT나 AMD-V 기능이 포함되어
있어야 한다. 이를 확인 하는 방법은 아래와 같다.

– Intel CPU

# cat /proc/cpuinfo | grep vmx

– AMD CPU

# cat /proc/cpuinfo | grep svm

cpuinfo 의 flags 정보에 vmx or svm 이 포함되어 있다면 해당 시스템에 KVM을 이용하여
가상화 환경 구현이 가능하다.

2.2 Bridge 네트워크 환경 구성

KVM을 통해 기본적으로 가상화 운영체제 (Guest OS)를 설치하면 NAT 기반으로 사설 네트워크
환경에서 동작하게 된다. Guest OS를 실제 네트워크 환경에 포함시키기 위해서는 host OS의
네트워크 환경이 bridge 기반으로 구성될 필요가 있다.

일단 bridge 구성에 필요한 bridge-utils 패키지를 설치 한다.

# yum install bridge-utils

host OS 네트워크 환경을 bridge 구성으로 전환한다.

# chkconfig –level 345 NetworkManager off
# /etc/rc.d/init.d/NetworkManager stop
# /etc/rc.d/init.d/network restart

# cd /etc/sysconfig/network-scripts/
# vi ifcfg-eth0
—————————————————————————————
DEVICE=”eth0″
HWADDR=”00:25:90:22:3B:2E”
BOOTPROT=static
ONBOOT=”yes”
TYPE=Ethernet
IPV6INIT=no
USERCTL=no
BRIDGE=br0
—————————————————————————————

# vi ifcfg-br0
—————————————————————————————
DEVICE=br0
TYPE=Bridge
BOOTPROTO=static
GATEWAY=192.168.123.254
IPADDR=192.168.123.40
NETMASK=255.255.255.0
ONBOOT=yes
—————————————————————————————

# vi ifcfg-eth1
—————————————————————————————
DEVICE=”eth1″
HWADDR=”00:25:90:22:3B:2F”
BOOTPROT=static
ONBOOT=”yes”
TYPE=Ethernet
IPV6INIT=no
USERCTL=no
BRIDGE=br1
—————————————————————————————

# vi ifcfg-br1
—————————————————————————————
DEVICE=br1
TYPE=Bridge
BOOTPROTO=static
IPADDR=192.168.123.60
NETMASK=255.255.255.0
ONBOOT=yes
—————————————————————————————

# /etc/rc.d/init.d/network restart

# ifconfig
—————————————————————————————
br0       Link encap:Ethernet  HWaddr 00:25:90:22:3B:2E 
          inet addr:192.168.123.40  Bcast:192.168.123.255  Mask:255.255.255.0
          inet6 addr: fe80::225:90ff:fe22:3b2e/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:39 errors:0 dropped:0 overruns:0 frame:0
          TX packets:58 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3238 (3.1 KiB)  TX bytes:11585 (11.3 KiB)

br1       Link encap:Ethernet  HWaddr 00:25:90:22:3B:2F 
          inet addr:192.168.123.60  Bcast:192.168.123.255  Mask:255.255.255.0
          inet6 addr: fe80::225:90ff:fe22:3b2f/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:27 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 b)  TX bytes:4943 (4.8 KiB)

eth0      Link encap:Ethernet  HWaddr 00:25:90:22:3B:2E 
          inet6 addr: fe80::225:90ff:fe22:3b2e/64 Scope:Link
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          RX packets:10407645 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11541935 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:9816320504 (9.1 GiB)  TX bytes:13960651544 (13.0 GiB)
          Memory:faee0000-faf00000

eth1      Link encap:Ethernet  HWaddr 00:25:90:22:3B:2F 
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)
          Memory:fafe0000-fb000000

lo        Link encap:Local Loopback 
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1460131 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1460131 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3566989451 (3.3 GiB)  TX bytes:3566989451 (3.3 GiB)
———————————————————————————

위와 같이 bridge device를 여러개로 구성한 이유는 여러대의 가상머신이 동시에 운영될때
가상머신의 네트워크 장치를 각각 여러개의 물리적인 네트워크 장치로 분산시키기 위함이다.

# /etc/rc.d/init.d/libvirtd restart

3. KVM 환경 구축 하기

3.1 RHEL6 Host OS 환경

KVM 가상화를 계획한 상태에서 RHEL6를 설치하는 거라면 패키지 그룹 중 아래 그룹에
소속된 모든 패키지를 설치한다.

@virtualization
@virtualization-client
@virtualization-platform
@virtualization-tools

만일 Host OS로 RHEL6를  설치 시 가상화 계획이 없다가, 이후 KVM을 통해 가상화를 원할
경우 RHEL6 RPM 중 qemu, kvm, spice, virt keyword 가 들어 있는 모든 패키지를 설치한다.

qemu-kvm-0.12.1.2-2.113.el6.x86_64
qemu-kvm-tools-0.12.1.2-2.113.el6.x86_64
cairo-spice-1.8.7.1-4.el6.x86_64
spice-server-0.4.2-15.el6.x86_64
spice-client-0.4.2-18.el6.x86_64
pixman-spice-0.13.3-5.el6.x86_64
ffmpeg-spice-libs-0.4.9-0.15.5spice.20080908.el6.x86_64
libvirt-cim-0.5.8-3.el6.x86_64
virt-manager-0.8.7-1.noarch
virt-viewer-0.2.1-2.el6.x86_64
libvirt-java-0.4.5-2.el6.noarch
fence-virtd-serial-0.2.1-5.el6.x86_64
virt-top-1.0.4-3.1.el6.x86_64
libvirt-0.8.1-27.el6.x86_64
libvirt-devel-0.8.1-27.el6.x86_64
fence-virtd-libvirt-0.2.1-5.el6.x86_64
python-virtinst-0.500.3-7.el6.noarch
libvirt-java-devel-0.4.5-2.el6.noarch
libvirt-client-0.8.1-27.el6.x86_64
libvirt-python-0.8.1-27.el6.x86_64
fence-virtd-multicast-0.2.1-5.el6.x86_64
virt-v2v-0.6.2-4.el6.x86_64
libvirt-qpid-0.2.22-3.el6.x86_64
fence-virtd-0.2.1-5.el6.x86_64
qemu-img-0.12.1.2-2.113.el6.x86_64
gpxe-roms-qemu-0.9.7-6.3.el6.noarch
libguestfs-java-1.2.7-1.24.el6.x86_64
libguestfs-tools-1.2.7-1.24.el6.x86_64
perl-libguestfs-1.2.7-1.24.el6.x86_64
libguestfs-mount-1.2.7-1.24.el6.x86_64
libguestfs-1.2.7-1.24.el6.x86_64

3.2 RHEL5.4+ Host OS 환경

Host OS 가 RHEL5.4+ 버전일 경우의 패키지 구성은 아래와 같다.

kmod-kvm : kvm kernel module(s)
kvm : Kernel-based Virtual Machine
kvm-qemu-img : Qemu disk image utility
kvm-tools : KVM debugging and diagnostics tools
python-virtinst : Python modules and utilities for installing virtual machines
virt-manager : Virtual Machine Manager (GUI app, to install and configure VMs)
virt-viewer: Virtual Machine Viewer (another lightweight app to view VM console and/or install VMs)
bridge-utils : Utilities for configuring the Linux Ethernet bridge (this is recommended for KVM networking)

#  yum groupinstall KVM

3.3 KVM 관련 주요 디렉토리 구성

패키지 설치가 완료된 상태의  KVM 가상화 관련 디렉토리 구조는 아래와 같다.

/etc/libvirt/
– 기본 설정 디렉토리

/etc/libvirt/qemu/
– 가상머신(VM)의 상세 설정 파일이 존재하는 디렉토리
xml 파일 형태로 존재하며, virt-manger 혹은 virsh edit <vm_name> 명령으로 수정이
가능하다.

/etc/libvirt/qemu/networks/
– KVM 가상 머신의 네트워크 환경 설정 디렉토리 .
기본적으로 NAT로 구성되며, 성능 향상을 위해서는 bridge 기반으로 재구성해야함.

/etc/libvirt/qemu/networks/default.xml
– The default NAT configuration used by NAT device virbr0.

/var/log/libvirt/
– The default log file directory. All VM specific logs files are stored here.

/etc/libvirt/libvirtd.conf
– Master libvirtd configuration file.

/etc/libvirt/qemu.conf
– Master configuration file for the QEMU driver.

/var/lib/libvrit/images
– 기본 VM 이미지 저장소. virt-manger를 통해 외부 저장소를 등록할 수 있다.

3.4 virt-manager 에 spice 기능 추가 하기

spice protocol을 이용하여 kvm으로 구성된 VM 의 graphic 관련 성능을 향상 시킬수 있다.
RHEL6 의 기본 설치되는 virt-manager 의 경우 spice의 기능 항목이 포함되지 않았다.
spice 기능이 포함된  virt-manager를 이용하기 위해서는 아래 두가지 추가 작업을 해야한다.

– virt-manager version upgrade

RHEL6 를 기본 설치 하면 virt-manager-0.8.4-8 가 설치된다. spice가 추가된 virt-manager
를 이용하기 위해서는 virt-manager-0.8.7 이상 버전을 사용해야 한다.
그리고 python-virtinst 역시 0.500.6 버전 이상을 설치 해야 한다.

wget http://virt-manager.et.redhat.com/download/sources/virtinst/virtinst-0.500.6.tar.gz
wget http://virt-manager.et.redhat.com/download/sources/virt-manager/virt-manager-0.8.7.tar.gz

# tar xzvf virtinst-0.500.6.tar.gz
# cd virtinst-0.500.6
# python setup.py install

# tar xzvf virt-manager-0.8.7.tar.gz
# cd virt-manager-0.8.7
# ./configure
# make rpm
# rpm -Uvh /root/rpmbuild/RPMS/noarch/virt-manager-0.8.7-1.el6.noarch.rpm

4.Guest OS 설치하기

Guest OS를 설치하는 방법은 크게 virt-manager를 이용한 방법과 command 를 이용한
방법 두가지가 있다.

Guest OS 설치 시 사용할 수 있는 명령은 virt-install 과 qemu-kvm 이다.

# virt-install –connect qemu:///system -n <vm_name> -r <mem_size> -vcpu <core_num> -f <vmimage_path> -s <disk_size> -c <install_media_path> –vnc –os-type=windows –accelerate –hvm

아래는 virt-install 명령을 이용한 몇가지 응용 설치 명령 예제이다.

– 기본 설치 방법

# virt-install –connect qemu:///system -n desktop_xp1 -r 2048 –vcpu 2 -f /home/vdimage/winxp01.qcow2 -s 40 -c /home/WindowsXP3/WindowsXP3.iso –vnc –os-type=windows –accelerate –hvm

– nfs 저장소를 이용한 원격 설치 방법

# virt-install –connect qemu:///system -n rhel5 -r 2048 –vcpus=2 -f /vos/HardDisks/rhel5.qcow2 -s 20 –vnc –os-type=linux –accelerate –hvm –location=nfs:192.168.123.2:/data1/os/rhes5/rhel5.5 –extra-args=”linux askmethod”

– Guest OS 네트워크 환경을 bridge 장치로 구성 (Linux)

# virt-install –connect qemu:///system -n rhel5 -r 2048 -c rhel5_5.iso –vcpus=2 -f /vos/HardDisks/rhel5.qcow2 -s 20 –vnc –os-type=linux –accelerate –network bridge:br0 –hvm

– Guest OS 네트워크 환경을 bridge 장치로 구성 (windows)
 
# virt-install –connect qemu:///system -n win7 -r 2048 -f /vos/HardDisks/win7.qcow2 -s 20 -c GRMCkPRFRER_KO_DVD.iso –vnc –os-type=windows –accelerate –network bridge:br0 –hvm

– Display 를 spice, vga를 qxl 로 직접 구성 (windows)

# virt-install –connect qemu:///system -n desktop_xp0 -r 2048 –vcpu 2 -f /home/vdimage/winxp00.qcow2 -s 40 -c /home/WindowsXP3/WindowsXP3.iso –os-type=windows –accelerate –hvm –network bridge=br0,model=virtio  –graphics=spice –video=qxl

# /usr/libexec/spicec -h localhost -p 5901

5. VM 주요 관리 방법

5.1 Guest OS 성능 개선 방법

– video driver 변경 (QXL)

# virsh edit <vm_name>
——————————————————————————————
.
    <video>
      <model type=’vga’ vram=’9216′ heads=’1’/>
      <address type=’pci’ domain=’0x0000′ bus=’0x00′ slot=’0x02′ function=’0x0’/>
    </video>
.
을 아래와 같이 변경

    <video>
      <model type=’qxl’ vram=’33000′ heads=’1’/>
      <address type=’pci’ domain=’0x0000′ bus=’0x00′ slot=’0x02′ function=’0x0’/>
    </video>

——————————————————————————————-

windows guest 의 경우 http://www.spice-space.org/download 에서 qxl drvier 다운로드 후,
driver 업데이트를 진행한다.

# wget http://www.spice-space.org/download/binaries/qxl-win32-0.6.1.zip

– display 접속 방식 변경 (Spice)

# virsh edit <vm_name>
——————————————————————————————-
.
   <graphics type=’vnc’ port=’-1′ autoport=’yes’ keymap=’en-us’/>

을 아래로 변경 .

    <graphics type=’spice’ autoport=’yes’ listen=’0.0.0.0’/>
.
——————————————————————————————

– disk driver 변경 (virtio -> virtual scsi controller, cache mode -> writeback )

# virsh edit <vm_name>
————————————————————————————–
.
    <disk type=’file’ device=’disk’>
      <driver name=’qemu’ type=’raw’ cache=’none’/>
      <source file=’/home/vdimage/winxp03.qcow2’/>
      <target dev=’hda’ bus=’ide’/>
      <address type=’drive’ controller=’0′ bus=’0′ unit=’0’/>
    </disk>

을 아래로 변경

    <disk type=’file’ device=’disk’>
      <driver name=’qemu’ type=’raw’ cache=’writeback’/>
      <source file=’/home/vdimage/winxp01.qcow2’/>
      <target dev=’hda’ bus=’virtio’/>
      <address type=’drive’ controller=’0′ bus=’0′ unit=’0’/>
    </disk>
.
—————————————————————————————-

단 guest OS 가 windows 일 경우에는 virtio 상태로 운영체제를 설치할 수 없기에
IDE로 설치한 후, 별도의 non-system type의 disk 를 virtio 방식으로 추가를 한다.
그런 후 windows vm 을 부팅한후, virtio driver를 업데이트 한다.
reboot 후 해당 디스크를 포맷하여, VM OS 상에 virtio Disk 를 완전히 인식 가능하게
한다. 다시 VM을 종료한 후, virt-manger 상에서 추가된 virtio disk 를 제거하고,
운영체제가 설치된 IDE Disk1 의 Disk bus 설정을 IDE 에서 Virtio 로 변경한다.
 
다시 VM OS를 실행하고, 정상적으로 부팅하는지를 확인한다.

– network 구성 변경 (bridge, virtio)

# virsh edit <vm_name>
——————————————————————————————
.
    <interface type=’network’>
      <mac address=’52:54:00:41:b0:29’/>
      <source network=’default’/>
      <address type=’pci’ domain=’0x0000′ bus=’0x00′ slot=’0x03′ function=’0x0’/>
    </interface>
.
을 아래와 같이 변경

    <interface type=’bridge’>
      <mac address=’52:54:00:41:b0:29’/>
      <source bridge=’br0’/>
      <target dev=’vnet0’/>
      <model type=’virtio’/>
      <address type=’pci’ domain=’0x0000′ bus=’0x00′ slot=’0x03′ function=’0x0’/>
    </interface>

—————————————————————————————–

virtio network driver는 아래에서 구할 수 있다.

wget http://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/virtio-win-1.1.16.iso

지금까지의 vm의 설정 변경은 위의 방식과 같이 command 상에서도 가능하고, virt-manger GUI
환경에서도 수정이 가능하다.

5.2 KVM 주요 관리 팁

– Guest OS 의 clone OS 생성하기

# virt-clone -o <원본VM_name> -n <복제VM_name> -f <복제VM image file>

# virt-clone -o desktop_xp3 -n desktop_xp2 -f winxp02.qcow2

– Default Virtaul Netwrok 비활성화 하기

기본 NAT 구성을 하지 않을 경우 virbr0를 비활성화 시키는 방법이다.

# virsh net-autostart default –disable
# virsh net-destroy default

– qemu 명령을 통해 직접 VM 실행 방법

KVM에서 VM을 일관성 있게 관리하기 위해 VM 실행을 가급적 virt-manager 혹은 virsh 명령을
통해 실행하고 관리한다. 하지만 이를 위해서는 VM 이미지 파일 이외의 KVM VM 관련 설정이
모두 존재해 한다. 만일 단순히 VM 이미지 파일만 존재할때, 이를 실행하기 위해서는 qemu
명령을 직접 수행하여 VM을 실행할 수 있다.

RHEL6

# /usr/libexec/qemu-kvm -m 2048 -smp 2 -name desktop_xp4 -drive file=/home/vdimage/winxp01-clone.qcow2 -vga qxl -spice port=5900,disable-ticketing

RHEL5

# /usr/libexec/qemu-kvm -m 2048 -smp 2 -name windows_xp  -drive file=/xfs/vfs/winxp00.qcow2 -qxl 1,ram=256 -spice port=5900,disable-ticketing

KVM 을 RHEL6 (virt-manager 0.8)에서 구성한 경우라면, virt-manager를 실행하고 “기존이미지 불러오기”
를 통해 기존 이미지를 쉽게 KVM에 등록하고 사용이 가능하다. 단 RHEL5 (virt-manager 0.6) 에서는
기존 이미지를 바로 불러서 virt-manager 에 등록하는 기능이 없다. virt-manager에 기존 이미지를 등록
하기 위해서는 virsh 명령을 이용해야 한다.

– 기존 VM 이미지 파일을 이용하여 KVM 에 VM 등록하기

RHEL5 기반의 KVM 의 경우 VM 이미지 파일만으로 virt-manager 에 기존 VM을 등록하기 어렵다.
이때 virsh 명령을 이용하여 몇가지 수동적인 작업을 해 줘야 한다.

1.  /etc/libvirt/qemu 에 해당 이미지의 기존 xml 설정 파일이나 표준 xml 샘플 파일을 복사해 둔다.
2. uuidgen 명령을 통해 새로운 VM uid 를 생성하고, 이를 xml 파일에 적용한다.

# uuidgen
63369b94-61bd-4070-b31e-ee1499a0c667

# vi <vm_configfile.xml>
————————————————————————-
<domain type=’kvm’>
  <name>windows_xp00</name> -> vm_name 수정
  <uuid>63369b94-61bd-4070-b31e-ee1499a0c667</uuid> -> uuidgen 으로 받은 uid 적용
.

3. virsh define 명령으로 새로운 xml 설정 파일을 시스템에 반영

# virsh define windows_xp00.xml

4. virsh edit 명령으로 수동 등록한 xml 파일의 내용을 현재 시스템 상태에 맞게 변경

# virsh edit windows_xp00
————————————————————————–
<domain type=’kvm’>
  <name>windows_xp00</name>
  <uuid>63369b94-61bd-4070-b31e-ee1499a0c667</uuid>
  <memory>2097152</memory> -> 메모리 지정
  <currentMemory>2097152</currentMemory>
.
  <os>
    <type arch=’x86_64′ machine=’rhel5.5.0′>hvm</type> -> 운영체제 버전에 맞게 수정
    <boot dev=’hd’/>
  </os>
.

    <disk type=’file’ device=’disk’>
      <driver name=’qemu’ type=’raw’ cache=’none’/>
      <source file=’/xfs/vfs/winxp00.qcow2’/> -> 기존 이미지 파일 위치 지정
      <target dev=’hda’ bus=’ide’/>
      <address type=’drive’ controller=’0′ bus=’0′ unit=’0’/>
    </disk>

.
—————————————————————————-

가급적 xml 파일은 가장 기본적인 상태의 시스템 표준 설정을 사용하길 권장한다.
display 설정은 가급적 vnc 기본 상태로 ..

    <graphics type=’vnc’ port=’-1′ autoport=’yes’ keymap=’en-us’/>

vga 설정은 기본 vga로 ..
    <video>
      <model type=’vga’ vram=’9216′ heads=’1’/>
    </video>

5. virsh start <vm_name>

xml 설정이 정상적이라면 virsh start 로 정상적으로 VM 실행이 가능할 것이다.

# virsh start windows_xp00
도메인 windows_xp00가 시작됨

virt-viewer 명령으로 VM의 display 확인.

# virt-viewer windows_xp00

5.3 virsh 명령어를 통한 KVM 관리 방법

– Hypervisor 접속하기

# virsh -c qemu:///system

– 모든 VM 리스트 확인

# virsh list –all
————————————————-
  8 desktop_xp0          실행중
  – desktop_xp1          종료
  – desktop_xp2          종료
  – desktop_xp3          종료
  – desktop_xp4          종료
  – desktop_xp5          종료
  – desktop_xp6          종료
  – RHEL6_00             종료

– 사전에 정의된 VM 실행하기

# virsh start <vm_name>

– 실행 중인 VM 리스트 확인

# virsh list 
 Id 이름                 상태
———————————-
  7 desktop_xp1          실행중
  8 desktop_xp2          실행중
  9 desktop_xp3          실행중
 10 desktop_xp4          실행중

– 실행 중인 VM shutdown

# virsh list
# virsh shutdown <vm_name>
# virsh shutdown desktop_xp1
# virsh shutdown 7

– 실행 중인 VM reboot

# virsh list
# virsh reboot <vm_name>
# virsh reboot desktop_xp4
# virsh reboot 10

– 실행 중인 VM 강제 종료하기

# virsh list
# virsh destroy <vm_name>

– 실행 중인 VM 의 정보 확인

# virsh list
# virsh dominfo <vm_name>

# virsh dominfo desktop_xp4
—————————————————————————-
Id:             10
이름:           desktop_xp4
UUID:           83087882-2ba1-fb27-c11c-3eef6ed8da72
OS 유형:        hvm
상태:           실행중
CPU:            2
CPU 시간:       40.7s
최대 메모리:    2097152 kB
사용된 메모리:  2097152 kB
Persistent:     yes
Autostart:      비활성화됨
모안 모델:      selinux
보안 DOI:       0
보안 레이블:    system_u:system_r:svirt_t:s0:c418,c712 (enforcing)
——————————————————————————

– KVM Hosts machine 정보 확인

# virsh nodeinfo
——————————————————————————
CPU 모델:            x86_64
CPU:                 16
CPU 주파수:          1600 MHz
CPU 소켓:            2
소켓당 코어:         4
코어당 스레드:       2
NUMA cell:           2
메모리 용량:         24599776 kB
——————————————————————————

6. USB Redirector로 원격 USB Device Access 하기

KVM에서 제공하는 VM 시스템에 원격으로 접속하여 가상 데스크탑을 사용하는 방법에
대해 알아 보았다. 이런 환경에서 이슈로 발생할 수 있는 문제가 Client PC에 장착된
USB를 어떻게 VM 머신에서 인식하게 할것인가 이다.

이때 솔루션을 사용할 수 있는 방법이 USB redirector 기술이다.
USB redirector 는 TCP/IP 네트워크를 이용하여 원격에 장착된 USB Device에 접근하는
기술로 다양한 제품이 존재한다. 오픈 소스로 USBIP 란 프로젝트에서 제공하는
기술을 이용해도 되고, 상용으로 알려진 제품을 이용해도 된다.

대부분의 상용 제품의 경우에도 리눅스 환경에서 사용할 경우 Free로 사용할 수 있다.

아래는 http://www.incentivespro.com/ 사이트에서 제공하는 USB Redirector 제품에
대한 사용방법 설명이다.

USB Redirector를 구현하는 환경은 아래와 같다.

a. Linux(Server) – Windows(Client)
b. Linux(server) – Linux(Client)
c. Windows(Server) – Windows(Client)
d. Windows(Server) – Windows(Client)

Server 는 실제 USB Device 가 장작되는 Machine이고, Client 는 Remote Server에
장착된 USB 장치를 네트워크로 접근하여 인식하는 machine 이다.

incentivespro.com 에서 제공하는 USB Redirector 제품의 경우 아래와 같은 가격정책
을 가지고 있다.

a. Linux(Server) – Windows(Client) : 69.99$
b. Linux(server) – Linux(Client)  : Free
c. Windows(Server) – Windows(Client) : 74.99$
d. Windows(Server) – Linux(Client) : 74.99$

원래 Linux Server 와 Windows, Linux Client는 Free 이다.
하지만 Linux Server에 접속하는 Windows Clinet는 별도의 라이센스비(69.99$)가
포함되어 진다.

Windows Server의 경우 기본 15일간 free로 사용이 가능하다.

Linux Server와 Linux Client 간 사용은 완전 free 다.

설치 방법에 대해 알아보도록 하자 .

http://www.incentivespro.com/downloads.html 에서 USB Redirector for LINUX
버전을 다운 받는다.

Server 와 Client 에 모두 아래와 같이 설치 한다.

# tar xzvf usb-redirector-linux-x86_64.tar.gz
# cd usb-redirector-linux-x86_64

– Server 버전 설치

# ./installer.sh install-server

– Clinet 버전 설치

# ./installer.sh install-client

– Server and Client 버전 설치

./installer.sh install

설치가 완료되면 아래 경로에 패키지가 설치 된다.

# ls /usr/local/usb-redirector/bin
tusbd.ko  usbclnt  usbsrv  usbsrvd

– Server 관리 방법

데몬 시작
# ./usbsrvd

인식되는 USB 리스트 확인
# ./usbsrv -l
================= USB SERVER OPERATION SUCCESSFUL ===============
List of USB devices:

   1: 2.4G USB RF KeyBoard Composite USB Device
      Vid: 05af   Pid: 0408   Port: 2-4.4
      Status: plugged, in exclusion list

   2: Vimicro USB2.0 Camera Vimicro Corp. Composite USB Device
      Vid: 0ac8   Pid: 3420   Port: 2-4.3
      Status: plugged, in exclusion list

   3: Microsoft 5-Button Mouse with IntelliEye(TM) Microsoft USB Human Interface Device – Mouse
      Vid: 045e   Pid: 0047   Port: 2-4.1
      Status: plugged, in exclusion list

   4: USB Audio Composite USB Device
      Vid: 0c45   Pid: 17fd   Port: 6-1
      Status: plugged

   5: USB DISK SMI Corporation USB Mass Storage Device
      Vid: 1c6c   Pid: 0d48   Port: 2-4.2
      Status: plugged, shared

===================== ======================= ===================

특정 USB Device 공유하기
# ./usbsrv -s <device>

<device> is <deviceid> | -vid <vendorid> -pid <productid> -usbport <port>

만일 usbid 5 인 USB DISK SMI Corporation USB Mass Storage Device 를 공유하고자 할경우
아래와 같이 명령을 실행하면 된다.

# ./usbsrv -s 5

해당 USB 장치 공유를 해제할때는 아래와 같이 명령을 실행한다.

# ./usbsrv -t 5

이밖에 주요 관리 명령은 아래와 같다.

    -s,-share <device>        Share a specified device.
    -t,-unshare <device>      Unshare a specified device.
    -addexclude <device>      Add specified device to exclusion list.
    -remexclude <device>      Remove specified device from exclusion list.
    -createcallback <address:port>
        Create callback connection to remote USB client.
    -closecallback <address:port> | <callbackid>
        Close callback connection to remote USB client.
    -l,-list                  Show the list of all USB devices currently present in USB server configuration.
    -i,-info                  Show current USB Server state.
    -listclients              Show the list of connected USB clients.
    -n,-settcpport <port>     Change TCP port number used to accept incoming connections.
    -autoshareon              Swith to auto-sharing mode.
    -autoshareoff             Swith to manual-sharing mode.

-addexclude 는 기본 인식되는 USB 중 공유 가능 목록에서 제외할 경우에 사용된다.
addexclude 가 적용된 device는 원격에서 접속할 수 없게 된다. 이 기능은 자동으로 모든 장치를
shared 하는 구성이라면, 로컬에 장착된 mouse나 keyboard 처럼 외부에서 접근을 하면 안되는
장치들을 제외 시킬 때 사용할 수 있다. 이와 같이 원격에서 같은 장치를 공유하는 환경에서는
특정 host 에서 장치를 사용하면, 다른 host 에서는 해당 장치를 사용할 수 없다.
그렇기 때문에 반드시 로컬에서만 사용해야 하는 장치는 exclusion 시켜야 한다.

– Client 관리 방법

원격 USB 서버 접속
# ./usbclnt -addserver <server_ip>:32032

원격 USB 장치 접근 목록 확인
# ./usbclnt -l
================= USB CLIENT OPERATION SUCCESSFUL ===============
List of USB servers and devices:

   5: USB server at 192.168.123.2:32032
      Mode: manual-connect   Status: connected
   |
   `-   1: PC Camera Z-Star Corp.
           Vid: 0ac8   Pid: 301b   Port: 5-2
           Mode: manual-connect   Status: available for connection
===================== ======================= ===================

원격 USB 장치 접속

# ./usbclnt -connect 5-1

원격 USB 접속 장치 해제

# ./usbclnt -u 5-1

기타 관리 옵션

   -a,-addserver <address:port>
        Add remote usb server into configuration.
    -r, -remserver <address:port> | <serverid>
        Remove remote usb server from configuration and disconnect all devices from that server.
    -c, -connect <server> <device> | <serverid>-<deviceid>
        Connect a specified device from a specified server. Server should be added to your configuration first.
    -u, -disconnect <server> <device> | <serverid>-<deviceid>.
        Disconnect a specified device on a specified server.
    -addexclude <server> <device> | <serverid>-<deviceid>
        Add specified device to exclusion list.
    -remexclude <server> <device> | <serverid>-<deviceid>
        Remove specified device from exclusion list.
    -autoconnecton <server> [<device>] | <serverid>[-<deviceid>]
        Enable automatic connection of a single device or all devices on the specified server.
    -autoconnectoff <server> [<device>] | <serverid>[-<deviceid>]
        Disable automatic connection of a single device or all devices on the specified server.
    -l, -list
        Show a list of all usb servers and devices in your configuration.
    -i, -info
        Show information about USB Client.

7. USBIP 를 이용한 USB Redirect 환경 구성하기

위의 USB Redirector 의 경우 일부 환경에서는 free로 사용이 가능하나, 전반적인 환경에서는
상용으로 비용을 지급해야 한다.

대부분의 USBIP 기술은 Open Source 인 Usbip 프로젝트에서 나온 산출물을 이용해 개발되었다고
볼수 있다. 본 장에서는 Open Source 인 usbip 를 이용하여 usb redirect 환경을 구성하는
방법에 대해 알아보자

USBIP 는 Server(USB 장치가 물리적으로 장착되는 시스템)환경이 LINUX 이고, Client 환경이
Windows or LINUX 인 조합에서 사용이 가능하다.

관련된 패키지는 http://usbip.sourceforge.net/ 에서 구할 수 있다.

필요한 패키지는 Server(LIUNX) 환경에 설치되는 usbip-0.17.tar.gz 파일을 다운 받는다.
그런 후 Client(Windows) 환경에 필요한 usbip_windows_v0.1.0.0_signed.zip 파일을 다운받는다.

– Server(LINUX) and Client(LINUX) 환경 설치

먼저 Server(LINUX) 환경에 패키지를 설치 한다.

# tar xzvf usbip-0.17.tar.gz
# cd usbip-0.17
# ls
COPYING  NEWS  README  drivers  src

drivers 디렉토리에는 Kernel modules source 가 들어있고, src 밑에는 관련 util source
가 들어 있다.

먼저 kernel modules을 설치 한다.

# cd drivers/<kernel_version>

기본적인 설치 방법은 아래와 같다.

# make KSOURCE=<kernel source path>

현재 테스트하고 있는 장비는 RHEL5.x 환경이다.

# make KSOURCE=/usr/src/kernels/2.6.18-238.9.1.el5-x86_64

기본 RHEL 커널을 사용하고 있다면 아래와 같은 에러가 발생할 것이다.

.
/home/alang/Downloads/usbip-0.1.7/drivers/2.6.18/stub_rx.c:377: error: redefinition of ‘usb_endpoint_xfer_bulk’
include/linux/usb.h:496: error: previous definition of ‘usb_endpoint_xfer_bulk’ was here
/home/alang/Downloads/usbip-0.1.7/drivers/2.6.18/stub_rx.c:383: error: redefinition of ‘usb_endpoint_xfer_control’
include/linux/usb.h:508: error: previous definition of ‘usb_endpoint_xfer_control’ was here
/home/alang/Downloads/usbip-0.1.7/drivers/2.6.18/stub_rx.c:389: error: redefinition of ‘usb_endpoint_xfer_int’
include/linux/usb.h:521: error: previous definition of ‘usb_endpoint_xfer_int’ was here
/home/alang/Downloads/usbip-0.1.7/drivers/2.6.18/stub_rx.c:395: error: redefinition of ‘usb_endpoint_xfer_isoc’
include/linux/usb.h:534: error: previous definition of ‘usb_endpoint_xfer_isoc’ was here
make[2]: *** [/home/alang/Downloads/usbip-0.1.7/drivers/2.6.18/stub_rx.o] Error 1
make[1]: *** [_module_/home/alang/Downloads/usbip-0.1.7/drivers/2.6.18] 오류 2
make[1]: Leaving directory `/usr/src/kernels/2.6.18-238.9.1.el5-x86_64′
make: *** [default] 오류 2

해결 방법은 아래와 같다.

# cd usbip-0.1.7/drivers/2.6.18

kernel.org 에서 같은 커널 버전의 original source 파일을 다운 받는다.

# wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2
# tar xjvf linux-2.6.18.tar.bz

original kernel source 의 hcd.h, hub.h 파일을 RHEL 커널 소스에 copy 한다.

# cp linux-2.6.18/drivers/usb/core/{hcd.h,hub.h} \
/usr/src/kernels/2.6.18-238.9.1.el5-x86_64/drivers/usb/core/

현재 디렉토리의 stub_rx.c 소스 파일을 상위의 head 디렉토리에 있는 소스
파일로 대처한다.

# mkdir backup
# mv stub_rx.c backup
# cp ../head/stub_rx.c .

현재 디렉토리에 header 디렉토리를 만들고 hcd.h, hub.h 파일을 복사한다.

# mkdir headers
# cp linux-2.6.18/drivers/usb/core/{hcd.h,hub.h} headers

make 한다.

# make KSOURCE=/usr/src/kernels/2.6.18-238.9.1.el5-x86_64

정상적으로 compile 이 완료되면, 아래와 같은 모듈이 생성된다.

usbip.ko  usbip_common_mod.ko  vhci-hcd.ko

usbip_common_mod.ko -> server/client 공통 module
usbip.ko -> server module
vhci-hcd.ko -> client module

해당 파일을 적당한 곳에 복사해 둔다.

# mkdir -p /usr/local/usbip/bin
# cp *.ko /usr/local/usbip/bin

이제 usbip utility 를 컴파일 한다.

# cd ~usbip-0.1.7/src
# ./autogen.sh
# ./configure –prefix=/usr/local/usbip

configure 단계에서 아래와 같은 에러가 발생할 수 있다.

checking for sysfs/libsysfs.h… no
configure: error: Missing /usr/include/sysfs/libsysfs.h

libsysfs, libsysfs-devel 패키지 설치를 확인한 후, 설치가 안되어 있다면
설치 한다.

# yum install libsysfs libsysfs-devel

configure가 정상적으로 완료되면 make 와 make install로 패키지를 설치한다.

# make && make install

# cd /usr/local/usbip/bin
# ls
bind_driver  usbip  usbip.ko  usbip_common_mod.ko  usbipd  vhci-hcd.ko

Server 환경 설치가 완료되었다.

– Client(Windwos) 환경 설치

usbip_windows_v0.1.0.0_signed.zip 파일 압축을 해제한다.

장치관리자에서 “레거시 하드웨어 추가” 혹은 “새 하드웨어 추가”를 선택한다.
“목록에서 직접 선택한 하드웨어 설치” 를 선택하고,
모든장치 선택에서 다음 진행.
디스크 있음(Have Disk) 에서 압축 해제된 디렉토리 선택

USB/IP Enumerator 가 표시된다. 선택하고 다음 진행.
설치를 완료한다.

설치가 완료되면, 장치 관리자의 [시스템] 에서 USB/IP Enumerator 란 장치가
잡혀 있는 것을 확인 할 수 있다.

압축 해제 폴더에 usbip.exe 파일이 존재한다. 해당파일은 usb client 관리명령
으로 Server에 접속할때 사용되어 진다.

– 사용방법

[Server(LINUX) 환경]

# cd /usr/local/usbip/bin

Server kernel module 로딩

# insmod usbip_common_mod.ko
# insmod usbip.ko

USBIP Server 데몬 시작

# ./usbipd -D

USB Device 목록 확인

# ./bind_driver –list
—————————————————-
List USB devices
 – busid 2-4.4 (05af:0408)
         2-4.4:1.0 -> usbhid
         2-4.4:1.1 -> usbhid

 – busid 2-4.3 (0ac8:3420)
         2-4.3:1.0 -> uvcvideo
         2-4.3:1.1 -> uvcvideo
         2-4.3:1.2 -> snd-usb-audio
         2-4.3:1.3 -> snd-usb-audio

 – busid 2-4.1 (045e:0047)
         2-4.1:1.0 -> usbhid

 – busid 6-1 (0c45:17fd)
         6-1:1.0 -> snd-usb-audio
         6-1:1.1 -> snd-usb-audio
         6-1:1.2 -> snd-usb-audio
         6-1:1.3 -> usbhid

 – busid 2-4 (05e3:0606)
         2-4:1.0 -> hub
———————————————————-

USB Device 공유하기

# ./bind_driver –usbip <busid>

uvcvideo 장치를 USBIP를 통해 Remote PC에 공유하기 위한다면
아래와 같은 명령으로 공유가 가능하다.

# ./bind_driver –usbip 2-4.3
———————————————————–
** (process:6949): DEBUG:  2-4.3:1.0    -> uvcvideo
** (process:6949): DEBUG: unbinding interface
** (process:6949): DEBUG:  2-4.3:1.1    -> none
** (process:6949): DEBUG:  2-4.3:1.2    -> snd-usb-audio
** (process:6949): DEBUG: unbinding interface
** (process:6949): DEBUG:  2-4.3:1.3    -> snd-usb-audio
** (process:6949): DEBUG: unbinding interface
** (process:6949): DEBUG: write “add 2-4.3” to /sys/bus/usb/drivers/usbip/match_busid
** Message: bind 2-4.3 to usbip, complete!
———————————————————–

bind_driver –list 로 공유 상태를 확인한다.

# ./bind_driver –list
———————————————————–
List USB devices
 – busid 2-4.4 (05af:0408)
         2-4.4:1.0 -> usbhid
         2-4.4:1.1 -> usbhid

 – busid 2-4.3 (0ac8:3420)
         2-4.3:1.0 -> usbip
         2-4.3:1.1 -> usbip
         2-4.3:1.2 -> usbip
         2-4.3:1.3 -> usbip

.
———————————————————–

USB 장치 공유 해제 하기

# ./bind_driver –other <usbid>

[Client(LINUX) 환경]

Client Kernel Module 로딩하기

# insmod usbip_common_mod.ko
# insmod vhci-hcd.ko

Remote Server의 공유 USB 목록 확인하기

# ./usbip –list <server_ip>

Remote Server의 공유 USB 연결하기

# usbip –attach <server_ip> <busid>

공유 USB 연결 상태 확인
# usbip –port

공유 USB 연결 해제하기
# usbip –detach 0

[Client(Winodws) 환경]

Windows 명령창에서 usbip_windows_v0.1.0.0.zip 압축 파일이 해제된 디렉토리
이동한다.

usbip.exe 명령이 존재하고, 사용방법은 Client(LINUX)와 동일하다.

– 참고 사항

A. Open Source인 USBIP의 경우 Windows 7 에서 장치를 인식하지만, 로딩 단계에서
실패 되는 경우가 많고, Windows XP의 경우에도 인식이 안되는 경우가 종종 발생
했다. USBIP 장치를 연결한 상태에서 정상적으로 장치 제거를 하지 않고, 운영체제
를 종료할 경우 종료 진행 중 멈추는 증세도 발견되었음.

B. linux kernel 2.6.25 이상 부터는 USBIP가 linux의 기본 커널안에 포함되어 있다.
RHEL6 의 경우 2.6.32 로 http://usbip.sourceforge.net 사이트에서 다운 받은
소스로는 설치가 안된다.

RHEL6 에서 설치하는 방법은 아래와 같다.

# cd usbip-0.1.7/drivers

# wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.tar.bz2
# tar xjvf linux-2.6.32.tar.bz2
# cp -a linux-2.6.32/drivers/staging/usbip 2.6.32
# cp 2.6.25/Makefile 2.6.32
# cp linux-2.6.32/drivers/usb/core/{hcd.h,hub.h} \
/usr/src/kernels/2.6.32-71.el6.x86_64/drivers/usb/core

# mkdir headers
# cp linux-2.6.32/drivers/usb/core/{hcd.h,hub.h} headers
# cd 2.6.32
# make KSOURCE=/usr/src/kernels/2.6.32-71.el6.x86_64

간혹 hcd.h 파일을 찾을수 없다는 에러와 함께 comile 이 안되는 경우가 발생한다.
이때는 해당 소스의 head 파일 경로를 headers 경로로 변경해 주면 된다.
에러가 발생하는 소스 파일은 stub_rx.c 와 vhci.h 파일이다.

이후 과정은 앞서 설명한바와 같이  동일하다.

8. Live Migration 구현 및 관리 방법

9. DRS, DPM, PCI Passthrought …`

usb passthrought 기능

RHEL6 에서 usb passthrough 기능이 존재한다. 하지만 libvirt bug로 인해 정상동작하지 않는다.
libvirt-0.8.8 로 업그레이드하면 잘된다.

usb passthrought

virt-manager 에서 usb 장치를 추가한 후, virsh edit 로 관련 정보 확인 ..

 <hostdev mode=’subsystem’ type=’usb’>
     <source>
       <vendor id=’0x1234’/>
       <product id=’0x5678’/>
     </source>
   </disk>

qemu-kvm     -usb -usbdevice host:1234:5678

/usr/libexec/qemu-kvm -M rhel6.0.0 -enable-kvm -m 3048 -smp 4,sockets=1,cores=2,threads=4 -name desktop_xp1 -uuid 8cc9210d-bce4-04f0-7584-b344b99e56c2 -nodefconfig -nodefaults -chardev socket,id=monitor,path=/var/lib/libvirt/qemu/desktop_xp1.monitor,server,nowait -mon chardev=monitor,mode=control -rtc base=localtime -boot c -drive file=/home/vdimage/winxp01.qcow2,if=none,id=drive-virtio-disk0,boot=on,format=raw,cache=writeback -device virtio-blk-pci,bus=pci.0,addr=0x6,drive=drive-virtio-disk0,id=virtio-disk0 -drive if=none,media=cdrom,id=drive-ide0-1-0,readonly=on,format=raw -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 -usb -device usb-tablet,id=input0 -usbdevice host:04e8:2f03 -spice port=5901,addr=0.0.0.0,disable-ticketing -vga qxl -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4

# virsh nodedev-list –tree
# virsh nodedev-list | grep pci
# virsh nodedev-dumpxml pci_8086_3a6c
# virsh nodedev-dettach pci_8086_3a6c

Bus 002 Device 003: ID 04e8:2f03 Samsung Electronics Co., Ltd

  +- pci_0000_00_1d_7
  |   |
  |   +- usb_usb2
  |       |
  |       +- usb_2_0_1_0
  |       +- usb_2_4
  |           |
  |           +- usb_2_4_1_0
  |               |
  |               +- scsi_host5
  |                   |
  |                   +- scsi_target5_0_0
  |                       |
  |                       +- scsi_5_0_0_0
  |                           |
  |                           +- block_sdb_Samsung_S1_Mini_0000002AE0931020042D_0_0

<device>
  <name>pci_0000_00_1d_7</name>
  <parent>computer</parent>
  <driver>
    <name>ehci_hcd</name>
  </driver>
  <capability type=’pci’>
    <domain>0</domain>
    <bus>0</bus>
    <slot>29</slot>
    <function>7</function>
    <product id=’0x3a3a’>82801JI (ICH10 Family) USB2 EHCI Controller #1</product>
    <vendor id=’0x8086′>Intel Corporation</vendor>
  </capability>
</device>
o
pci_0000_05_00_0
05:00.0 0300: 10de:0659 (rev ff)

readlink /sys/bus/pci/devices/0000\:00\:1d.7/driver
virsh nodedev-dettach pci_0000_00_1d_7
virsh start desktop_xp1

assigned_dev_iomem_map: Error: create new mapping failed

서진우

슈퍼컴퓨팅 전문 기업 클루닉스/ 상무(기술이사)/ 정보시스템감리사/ 시스존 블로그 운영자

You may also like...

9 Responses

  1. Binance 말해보세요:

    Can you be more specific about the content of your article? After reading it, I still have some doubts. Hope you can help me.

  1. 2023년 12월 9일

    … [Trackback]

    […] Read More on that Topic: nblog.syszone.co.kr/archives/4531 […]

  2. 2023년 12월 19일

    … [Trackback]

    […] Info to that Topic: nblog.syszone.co.kr/archives/4531 […]

  3. 2023년 12월 20일

    … [Trackback]

    […] Here you will find 28557 additional Information to that Topic: nblog.syszone.co.kr/archives/4531 […]

  4. 2024년 2월 3일

    … [Trackback]

    […] Read More Information here on that Topic: nblog.syszone.co.kr/archives/4531 […]

  5. 2024년 3월 3일

    … [Trackback]

    […] Info to that Topic: nblog.syszone.co.kr/archives/4531 […]

  6. 2024년 3월 6일

    … [Trackback]

    […] Read More to that Topic: nblog.syszone.co.kr/archives/4531 […]

  7. 2024년 3월 18일

    … [Trackback]

    […] Find More Info here on that Topic: nblog.syszone.co.kr/archives/4531 […]

  8. 2024년 4월 15일

    … [Trackback]

    […] Here you can find 13793 more Info on that Topic: nblog.syszone.co.kr/archives/4531 […]

페이스북/트위트/구글 계정으로 댓글 가능합니다.