The Design and Implementation of Hyperupcalls


Nadav Amit, Michael Wei
USENIX 2018 Annual Technical Conference

개요

eBPF를 사용해서 Hyperupcall이라는 것을 만들어 Hypervisor가 Upcall처럼 Guest와 Context change없이 Guest가 요구하는 동작을 안전하게 수행하도록 하여서 Guest OS와 Hypervisor사이의 Semantic Gap을 없얬다.

Motivation

Hardware virtualization은 다양한 이점을 가져왔지만, Isolation을 위해서 Semantic Gap이 HypervisorGuest OS사이에 생겼다. 이러한 Semantic gap은 성능 저하의 주된 원인이 되었다.

Importance

Paravirtualization은 Semantic gap을 없앴지만, Context switch가 필요하고, Context의 작업이 끝날때 까지 Busy wait해야 하며, Hypervisor와 Guest OS의 개발을 같이 해야만 하는 문제가 있었다. VMIHMI와 같은 경우에는 introspecting을 통해서 다른 context의 정보를 가져와 위와 같은 문제를 없앴지만, 다른 Context에 조금이라도 다른 Data structure나 Memory layout이 생기면 시스템을 사용할 수 없는 fragile한 문제가 있었다.

Main Idea

SPIN Operating system[1], ExoKernel처럼 Hypervisor와 Guest사이에 Flexible한 Interface를 제공하고, Guest OS가 Hypervisor의 기능을 바꿀 수 있도록 하여서 Semantic gap을 해결하고자 하였다.

Design

Hypervisor-Guest Communication Mechanisms
Hypercall Upcall VMI Pre-virtualization Hyperupcall
Direction Guest -> Hyper Hyper -> Guest Hyper -> Guest Hyper -> Guest Hyper -> Hyper
Context switch Yes Yes No Yes No
Maintenance Hard Hard Hard (Fragile to code change) Moderate Easy
Security (TCB) VMM VMM VMM VMM eBPF

Guest OS가 eBPF로 Hyperupcall이라는 코드를 Hypervisor로 내려주면 Hypervisor가 Memory pressure환경처럼 특정 조건에서 등록된 Hyperupcall을 실행시켜서, Guest OS의 Semantic 정보를 통해서 효율적으로 Hypervisor기능을 수행할 수 있도록 하였다.

Building Hyperupcall
eBPF를 사용해서 안전하게 특정 이벤트 시점에 발생할 Hypervisor extension을 작성할 수 있도록 하였다. Guest OS와 같은 경우 KASLR를 사용할 수도 있어서, OS symbol offset을 Runtime에 추적할 수 있도록 하였다. Hyperupcall이 만약 Guest의 작동에만 영향을 주면 Local hyperyupcall로 hyperupcall이 block되고 sleep될 수 있도록 하였다. 만약 Hyperupcall의 기능이 Global하게 영향을 주면, eBPF처럼 Static한 time에 끝날 수 있도록 하였다. eBPF는 만약 제약사항들이 존재하기 때문에 memset이나 memcpy처럼 Loop을 사용하는 Operation들은 Helper function으로 만들어서 이러한 제약조건을 회피하였다.
Compilation
Hyperupcall의 BPF Context에는 event종류, Host virtual address, vcpus와 같은 정보들이 담겨있다. 특히 GVA로 접근하는 Guest OS의 Address를 Hyperupcall에서 접근하기 위해서 Hypervisor가 GVA의 어드레스를 HVA에 Mapping하도록 하였다. 나중에 Hyperupcall에서는 Baseaddress offset을 HVA와 GVA의 차이만큼 빼도록 하여서 접근할 수 있도록 하였다.
Registration
Hyperupcall을 event종류, Guest OS 메모리의 어느정도를 Hyperupcall에 사용할 것인지 (최대 Guest total physical memory의 2%로 제약된다.)를 통해서 등록할 수 있도록 하였다.
Execution
Hyperupall을 static keys라는 시스템을 사용해서 Pathcing해서 빠르게 실행될 수 있도록 하였다. VCPU의 Register와 같은 정보들은 따로 Copy를 통해서 접근하도록 하여서 VMCS를 로딩하는 등의 Overhead를 피했다. Guest의 구조체에 직접 접근하기 때문에 Guest OS와의 Synchronization문제가 있는데, 이는 Hyperupcall에서 try_lock을 구현할 수 있도록 하여서 해결하였다.

Result

Guest OS TLB Shootdown, Memory reclaimation과 같은 시나리오에 적용해서 유의미한 성능향상이 있음을 보였다.

Contribution

  1. Guest OS와 Hypervisor사이의 Semantic gap을 Safe programming환경을 통해서 해결함
  2. Hyperupcall과 같이 후에 Hypervisor semantic gap을 극복하는 연구의 아이디어를 제공함

Criticizing

  1. eBPF에서 Side channel attack으로 공격당하면, Hypervisor의 Address space offset과 같은 것들이 Leak될 수도 있다.
  2. eBPF의 제약 조건을 극복하기 위해서 여러 패치를 했지만, 근본적인 eBPF의 문제로 인해서 복잡한 Logic을 작성 불가능 할 수도 있다.
  3. Guest OS와의 Synchornization문제가 어쩌면 조금 약하게 푼것 같다는 생각이 든다. (중요한 일이지만 Future work으로 남긴것 같다.)

Reference