Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KVM #438

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft

KVM #438

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions linux/aux-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ install:
cp cleanup-dispvms $(DESTDIR)/usr/lib/qubes
cp startup-misc.sh $(DESTDIR)/usr/lib/qubes
cp fix-dir-perms.sh $(DESTDIR)/usr/lib/qubes/
cp hypervisor.sh $(DESTDIR)/usr/lib/qubes/
32 changes: 32 additions & 0 deletions linux/aux-tools/hypervisor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

# Return hypervisor name or match result if 'name' provided
hypervisor () {
local name="$1"
local hypervisor

if [[ $(cat /sys/hypervisor/type 2>/dev/null) == 'xen' ]]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if [[ $(cat /sys/hypervisor/type 2>/dev/null) == 'xen' ]]; then
if hypervisor=$(cat /sys/hypervisor/type 2>/dev/null) && [[ "$hypervisor" = 'xen' ]]; then

hypervisor="xen"

elif [ -e /sys/devices/virtual/misc/kvm ]; then
hypervisor="kvm"
fi

if [ ! -z $hypervisor ]; then
if [ -z "$name" ]; then
echo "$hypervisor"
return 0
fi
if [ "$name" == "$hypervisor" ]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if [ "$name" == "$hypervisor" ]; then
if [ "$name" = "$hypervisor" ]; then

return 0
fi
fi
return 1
}


(return 0 2>/dev/null) && sourced=1 || sourced=0
if (( ! sourced )); then
hypervisor "$1"
fi

19 changes: 13 additions & 6 deletions linux/aux-tools/startup-misc.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
#!/bin/sh
#!/usr/bin/sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#!/usr/bin/sh
#!/usr/bin/bash --
set -euo pipefail


# Misc dom0 startup setup
#### KVM:
. /usr/lib/qubes/hypervisor.sh
########

/usr/lib/qubes/fix-dir-perms.sh
DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }')
xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ]
#### KVM:
if hypervisor xen; then
/usr/lib/qubes/fix-dir-perms.sh
DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs into an xl bug: xl doesn’t check for write errors on stdout. The following helps but does not fix the problem:

Suggested change
DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }')
DOM0_MAXMEM=$(/usr/sbin/xl list 0 | awk 'NR == 1 && NF > 3 && $3 ~ /^[0-9]+$/ { print $3 }')

xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ]
xenstore-write /local/domain/0/memory/static-max "$(( $DOM0_MAXMEM * 1024 ))"


xl sched-credit -d 0 -w 2000
cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml
xl sched-credit -d 0 -w 2000
fi
########

cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml
s=$(date +%F-%T) && cp /var/lib/qubes/qubes.xml "/var/lib/qubes/backup/qubes-$s.xml"

/usr/lib/qubes/cleanup-dispvms

# Hide mounted devices from qubes-block list (at first udev run, only / is mounted)
Expand Down
3 changes: 1 addition & 2 deletions linux/systemd/qubes-core.service
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[Unit]
Description=Qubes Dom0 startup setup
After=qubes-db-dom0.service libvirtd.service xenconsoled.service qubesd.service qubes-qmemman.service
After=qubes-db-dom0.service libvirtd.service xenconsoled.service qubesd.service
# Cover legacy init.d script

[Service]
Expand All @@ -17,5 +17,4 @@ ExecStop=-/usr/bin/killall qubesdb-daemon

[Install]
WantedBy=multi-user.target
Also=qubes-meminfo-writer-dom0.service qubes-qmemman.service
Alias=qubes_core.service
4 changes: 2 additions & 2 deletions qubes/api/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async def vm_volume_import(self, untrusted_payload):

