Files
document-haness/docs/keycloak-session-store/final/.techviz/cpu-io-passthrough-paths/spec.json
T

342 lines
9.3 KiB
JSON

{
"version": "1.1",
"id": "cpu-io-passthrough-paths",
"title": "게스트가 하드웨어에 닿는 갈래는 셋이고 깊이가 다르다",
"question": "게스트의 CPU 실행·virtio I/O·직접 할당한 장치는 각각 어디까지 내려가고 호스트 유저공간을 지나는가",
"type": "architecture",
"direction": "TB",
"audience": [
"가상화 구조를 처음 읽는 사람",
"이 실험대가 무엇 위에서 도는지 알아야 하는 사람"
],
"summary": "CPU 는 QEMU 와 KVM 사이를 왕복하고, virtio 는 virtqueue 를 누가 소비하느냐에 따라 QEMU 나 커널 vhost 로 가며, 패스스루는 유저공간 드라이버가 IOMMU 보호 아래 장치에 직접 닿는다.",
"alt": "게스트·호스트 유저공간·호스트 커널·하드웨어 네 층을 가로지르는 세 갈래 경로도.",
"long_description": "위에서 아래로 읽는다. 맨 위 QEMU 에서 갈래 셋이 갈린다. 왼쪽 CPU 갈래는 KVM_RUN 으로 커널의 KVM 에 들어가고 KVM 이 VM entry 로 물리 CPU 에 올리며 게스트 코드가 VMX non-root 로 거기서 돈다. 물리 CPU 상자에 VM exit 이 함께 적혀 있고 나온 이유는 KVM 상자의 struct kvm_run 으로 유저공간에 돌아간다. 가운데 패스스루 갈래는 QEMU 가 VFIO 로 장치 fd 를 받고 vfio-pci 가 장치를 묶으며 그 장치의 DMA 가 IOMMU 를 지난다. 오른쪽 virtio 갈래는 virtqueue 가 게스트 드라이버에 닿고 같은 virtqueue 를 커널 vhost 와 나누는 길이 따로 있다. 앞의 둘은 이 실험대가 쓰고 패스스루는 쓰지 않는다.",
"source_context": {
"document": "docs/keycloak-session-store/final/document.md",
"document_sha256": "0ae5674723f25dc85d5069529890f07be1a11b768b56901103fa3ea6ac3dcf55",
"anchor": {
"kind": "heading",
"value": "이 층 아래의 구조 — 조사한 것",
"line": 1091
}
},
"composition": {
"profile": "component-flow",
"diagram_only": true,
"reference_ids": [
"payment-event-flow"
],
"rationale": "세 갈래가 각각 방향이 있는 경로다. comparison 은 관계선을 지워도 뜻이 남는 배치라 이 그림에서는 표가 되고, 깊이가 다르다는 주장이 자리로 드러나지 않는다.",
"focus_node": "qemu"
},
"groups": [],
"nodes": [
{
"id": "qemu",
"label": "QEMU",
"kind": "service",
"role": "source",
"shape": "box",
"emphasis": "primary",
"details": [
"/dev/kvm",
"KVM_CREATE_VM · KVM_CREATE_VCPU"
],
"description": "KVM 핸들을 열고 VM 과 vCPU 를 만드는 유저공간 프로세스. vcpu ioctl 은 그 vcpu 를 만든 스레드에서 낸다.",
"evidence": [
{
"start_line": 1102,
"end_line": 1108
}
],
"assumption": false
},
{
"id": "vfio",
"label": "VFIO",
"kind": "service",
"role": "service",
"shape": "box",
"details": [
"vfio-pci",
"IOMMU 그룹",
"/dev/vfio/vfio"
],
"description": "IOMMU 보호 아래 장치 접근을 유저공간에 여는 프레임워크. 소유 단위가 IOMMU 그룹이다.",
"evidence": [
{
"start_line": 1131,
"end_line": 1146
}
],
"assumption": false
},
{
"id": "pci-device",
"label": "물리 PCI 장치",
"kind": "service",
"role": "service",
"shape": "box",
"details": [
"게스트 직접 할당"
],
"description": "호스트 드라이버에서 떼어 vfio-pci 에 묶은 장치.",
"evidence": [
{
"start_line": 1131,
"end_line": 1133
},
{
"start_line": 1144,
"end_line": 1146
}
],
"assumption": false
},
{
"id": "iommu",
"label": "IOMMU",
"kind": "service",
"role": "sink",
"shape": "box",
"details": [
"DMA · 인터럽트 리매핑"
],
"description": "장치가 아무 메모리나 건드리지 못하게 막는 리매핑 장치.",
"evidence": [
{
"start_line": 1144,
"end_line": 1146
}
],
"assumption": false
},
{
"id": "kvm",
"label": "KVM",
"kind": "service",
"role": "service",
"shape": "box",
"details": [
"struct kvm_run",
"KVM_GET_VCPU_MMAP_SIZE"
],
"description": "mmap 한 공유 메모리로 나온 이유를 유저공간에 알리는 커널 쪽.",
"evidence": [
{
"start_line": 1105,
"end_line": 1108
}
],
"assumption": false
},
{
"id": "physical-cpu",
"label": "물리 CPU",
"kind": "service",
"role": "service",
"shape": "box",
"details": [
"VMX root · VMX non-root",
"VM entry · VM exit",
"guest-state 영역"
],
"description": "VM entry 때 guest-state 영역에서 상태를 싣고 VM exit 때 그리로 저장하는 프로세서.",
"evidence": [
{
"start_line": 1111,
"end_line": 1113
}
],
"assumption": false
},
{
"id": "guest-code",
"label": "게스트 코드",
"kind": "service",
"role": "sink",
"shape": "box",
"details": [
"vCPU"
],
"description": "VMX non-root 로 물리 CPU 에서 도는 게스트 명령.",
"evidence": [
{
"start_line": 1111,
"end_line": 1113
}
],
"assumption": false
},
{
"id": "virtio-driver",
"label": "게스트 virtio 드라이버",
"kind": "service",
"role": "sink",
"shape": "box",
"details": [
"virtio-pci · virtio-mmio",
"virtqueue"
],
"description": "게스트가 보는 반가상화 장치의 드라이버. 주고받는 통로가 virtqueue 다.",
"evidence": [
{
"start_line": 1116,
"end_line": 1118
}
],
"assumption": false
},
{
"id": "vhost",
"label": "vhost",
"kind": "service",
"role": "sink",
"shape": "box",
"details": [
"리눅스 커널 구현",
"virtqueue 공유"
],
"description": "virtqueue 를 QEMU 밖과 나누는 커널 구현. vhost-user 규약이 이것을 제어하는 ioctl 인터페이스를 보완한다.",
"evidence": [
{
"start_line": 1125,
"end_line": 1129
}
],
"assumption": false
}
],
"edges": [
{
"id": "qemu-device-fd",
"from": "qemu",
"to": "vfio",
"label": "장치 fd",
"kind": "request",
"style": "solid",
"evidence": [
{
"start_line": 1138,
"end_line": 1141
}
],
"assumption": false
},
{
"id": "vfio-binds-device",
"from": "vfio",
"to": "pci-device",
"label": "vfio-pci 결합",
"kind": "control",
"style": "solid",
"evidence": [
{
"start_line": 1144,
"end_line": 1146
}
],
"assumption": false
},
{
"id": "device-dma",
"from": "pci-device",
"to": "iommu",
"label": "DMA",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 1144,
"end_line": 1146
}
],
"assumption": false
},
{
"id": "qemu-kvm-run",
"from": "qemu",
"to": "kvm",
"label": "KVM_RUN",
"kind": "request",
"style": "solid",
"evidence": [
{
"start_line": 1104,
"end_line": 1106
}
],
"assumption": false
},
{
"id": "kvm-vm-entry",
"from": "kvm",
"to": "physical-cpu",
"label": "VM entry",
"kind": "request",
"style": "solid",
"evidence": [
{
"start_line": 1111,
"end_line": 1112
}
],
"assumption": false
},
{
"id": "cpu-runs-guest",
"from": "physical-cpu",
"to": "guest-code",
"label": "VMX non-root",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 1111,
"end_line": 1112
}
],
"assumption": false
},
{
"id": "qemu-virtqueue",
"from": "qemu",
"to": "virtio-driver",
"label": "virtqueue",
"kind": "data",
"style": "solid",
"evidence": [
{
"start_line": 1116,
"end_line": 1118
},
{
"start_line": 1128,
"end_line": 1128
}
],
"assumption": false
},
{
"id": "qemu-vhost-ioctl",
"from": "qemu",
"to": "vhost",
"label": "제어 ioctl",
"kind": "control",
"style": "dashed",
"evidence": [
{
"start_line": 1125,
"end_line": 1129
}
],
"assumption": false
}
],
"legend": [],
"metadata": {
"rationale": "세 갈래의 깊이 차이는 어느 층까지 선이 내려가느냐로만 보이므로 배치와 관계선이 함께 있어야 한다. 셋 중 패스스루는 이 실험대가 쓰지 않으며 본문이 그 사실을 적는다."
}
}