![사용자 모드 QEMU에서 충돌 없이 포트를 전달하려면 어떻게 해야 합니까?](https://rvso.com/image/756237/%EC%82%AC%EC%9A%A9%EC%9E%90%20%EB%AA%A8%EB%93%9C%20QEMU%EC%97%90%EC%84%9C%20%EC%B6%A9%EB%8F%8C%20%EC%97%86%EC%9D%B4%20%ED%8F%AC%ED%8A%B8%EB%A5%BC%20%EC%A0%84%EB%8B%AC%ED%95%98%EB%A0%A4%EB%A9%B4%20%EC%96%B4%EB%96%BB%EA%B2%8C%20%ED%95%B4%EC%95%BC%20%ED%95%A9%EB%8B%88%EA%B9%8C%3F.png)
나는 일부 권한 있는 작업을 수행하는 Python 스크립트용 테스트 제품군의 일부로 QEMU에서 Linux를 실행하고 있습니다. 전체 가상 머신을 실행하는 것이 나에게 중요한 이유는 다음과 같습니다.
- 테스트를 실행하기 위해 sudo 액세스를 요구하고 싶지 않습니다.
- 나중에 다양한 배포판과 커널 버전에서 테스트를 실행하는 것이 더 쉬울 것입니다.
- 컴퓨터가 고장날 가능성이 적습니다
내 접근 방식은 VM의 SSH로 전달된 호스트 포트를 사용하여 QEMU VM을 시작하고, SSH를 통해 스크립트를 전송 및 실행하고, 스크립트를 실행하고, 원격 시스템에 대한 정보를 어설션하는 것입니다. 이 설정에서 짜증나는 점은 SSH 포트와 다른 네트워크 애플리케이션용 포트입니다.
내 질문:사용자 모드 QEMU에서 충돌 없이 포트를 전달하려면 어떻게 해야 합니까?
여기서 나의 목표는 위에서 언급한 것처럼 사전 설정이나 sudo 없이 여러 테스트를 동시에 실행할 수 있는 것입니다. QEMU의 사용자 모드 네트워킹은 포트 전달을 지원하며, 0
hostfwd 선언( )에서 호스트 포트를 전달하면 hostfwd=tcp:127.0.0.1:0-:22
OS가 동적으로 하나를 할당합니다. 엄청난! 문제는 상위 프로세스에서 해당 포트를 안정적으로 가져오는 것입니다.
나는 다음과 같은 작업을 수행하고 있습니다.
#!/bin/sh
set -e
cd "$(mktemp -d)"
# Download cloud image.
image_base_url="https://cloud-images.ubuntu.com/releases/18.04/release/"
image_name="ubuntu-18.04-server-cloudimg-amd64.img"
image_url="$image_base_url$image_name"
curl --location -o linux.img $image_url
# Create SSH key.
ssh_key_path="$PWD/id_rsa"
ssh-keygen -t rsa -b 4096 -N "" -f "$ssh_key_path"
# Create cloud-init payload.
cat <<EOF > user_data
#cloud-config
password: ubuntu
chpasswd: { expire: False }
ssh_pwauth: True
ssh_authorized_keys:
- $(cat "${ssh_key_path}.pub")
EOF
cloud-localds user_data.img user_data
# Socket path for QMP.
qmp_socket="$PWD/qmp.sock"
# Start VM.
qemu-system-x86_64 \
-drive file=linux.img,format=qcow2 \
-drive file=user_data.img,format=raw \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:0-:22 \
-device rtl8139,netdev=net0 \
-enable-kvm \
-m 2G \
-serial mon:stdio \
-nographic \
-smp 2 \
-snapshot \
-qmp unix:$qmp_socket,server,nowait \
& \
;
# wait a bit, then test stuff here
# ...
게스트 OS가 제대로 작동합니다.
내가 시도한 것들:
조금 놀았어QMP, 그러나 정보를 제공하는 명령을 찾을 수 없습니다
상위 프로세스의 임의 포트를 바인딩한
SO_REUSEPORT
다음 하위 명령에 대해 지정하는 것을 고려했지만 QEMU는 이 플래그를 사용하지 않으므로 작동하지 않습니다.netstat -nalp | grep $child_pid
, 단, 여러 포트를 포워딩하는 경우에는 사용할 수 없습니다.바인딩되지 않은 임의의 포트를 선택하여 qemu를 시작하려고 시도하고 메시지 일치로 실패하면 다시 시도합니다
Could not set up host forwarding rule 'tcp:...'
. 이것은 효과가 있지만- 포트가 많을수록 실패할 가능성이 더 높습니다.
- 재시도할 가치가 없는 다른 문제를 모호하게 만들 수 있습니다.
이는 괜찮은 대체 방법이지만 보다 간단한 해결책이 있기를 바랍니다.
답변1
좀 더 조사한 후: QEMU는 info usernet
명령을 통해 정보를 노출합니다. 출력은 다음과 같습니다.
(qemu) info usernet
VLAN -1 (net0):
Protocol[State] FD Source Address Port Dest. Address Port RecvQ SendQ
TCP[HOST_FORWARD] 13 127.0.0.1 38117 10.0.2.15 22 0 0
UDP[236 sec] 24 10.0.2.15 35061 91.189.89.198 123 0 0
UDP[204 sec] 26 10.0.2.15 60630 91.189.89.198 123 0 0
QMP를 통해 사용할 수 없지만 이에 상응하는 항목을 추가하기 위해 패치가 제출되었습니다.query-usernet
여기전자.
내 경우에는 를 사용하여 모니터를 노출하고 -monitor unix:$PWD/mon.sock,server,nowait
, 연결하고, 명령을 보내고, 출력을 읽고, 원하는 값에 대해 구문 분석하는 것이 간단합니다.
요약하자면, QEMU를 사용하여 sudo 또는 기타 전제 조건(QEMU 자체 제외)을 요구하지 않고 호스트에서 포트 충돌을 피하면서 네트워크 애플리케이션을 테스트하려면 다음을 수행하십시오.
- 각 애플리케이션에 대해 명령줄(
-netdev
) 또는 모니터(netdev_add
) 를 통해 포트 매핑을 생성하여0
호스트 포트를 제공합니다. monitor
소비 애플리케이션을 위해 Unix 소켓으로 노출- 소켓을 통해 실행
info usernet
하고 각 매핑에 대해 OS에서 할당한 실제 포트인 Source Port를 추출합니다.