When the script finish importing, it will trigger
internal.vm.volume.ImportEnd (with either b'ok' or b'fail' as a
payload) and response from that call will be actually send to the
payload) and response from that call will be actually sent to the
caller.
"""
self.enforce(self.arg in self.dest.volumes.keys())
Expand Down Expand Up @@ -121,7 +121,7 @@ async def vm_volume_import(self, untrusted_payload):
async def vm_volume_import_end(self, untrusted_payload):
'''
This is second half of admin.vm.volume.Import handling. It is called
when actual import is finished. Response from this method is sent do
when actual import is finished. Response from this method is sent to
the client (as a response for admin.vm.volume.Import call).

The payload is either 'ok', or 'fail\n<error message>'.
Expand Down
93 changes: 60 additions & 33 deletions qubes/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,23 @@ def init_vmm_connection(self):
raise qubes.exc.QubesException(
'VMM operations disabled in offline mode')

#### KVM:
##if 'xen.lowlevel.xs' in sys.modules:
## self._xs = xen.lowlevel.xs.xs()
##if 'xen.lowlevel.xc' in sys.modules:
## self._xc = xen.lowlevel.xc.xc()
if 'xen.lowlevel.xs' in sys.modules:
self._xs = xen.lowlevel.xs.xs()
try:
self._xs = xen.lowlevel.xs.xs()
except xen.lowlevel.xs.Error:
pass
if 'xen.lowlevel.xc' in sys.modules:
self._xc = xen.lowlevel.xc.xc()
try:
self._xc = xen.lowlevel.xc.xc()
except xen.lowlevel.xc.Error:
pass
########

self._libvirt_conn = VirConnectWrapper(
qubes.config.defaults['libvirt_uri'],
reconnect_cb=self._libvirt_reconnect_cb)
Expand All @@ -213,7 +226,7 @@ def libvirt_conn(self):
def xs(self):
"""Connection to Xen Store

This property in available only when running on Xen.
This property is available only when running on Xen.
"""

# XXX what about the case when we run under KVM,
Expand All @@ -229,7 +242,7 @@ def xs(self):
def xc(self):
"""Connection to Xen

This property in available only when running on Xen.
This property is available only when running on Xen.
"""

# XXX what about the case when we run under KVM,
Expand Down Expand Up @@ -279,9 +292,12 @@ def _fetch(self):

self.app.log.debug('QubesHost: no_cpus={} memory_total={}'.format(
self.no_cpus, self.memory_total))
with suppress(NotImplementedError):
self.app.log.debug('QubesHost: xen_free_memory={}'.format(
self.get_free_xen_memory()))
#### KVM:
#### XXX: TEMP: Commented out
##with suppress(NotImplementedError):
## self.app.log.debug('QubesHost: xen_free_memory={}'.format(
## self.get_free_xen_memory()))
########

@property
def memory_total(self):
Expand Down Expand Up @@ -323,26 +339,33 @@ def cpu_family_model(self):
self._cpu_model = model
return self._cpu_family, self._cpu_model

def get_free_xen_memory(self):
"""Get free memory from Xen's physinfo.

:raises NotImplementedError: when not under Xen
"""
try:
self._physinfo = self.app.vmm.xc.physinfo()
except AttributeError:
raise NotImplementedError('This function requires Xen hypervisor')
return int(self._physinfo['free_memory'])
#### KVM:
#### XXX: TEMP: Commented out
## def get_free_xen_memory(self):
## """Get free memory from Xen's physinfo.
##
## :raises NotImplementedError: when not under Xen
## """
## try:
## self._physinfo = self.app.vmm.xc.physinfo()
## except AttributeError:
## raise NotImplementedError('This function requires Xen hypervisor')
## return int(self._physinfo['free_memory'])
########

def is_iommu_supported(self):
"""Check if IOMMU is supported on this platform"""
if self._physinfo is None:
try:
self._physinfo = self.app.vmm.xc.physinfo()
except AttributeError:
raise NotImplementedError(
'This function requires Xen hypervisor')
return 'hvm_directio' in self._physinfo['virt_caps']
#### KVM:
#### XXX: TEMP: Commented out
## if self._physinfo is None:
## try:
## self._physinfo = self.app.vmm.xc.physinfo()
## except AttributeError:
## raise NotImplementedError(
## 'This function requires Xen hypervisor')
## return 'hvm_directio' in self._physinfo['virt_caps']
return True
########

def get_vm_stats(self, previous_time=None, previous=None, only_vm=None):
"""Measure cpu usage for all domains at once.
Expand Down Expand Up @@ -381,15 +404,19 @@ def get_vm_stats(self, previous_time=None, previous=None, only_vm=None):
current_time = time.time()
current = {}
try:
if only_vm:
xid = only_vm.xid
if xid < 0:
raise qubes.exc.QubesVMNotRunningError(only_vm)
info = self.app.vmm.xc.domain_getinfo(xid, 1)
if info[0]['domid'] != xid:
raise qubes.exc.QubesVMNotRunningError(only_vm)
else:
info = self.app.vmm.xc.domain_getinfo(0, 1024)
#### KVM:
#### XXX: TEMP: Commented out
##if only_vm:
## xid = only_vm.xid
## if xid < 0:
## raise qubes.exc.QubesVMNotRunningError(only_vm)
## info = self.app.vmm.xc.domain_getinfo(xid, 1)
## if info[0]['domid'] != xid:
## raise qubes.exc.QubesVMNotRunningError(only_vm)
##else:
## ##info = self.app.vmm.xc.domain_getinfo(0, 1024)
info = []
########
except AttributeError:
raise NotImplementedError(
'This function requires Xen hypervisor')
Expand Down
9 changes: 8 additions & 1 deletion qubes/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
'''Constants which can be configured in one place'''

import os.path
#### KVM:
from .hypervisor import hypervisor_name
########


qubes_base_dir = "/var/lib/qubes"
system_path = {
Expand All @@ -49,7 +53,10 @@
}

defaults = {
'libvirt_uri': 'xen:///',
#### KVM:
##'libvirt_uri': 'xen:///',
'libvirt_uri': 'xen:///' if hypervisor_name() == 'xen' else 'qemu:///system',
########
'memory': 400,
'hvm_memory': 400,
'kernelopts': "",
Expand Down
42 changes: 42 additions & 0 deletions qubes/hypervisor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2020 Jason Mehring <[email protected]>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <https://www.gnu.org/licenses/>.
#

'''Hypervisor utilities.'''

import pathlib


def hypervisor_name():
'''Return hypervisor name.'''
hypervisor = pathlib.Path('/sys/hypervisor/type')
if hypervisor.exists():
return hypervisor.read_text().strip().lower()
if pathlib.Path('/sys/devices/virtual/misc/kvm').exists():
return 'kvm'
return None


def is_xen():
'''Check if hypervisor is xen.'''
return hypervisor_name() == 'xen'


def is_kvm():
'''Check if hypervisor is xen.'''
return hypervisor_name() == 'xen'
1 change: 1 addition & 0 deletions qubes/tools/qubesd.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import qubes.api.misc
import qubes.log
import qubes.utils
import qubes.tools
import qubes.vm.qubesvm

# Wait for the system entropy pool to fill, so we can use “/dev/urandom” with
Expand Down
21 changes: 17 additions & 4 deletions qubes/vm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
import qubes.features
import qubes.log

#### KVM:
from qubes.hypervisor import hypervisor_name
########

VM_ENTRY_POINT = 'qubes.vm'

def validate_name(holder, prop, value):
Expand Down Expand Up @@ -368,12 +372,21 @@ def create_config_file(self):
'''Create libvirt's XML domain config file

'''
#### KVM:
##domain_config = self.app.env.select_template([
## 'libvirt/xen/by-name/{}.xml'.format(self.name),
## 'libvirt/xen-user.xml',
## 'libvirt/xen-dist.xml',
## 'libvirt/xen.xml',
## ]).render(vm=self)
hypervisor = hypervisor_name()
domain_config = self.app.env.select_template([
'libvirt/xen/by-name/{}.xml'.format(self.name),
'libvirt/xen-user.xml',
'libvirt/xen-dist.xml',
'libvirt/xen.xml',
f'libvirt/{hypervisor}/by-name/{self.name}.xml',
f'libvirt/{hypervisor}-user.xml',
f'libvirt/{hypervisor}-dist.xml',
f'libvirt/{hypervisor}.xml',
]).render(vm=self)
########
return domain_config

def watch_qdb_path(self, path):
Expand Down
20 changes: 15 additions & 5 deletions qubes/vm/qubesvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,22 @@
import qubes.vm.mix.net

qmemman_present = False
try:
import qubes.qmemman.client # pylint: disable=wrong-import-position
#### KVM:
##try:
## import qubes.qmemman.client # pylint: disable=wrong-import-position
##
## qmemman_present = True
##except ImportError:
## pass
from qubes.hypervisor import is_xen
if is_xen():
try:
import qubes.qmemman.client # pylint: disable=wrong-import-position

qmemman_present = True
except ImportError:
pass
qmemman_present = True
except ImportError:
pass
########

# overhead of per-qube/per-vcpu Xen structures,
# taken from OpenStack nova/virt/xenapi/driver.py
Expand Down
Loading