Merge branch 'hvm' of 10.141.1.101:/var/lib/qubes/git/marmarek/core

This commit is contained in:
Joanna Rutkowska 2012-02-27 13:17:48 +01:00
commit 859c99da5c
10 changed files with 436 additions and 54 deletions

View File

@ -0,0 +1,32 @@
#
# This is a Xen VM config file for Qubes VM
# DO NOT EDIT - autogenerated by qubes tools
#
name = "{name}"
builder='hvm'
memory={mem}
viridian=1
kernel='hvmloader'
#acpi=1
#apic=1
boot='dca'
device_model='stubdom-dm'
#pae=1
usbdevice='tablet'
sdl=0
vnc=0
disk = [ {rootdev}
{otherdevs}
]
vif = [ {netdev} ]
pci = [ {pcidev} ]
vcpus = {vcpus}
#tsc_mode = 2
#xen_extended_power_mgmt=0
on_poweroff = 'destroy'
on_reboot = 'destroy'
on_crash = 'destroy'

View File

@ -21,6 +21,7 @@
# #
import sys import sys
import stat
import os import os
import os.path import os.path
import subprocess import subprocess
@ -78,6 +79,11 @@ default_servicevm_vcpus = 1
default_kernelopts = "" default_kernelopts = ""
default_kernelopts_pcidevs = "iommu=soft swiotlb=2048" default_kernelopts_pcidevs = "iommu=soft swiotlb=2048"
default_hvm_disk_size = 20*1024*1024*1024
config_template_pv = '/usr/share/qubes/vm-template.conf'
config_template_hvm = '/usr/share/qubes/vm-template-hvm.conf'
qubes_whitelisted_appmenus = 'whitelisted-appmenus.list' qubes_whitelisted_appmenus = 'whitelisted-appmenus.list'
dom0_update_check_interval = 6*3600 dom0_update_check_interval = 6*3600
@ -238,6 +244,8 @@ class QubesVm(object):
self.firewall_conf = self.absolute_path(firewall_conf, default_firewall_conf_file) self.firewall_conf = self.absolute_path(firewall_conf, default_firewall_conf_file)
self.config_file_template = config_template_pv
self.updateable = updateable self.updateable = updateable
self._label = label if label is not None else QubesVmLabels["red"] self._label = label if label is not None else QubesVmLabels["red"]
if self.dir_path is not None: if self.dir_path is not None:
@ -788,7 +796,8 @@ class QubesVm(object):
def get_config_params(self, source_template=None): def get_config_params(self, source_template=None):
args = {} args = {}
args['name'] = self.name args['name'] = self.name
args['kerneldir'] = self.kernels_dir if hasattr(self, 'kernels_dir'):
args['kerneldir'] = self.kernels_dir
args['vmdir'] = self.dir_path args['vmdir'] = self.dir_path
args['pcidev'] = str(self.pcidevs).strip('[]') args['pcidev'] = str(self.pcidevs).strip('[]')
args['mem'] = str(self.memory) args['mem'] = str(self.memory)
@ -804,11 +813,13 @@ class QubesVm(object):
args['rootdev'] = self.get_rootdev(source_template=source_template) args['rootdev'] = self.get_rootdev(source_template=source_template)
args['privatedev'] = "'script:file:{dir}/private.img,xvdb,w',".format(dir=self.dir_path) args['privatedev'] = "'script:file:{dir}/private.img,xvdb,w',".format(dir=self.dir_path)
args['volatiledev'] = "'script:file:{dir}/volatile.img,xvdc,w',".format(dir=self.dir_path) args['volatiledev'] = "'script:file:{dir}/volatile.img,xvdc,w',".format(dir=self.dir_path)
modulesmode='r' if hasattr(self, 'kernel'):
if self.is_updateable() and self.kernel is None: modulesmode='r'
modulesmode='w' if self.is_updateable() and self.kernel is None:
args['otherdevs'] = "'script:file:{dir}/modules.img,xvdd,{mode}',".format(dir=self.kernels_dir, mode=modulesmode) modulesmode='w'
args['kernelopts'] = self.kernelopts args['otherdevs'] = "'script:file:{dir}/modules.img,xvdd,{mode}',".format(dir=self.kernels_dir, mode=modulesmode)
if hasattr(self, 'kernelopts'):
args['kernelopts'] = self.kernelopts
return args return args
@ -818,7 +829,7 @@ class QubesVm(object):
if source_template is None: if source_template is None:
source_template = self.template_vm source_template = self.template_vm
f_conf_template = open('/usr/share/qubes/vm-template.conf', 'r') f_conf_template = open(self.config_file_template, 'r')
conf_template = f_conf_template.read() conf_template = f_conf_template.read()
f_conf_template.close() f_conf_template.close()
@ -1163,6 +1174,14 @@ class QubesVm(object):
if notify_function is not None: if notify_function is not None:
notify_function("error", "ERROR: Cannot start the Qubes Clipboard Notifier!") notify_function("error", "ERROR: Cannot start the Qubes Clipboard Notifier!")
def start_qrexec_daemon(self, verbose = False):
if verbose:
print >> sys.stderr, "--> Starting the qrexec daemon..."
retcode = subprocess.call ([qrexec_daemon_path, str(xid)])
if (retcode != 0) :
self.force_shutdown()
raise OSError ("ERROR: Cannot execute qrexec_daemon!")
def start(self, debug_console = False, verbose = False, preparing_dvm = False): def start(self, debug_console = False, verbose = False, preparing_dvm = False):
if dry_run: if dry_run:
return return
@ -1234,12 +1253,7 @@ class QubesVm(object):
qmemman_client.close() qmemman_client.close()
if not preparing_dvm: if not preparing_dvm:
if verbose: self.start_qrexec_daemon(verbose=verbose)
print >> sys.stderr, "--> Starting the qrexec daemon..."
retcode = subprocess.call ([qrexec_daemon_path, str(xid)])
if (retcode != 0) :
self.force_shutdown()
raise OSError ("ERROR: Cannot execute qrexec_daemon!")
if not preparing_dvm and os.path.exists('/var/run/shm.id'): if not preparing_dvm and os.path.exists('/var/run/shm.id'):
self.start_guid(verbose=verbose) self.start_guid(verbose=verbose)
@ -1285,26 +1299,20 @@ class QubesVm(object):
attrs["qid"] = str(self.qid) attrs["qid"] = str(self.qid)
attrs["name"] = self.name attrs["name"] = self.name
attrs["dir_path"] = self.dir_path attrs["dir_path"] = self.dir_path
attrs["conf_file"] = self.relative_path(self.conf_file) # Simple paths
attrs["root_img"] = self.relative_path(self.root_img) for prop in ['conf_file', 'root_img', 'volatile_img', 'private_img']:
attrs["volatile_img"] = self.relative_path(self.volatile_img) if hasattr(self, prop):
attrs["private_img"] = self.relative_path(self.private_img) attrs[prop] = self.relative_path(self.__getattribute__(prop))
attrs["uses_default_netvm"] = str(self.uses_default_netvm) # Simple string attrs
for prop in ['memory', 'maxmem', 'pcidevs', 'vcpus', 'internal',\
'uses_default_kernel', 'kernel', 'uses_default_kernelopts',\
'kernelopts', 'services', 'updateable', 'installed_by_rpm',\
'uses_default_netvm' ]:
if hasattr(self, prop):
attrs[prop] = str(self.__getattribute__(prop))
attrs["netvm_qid"] = str(self.netvm_vm.qid) if self.netvm_vm is not None else "none" attrs["netvm_qid"] = str(self.netvm_vm.qid) if self.netvm_vm is not None else "none"
attrs["installed_by_rpm"] = str(self.installed_by_rpm)
attrs["template_qid"] = str(self.template_vm.qid) if self.template_vm and not self.is_updateable() else "none" attrs["template_qid"] = str(self.template_vm.qid) if self.template_vm and not self.is_updateable() else "none"
attrs["updateable"] = str(self.updateable)
attrs["label"] = self.label.name attrs["label"] = self.label.name
attrs["memory"] = str(self.memory)
attrs["maxmem"] = str(self.maxmem)
attrs["pcidevs"] = str(self.pcidevs)
attrs["vcpus"] = str(self.vcpus)
attrs["internal"] = str(self.internal)
attrs["uses_default_kernel"] = str(self.uses_default_kernel)
attrs["kernel"] = str(self.kernel)
attrs["uses_default_kernelopts"] = str(self.uses_default_kernelopts)
attrs["kernelopts"] = str(self.kernelopts)
attrs["services"] = str(self.services)
return attrs return attrs
def create_xml_element(self): def create_xml_element(self):
@ -1988,6 +1996,127 @@ class QubesAppVm(QubesVm):
def post_rename(self, old_name): def post_rename(self, old_name):
self.create_appmenus(False) self.create_appmenus(False)
class QubesHVm(QubesVm):
"""
A class that represents an HVM. A child of QubesVm.
"""
# FIXME: logically should inherit after QubesAppVm, but none of its methods
# are useful for HVM
def __init__(self, **kwargs):
if "dir_path" not in kwargs or kwargs["dir_path"] is None:
kwargs["dir_path"] = qubes_appvms_dir + "/" + kwargs["name"]
super(QubesHVm, self).__init__(**kwargs)
self.updateable = True
self.config_file_template = config_template_hvm
# remove settings not used by HVM (at least for now)
self.__delattr__('kernel')
self.__delattr__('kernelopts')
self.__delattr__('uses_default_kernel')
self.__delattr__('uses_default_kernelopts')
self.__delattr__('private_img')
self.__delattr__('volatile_img')
# HVM doesn't support dynamic memory management
self.maxmem = self.memory
self.drive = None
if 'drive' in kwargs.keys():
self.drive = kwargs['drive']
@property
def type(self):
return "HVM"
def is_appvm(self):
return True
def create_on_disk(self, verbose, source_template = None):
if dry_run:
return
if verbose:
print >> sys.stderr, "--> Creating directory: {0}".format(self.dir_path)
os.mkdir (self.dir_path)
self.create_config_file()
# create empty disk
f_root = open(self.root_img, "w")
f_root.truncate(default_hvm_disk_size)
f_root.close()
def get_disk_utilization_private_img(self):
return 0
def get_private_img_sz(self):
return 0
def resize_private_img(self, size):
raise NotImplementedError("HVM has no private.img")
def get_config_params(self, source_template=None):
params = super(QubesHVm, self).get_config_params(source_template=source_template)
params['volatiledev'] = ''
params['privatedev'] = ''
if self.drive:
stat_res = os.stat(self.drive)
if stat.S_ISBLK(stat_res.st_mode):
params['otherdevs'] = "'phy:%s,hdc:cdrom,r'," % self.drive
else:
params['otherdevs'] = "'script:file:%s,hdc:cdrom,r'," % self.drive
else:
params['otherdevs'] = ''
return params
def verify_files(self):
if dry_run:
return
if not os.path.exists (self.dir_path):
raise QubesException (
"VM directory doesn't exist: {0}".\
format(self.dir_path))
if self.is_updateable() and not os.path.exists (self.root_img):
raise QubesException (
"VM root image file doesn't exist: {0}".\
format(self.root_img))
return True
def reset_volatile_storage(self, **kwargs):
pass
def run(self, command, **kwargs):
raise NotImplementedError("Needs qrexec agent - TODO")
@property
def stubdom_xid(self):
if not self.is_running():
return -1
return int(xs.read('', '/local/domain/%d/image/device-model-domid' % self.xid))
def start_guid(self, verbose = True, notify_function = None):
if verbose:
print >> sys.stderr, "--> Starting Qubes GUId..."
retcode = subprocess.call ([qubes_guid_path, "-d", str(self.stubdom_xid), "-c", self.label.color, "-i", self.label.icon, "-l", str(self.label.index)])
if (retcode != 0) :
raise QubesException("Cannot start qubes_guid!")
def start_qrexec_daemon(self, **kwargs):
pass
def get_xml_attrs(self):
attrs = super(QubesHVm, self).get_xml_attrs()
attrs["drive"] = str(self.drive)
return attrs
class QubesVmCollection(dict): class QubesVmCollection(dict):
""" """
@ -2046,6 +2175,20 @@ class QubesVmCollection(dict):
self[vm.qid]=vm self[vm.qid]=vm
return vm return vm
def add_new_hvm(self, name, label = None):
qid = self.get_new_unused_qid()
vm = QubesHVm (qid=qid, name=name,
netvm_vm = self.get_default_netvm_vm(),
kernel = self.get_default_kernel(),
uses_default_kernel = True,
label=label)
if not self.verify_new_vm (vm):
assert False, "Wrong VM description!"
self[vm.qid]=vm
return vm
def add_new_disposablevm(self, name, template_vm, dispid, def add_new_disposablevm(self, name, template_vm, dispid,
label = None): label = None):
@ -2571,6 +2714,20 @@ class QubesVmCollection(dict):
os.path.basename(sys.argv[0]), err)) os.path.basename(sys.argv[0]), err))
return False return False
# And HVMs
for element in tree.findall("QubesHVm"):
try:
kwargs = self.parse_xml_element(element)
vm = QubesHVm(**kwargs)
self[vm.qid] = vm
self.set_netvm_dependency(element)
except (ValueError, LookupError) as err:
print("{0}: import error (QubesHVm): {1}".format(
os.path.basename(sys.argv[0]), err))
return False
# Really finally, read in the DisposableVMs # Really finally, read in the DisposableVMs
for element in tree.findall("QubesDisposableVm"): for element in tree.findall("QubesDisposableVm"):
try: try:

View File

@ -37,10 +37,14 @@ def main():
help="Specify the label to use for the new VM (e.g. red, yellow, green, ...)") help="Specify the label to use for the new VM (e.g. red, yellow, green, ...)")
parser.add_option ("-p", "--proxy", action="store_true", dest="proxyvm", default=False, parser.add_option ("-p", "--proxy", action="store_true", dest="proxyvm", default=False,
help="Create ProxyVM") help="Create ProxyVM")
parser.add_option ("-H", "--hvm", action="store_true", dest="hvm", default=False,
help="Create HVM (implies --standalone)")
parser.add_option ("-n", "--net", action="store_true", dest="netvm", default=False, parser.add_option ("-n", "--net", action="store_true", dest="netvm", default=False,
help="Create NetVM") help="Create NetVM")
parser.add_option ("-s", "--standalone", action="store_true", dest="standalone", default=False, parser.add_option ("-s", "--standalone", action="store_true", dest="standalone", default=False,
help="Create standalone VM - independent of template ") help="Create standalone VM - independent of template ")
parser.add_option ("-r", "--root", dest="root", default=None,
help="Use provided root.img instead of default/empty one (file will be MOVED)")
parser.add_option ("-m", "--mem", dest="mem", default=None, parser.add_option ("-m", "--mem", dest="mem", default=None,
help="Initial memory size (in MB)") help="Initial memory size (in MB)")
parser.add_option ("-c", "--vcpus", dest="vcpus", default=None, parser.add_option ("-c", "--vcpus", dest="vcpus", default=None,
@ -82,6 +86,18 @@ def main():
exit (1) exit (1)
label = QubesVmLabels[options.label] label = QubesVmLabels[options.label]
if options.hvm:
# Only standalone HVMs are supported for now
options.standalone = True
if not options.standalone and options.root is not None:
print >> sys.stderr, "root.img can be specified only for standalone VMs"
exit (1)
if options.root is not None and not os.path.exists(options.root):
print >> sys.stderr, "File specified as root.img does not exists"
exit (1)
qvm_collection = QubesVmCollection() qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_writing() qvm_collection.lock_db_for_writing()
qvm_collection.load() qvm_collection.load()
@ -90,6 +106,7 @@ def main():
print >> sys.stderr, "A VM with the name '{0}' already exists in the system.".format(vmname) print >> sys.stderr, "A VM with the name '{0}' already exists in the system.".format(vmname)
exit(1) exit(1)
template_vm = None
if options.template is not None: if options.template is not None:
template_vm = qvm_collection.get_vm_by_name(options.template) template_vm = qvm_collection.get_vm_by_name(options.template)
if template_vm is None: if template_vm is None:
@ -101,7 +118,7 @@ def main():
if (options.verbose): if (options.verbose):
print "--> Using TemplateVM: {0}".format(template_vm.name) print "--> Using TemplateVM: {0}".format(template_vm.name)
else: elif not options.hvm:
if qvm_collection.get_default_template_vm() is None: if qvm_collection.get_default_template_vm() is None:
print >> sys.stderr, "No default TempleteVM defined!" print >> sys.stderr, "No default TempleteVM defined!"
exit (1) exit (1)
@ -120,6 +137,8 @@ def main():
vm = qvm_collection.add_new_netvm(vmname, new_vm_template, label = label, updateable = options.standalone) vm = qvm_collection.add_new_netvm(vmname, new_vm_template, label = label, updateable = options.standalone)
elif options.proxyvm: elif options.proxyvm:
vm = qvm_collection.add_new_proxyvm(vmname, new_vm_template, label = label, updateable = options.standalone) vm = qvm_collection.add_new_proxyvm(vmname, new_vm_template, label = label, updateable = options.standalone)
elif options.hvm:
vm = qvm_collection.add_new_hvm(vmname, label = label)
else: else:
vm = qvm_collection.add_new_appvm(vmname, new_vm_template, label = label, updateable = options.standalone) vm = qvm_collection.add_new_appvm(vmname, new_vm_template, label = label, updateable = options.standalone)
@ -134,6 +153,9 @@ def main():
try: try:
vm.create_on_disk(verbose=options.verbose, source_template=template_vm) vm.create_on_disk(verbose=options.verbose, source_template=template_vm)
if options.root:
os.unlink(vm.root_img)
os.rename(options.root, vm.root_img)
except (IOError, OSError) as err: except (IOError, OSError) as err:
print >> sys.stderr, "ERROR: {0}".format(err) print >> sys.stderr, "ERROR: {0}".format(err)

View File

@ -51,22 +51,32 @@ def do_list(vm):
print fmt.format ("root COW img", vm.rootcow_img) print fmt.format ("root COW img", vm.rootcow_img)
if vm.template_vm is not None: if vm.template_vm is not None:
print fmt.format ("root img", vm.template_vm.root_img) print fmt.format ("root img", vm.template_vm.root_img)
print fmt.format ("root volatile img", vm.volatile_img) if hasattr(vm, 'volatile_img'):
print fmt.format ("root volatile img", vm.volatile_img)
print fmt.format ("private img", vm.private_img) if hasattr(vm, 'private_img'):
print fmt.format ("private img", vm.private_img)
print fmt.format ("vcpus", str(vm.vcpus)) print fmt.format ("vcpus", str(vm.vcpus))
print fmt.format ("memory", vm.memory) print fmt.format ("memory", vm.memory)
print fmt.format ("maxmem", vm.maxmem) if hasattr(vm, 'maxmem'):
if vm.template_vm is not None: print fmt.format ("maxmem", vm.maxmem)
print fmt.format ("kernel", "%s (from template)" % vm.kernel)
elif vm.uses_default_kernel: if hasattr(vm, 'kernel'):
print fmt.format ("kernel", "%s (default)" % vm.kernel) if vm.template_vm is not None:
else: print fmt.format ("kernel", "%s (from template)" % vm.kernel)
print fmt.format ("kernel", vm.kernel) elif vm.uses_default_kernel:
if vm.uses_default_kernelopts: print fmt.format ("kernel", "%s (default)" % vm.kernel)
print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts) else:
else: print fmt.format ("kernel", vm.kernel)
print fmt.format ("kernelopts", vm.kernelopts)
if hasattr(vm, 'kernelopts'):
if vm.uses_default_kernelopts:
print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts)
else:
print fmt.format ("kernelopts", vm.kernelopts)
if hasattr(vm, 'drive'):
print fmt.format("drive", str(vm.drive))
def set_label(vms, vm, args): def set_label(vms, vm, args):
@ -287,6 +297,13 @@ def set_name(vms, vm, args):
vm.set_name(args[0]) vm.set_name(args[0])
return True return True
def set_drive(vms, vm, args):
if len (args) != 1:
print >> sys.stderr, "Missing new drive content (file/device)!"
return False
vm.drive = args[0]
return True
properties = { properties = {
"updateable": set_updateable, "updateable": set_updateable,
@ -301,6 +318,7 @@ properties = {
"vcpus" : set_vcpus, "vcpus" : set_vcpus,
"kernelopts": set_kernelopts, "kernelopts": set_kernelopts,
"name": set_name, "name": set_name,
"drive": set_drive,
} }
@ -309,6 +327,10 @@ def do_set(vms, vm, property, args):
print >> sys.stderr, "ERROR: Wrong property name: '{0}'".format(property) print >> sys.stderr, "ERROR: Wrong property name: '{0}'".format(property)
return False return False
if not hasattr(vm, property):
print >> sys.stderr, "ERROR: Property '{0}' not available for this VM".format(property)
return False
return properties[property](vms, vm, args) return properties[property](vms, vm, args)
@ -353,7 +375,8 @@ def main():
print >> sys.stderr, "You must specify the property you wish to set..." print >> sys.stderr, "You must specify the property you wish to set..."
print >> sys.stderr, "Available properties:" print >> sys.stderr, "Available properties:"
for p in properties.keys(): for p in properties.keys():
print >> sys.stderr, "--> '{0}'".format(p) if hasattr(vm, p):
print >> sys.stderr, "--> '{0}'".format(p)
exit (1) exit (1)
property = args[1] property = args[1]

View File

@ -37,6 +37,8 @@ def main():
help="Do not start the GUId (ignored)") help="Do not start the GUId (ignored)")
parser.add_option ("--console", action="store_true", dest="debug_console", default=False, parser.add_option ("--console", action="store_true", dest="debug_console", default=False,
help="Attach debugging console to the newly started VM") help="Attach debugging console to the newly started VM")
parser.add_option ("--drive", dest="drive", default=None,
help="Temporarily attach specified drive as CD/DVD")
parser.add_option ("--dvm", action="store_true", dest="preparing_dvm", default=False, parser.add_option ("--dvm", action="store_true", dest="preparing_dvm", default=False,
help="Do actions necessary when preparing DVM image") help="Do actions necessary when preparing DVM image")
@ -55,6 +57,13 @@ def main():
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname) print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
exit(1) exit(1)
if options.drive:
if hasattr(vm, 'drive'):
vm.drive = options.drive
else:
print >> sys.stderr, "This VM does not support attaching drives"
exit (1)
try: try:
vm.verify_files() vm.verify_files()
xid = vm.start(debug_console=options.debug_console, verbose=options.verbose, preparing_dvm=options.preparing_dvm) xid = vm.start(debug_console=options.debug_console, verbose=options.verbose, preparing_dvm=options.preparing_dvm)

View File

@ -151,6 +151,7 @@ cp misc/qubes-vm.directory.template $RPM_BUILD_ROOT/usr/share/qubes/
cp misc/qubes-templatevm.directory.template $RPM_BUILD_ROOT/usr/share/qubes/ cp misc/qubes-templatevm.directory.template $RPM_BUILD_ROOT/usr/share/qubes/
cp misc/qubes-appmenu-select.desktop $RPM_BUILD_ROOT/usr/share/qubes/ cp misc/qubes-appmenu-select.desktop $RPM_BUILD_ROOT/usr/share/qubes/
cp misc/vm-template.conf $RPM_BUILD_ROOT/usr/share/qubes/ cp misc/vm-template.conf $RPM_BUILD_ROOT/usr/share/qubes/
cp misc/vm-template-hvm.conf $RPM_BUILD_ROOT/usr/share/qubes/
mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/bin
cp ../network/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes cp ../network/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes
@ -344,6 +345,7 @@ fi
/usr/share/qubes/qubes-templatevm.directory.template /usr/share/qubes/qubes-templatevm.directory.template
/usr/share/qubes/qubes-appmenu-select.desktop /usr/share/qubes/qubes-appmenu-select.desktop
/usr/share/qubes/vm-template.conf /usr/share/qubes/vm-template.conf
/usr/share/qubes/vm-template-hvm.conf
/usr/lib/qubes/qubes_setup_dnat_to_ns /usr/lib/qubes/qubes_setup_dnat_to_ns
/usr/lib/qubes/qubes_fix_nm_conf.sh /usr/lib/qubes/qubes_fix_nm_conf.sh
/etc/dhclient.d/qubes_setup_dnat_to_ns.sh /etc/dhclient.d/qubes_setup_dnat_to_ns.sh

36
vchan/Makefile.stubdom Normal file
View File

@ -0,0 +1,36 @@
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2012 Marek Marczykowski <marmarek@invisiblethingslab.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# Assume it is placed as xen-root/tools/vchan
XEN_ROOT = ../..
include $(XEN_ROOT)/tools/Rules.mk
CFLAGS+=-Wall -I$(XEN_ROOT)/tools/libxc -DCONFIG_STUBDOM
all: libvchan.a
libvchan.a: init.o io.o
$(AR) rc $@ $^
clean:
rm -f *.o *so *~ client server node node-select

View File

@ -19,6 +19,9 @@
* *
*/ */
#include <sys/types.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@ -29,25 +32,38 @@
#include <xenctrl.h> #include <xenctrl.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <mm.h>
#include "libvchan.h" #include "libvchan.h"
#ifndef CONFIG_STUBDOM
#include "../u2mfn/u2mfnlib.h" #include "../u2mfn/u2mfnlib.h"
#endif
static int ring_init(struct libvchan *ctrl) static int ring_init(struct libvchan *ctrl)
{ {
int u2mfn = open("/proc/u2mfn", O_RDONLY);
int mfn; int mfn;
struct vchan_interface *ring; struct vchan_interface *ring;
#ifdef CONFIG_STUBDOM
ring = (struct vchan_interface *) memalign(XC_PAGE_SIZE, sizeof(*ring));
if (!ring)
return -1;
mfn = virtual_to_mfn(ring);
#else
int u2mfn = open("/proc/u2mfn", O_RDONLY);
ring = (struct vchan_interface *) u2mfn_alloc_kpage (); ring = (struct vchan_interface *) u2mfn_alloc_kpage ();
if (ring == MAP_FAILED) if (ring == MAP_FAILED)
return -1; return -1;
ctrl->ring = ring;
if (u2mfn_get_last_mfn (&mfn) < 0) if (u2mfn_get_last_mfn (&mfn) < 0)
return -1; return -1;
ctrl->ring_ref = mfn;
close(u2mfn); close(u2mfn);
#endif
ctrl->ring = ring;
ctrl->ring_ref = mfn;
ring->cons_in = ring->prod_in = ring->cons_out = ring->prod_out = ring->cons_in = ring->prod_in = ring->cons_out = ring->prod_out =
0; 0;
ring->server_closed = ring->client_closed = 0; ring->server_closed = ring->client_closed = 0;
@ -65,13 +81,18 @@ static int server_interface_init(struct libvchan *ctrl, int devno)
struct xs_handle *xs; struct xs_handle *xs;
char buf[64]; char buf[64];
char ref[16]; char ref[16];
/* XXX temp hack begin */
char *domid_s;
int domid = 0;
unsigned int len;
/* XXX temp hack end */
#ifdef XENCTRL_HAS_XC_INTERFACE #ifdef XENCTRL_HAS_XC_INTERFACE
xc_evtchn *evfd; xc_evtchn *evfd;
#else #else
int evfd; int evfd;
#endif #endif
evtchn_port_or_error_t port; evtchn_port_or_error_t port;
xs = xs_domain_open(); xs = xs_daemon_open();
if (!xs) { if (!xs) {
return ret; return ret;
} }
@ -90,20 +111,41 @@ static int server_interface_init(struct libvchan *ctrl, int devno)
if (port < 0) if (port < 0)
goto fail2; goto fail2;
ctrl->evport = port; ctrl->evport = port;
ctrl->devno = devno;
// stubdom debug HACK XXX
domid_s = xs_read(xs, 0, "domid", &len);
if (domid_s)
domid = atoi(domid_s);
snprintf(ref, sizeof ref, "%d", ctrl->ring_ref); snprintf(ref, sizeof ref, "%d", ctrl->ring_ref);
snprintf(buf, sizeof buf, "device/vchan/%d/ring-ref", devno); snprintf(buf, sizeof buf, "device/vchan/%d/ring-ref", devno);
if (!xs_write(xs, 0, buf, ref, strlen(ref))) if (!xs_write(xs, 0, buf, ref, strlen(ref)))
#ifdef CONFIG_STUBDOM
// TEMP HACK XXX FIXME goto fail2;
fprintf(stderr, "xenstore-write /local/domain/%d/%s %s\n", domid, buf, ref);
#else
goto fail2; goto fail2;
#endif
snprintf(ref, sizeof ref, "%d", ctrl->evport); snprintf(ref, sizeof ref, "%d", ctrl->evport);
snprintf(buf, sizeof buf, "device/vchan/%d/event-channel", devno); snprintf(buf, sizeof buf, "device/vchan/%d/event-channel", devno);
if (!xs_write(xs, 0, buf, ref, strlen(ref))) if (!xs_write(xs, 0, buf, ref, strlen(ref)))
#ifdef CONFIG_STUBDOM
// TEMP HACK XXX FIXME goto fail2;
fprintf(stderr, "xenstore-write /local/domain/%d/%s %s\n", domid, buf, ref);
#else
goto fail2; goto fail2;
#endif
// do not block in stubdom - libvchan_server_handle_connected will be
// called on first input
#ifndef CONFIG_STUBDOM
// wait for the peer to arrive // wait for the peer to arrive
if (xc_evtchn_pending(evfd) == -1) if (xc_evtchn_pending(evfd) == -1)
goto fail2; goto fail2;
xc_evtchn_unmask(ctrl->evfd, ctrl->evport); xc_evtchn_unmask(ctrl->evfd, ctrl->evport);
snprintf(buf, sizeof buf, "device/vchan/%d", devno); snprintf(buf, sizeof buf, "device/vchan/%d", devno);
xs_rm(xs, 0, buf); xs_rm(xs, 0, buf);
#endif
ret = 0; ret = 0;
fail2: fail2:
@ -129,8 +171,8 @@ static int server_interface_init(struct libvchan *ctrl, int devno)
ctrl->rd_ring_size = sizeof(ctrl->ring->buf_##dir2) ctrl->rd_ring_size = sizeof(ctrl->ring->buf_##dir2)
/** /**
Run in AppVM (any domain). Run in AppVM (any domain).
Sleeps until the connection is established. Sleeps until the connection is established. (unless in stubdom)
\param devno something like a well-known port. \param devno something like a well-known port.
\returns NULL on failure, handle on success \returns NULL on failure, handle on success
*/ */
@ -156,6 +198,39 @@ struct libvchan *libvchan_server_init(int devno)
return ctrl; return ctrl;
} }
int libvchan_server_handle_connected(struct libvchan *ctrl)
{
struct xs_handle *xs;
char buf[64];
int ret = -1;
int libvchan_fd;
fd_set rfds;
xs = xs_daemon_open();
if (!xs) {
return ret;
}
// clear the pending flag
xc_evtchn_pending(ctrl->evfd);
snprintf(buf, sizeof buf, "device/vchan/%d", ctrl->devno);
xs_rm(xs, 0, buf);
ret = 0;
#if 0
fail2:
if (ret)
#ifdef XENCTRL_HAS_XC_INTERFACE
xc_evtchn_close(ctrl->evfd);
#else
close(ctrl->evfd);
#endif
#endif
xs_daemon_close(xs);
return ret;
}
/** /**
retrieves ring-ref and event-channel numbers from xenstore (if retrieves ring-ref and event-channel numbers from xenstore (if
they don't exist, return error, because nobody seems to listen); they don't exist, return error, because nobody seems to listen);
@ -250,7 +325,7 @@ static int client_interface_init(struct libvchan *ctrl, int domain, int devno)
/** /**
Run on the client side of connection (currently, must be dom0). Run on the client side of connection (currently, must be dom0).
\returns NULL on failure (e.g. noone listening), handle on success \returns NULL on failure (e.g. noone listening), handle on success
*/ */
struct libvchan *libvchan_client_init(int domain, int devno) struct libvchan *libvchan_client_init(int domain, int devno)
{ {
struct libvchan *ctrl = struct libvchan *ctrl =

View File

@ -22,6 +22,8 @@
#include "libvchan.h" #include "libvchan.h"
#include <xenctrl.h> #include <xenctrl.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <sys/select.h>
/** /**
\return How much data is immediately available for reading \return How much data is immediately available for reading
*/ */
@ -67,7 +69,24 @@ int libvchan_is_eof(struct libvchan *ctrl)
int libvchan_wait(struct libvchan *ctrl) int libvchan_wait(struct libvchan *ctrl)
{ {
int ret; int ret;
#ifndef CONFIG_STUBDOM
ret = xc_evtchn_pending(ctrl->evfd); ret = xc_evtchn_pending(ctrl->evfd);
#else
int vchan_fd = libvchan_fd_for_select(ctrl);
fd_set rfds;
libvchan_prepare_to_select(ctrl);
while ((ret = xc_evtchn_pending(ctrl->evfd)) < 0) {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(vchan_fd, &rfds);
ret = select(vchan_fd + 1, &rfds, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR) {
perror("select");
return ret;
}
}
#endif
if (ret!=-1 && xc_evtchn_unmask(ctrl->evfd, ctrl->evport)) if (ret!=-1 && xc_evtchn_unmask(ctrl->evfd, ctrl->evport))
return -1; return -1;
if (ret!=-1 && libvchan_is_eof(ctrl)) if (ret!=-1 && libvchan_is_eof(ctrl))

View File

@ -19,6 +19,9 @@
* *
*/ */
#ifndef _LIBVCHAN_H
#define _LIBVCHAN_H
#include <stdint.h> #include <stdint.h>
#include <xenctrl.h> #include <xenctrl.h>
typedef uint32_t VCHAN_RING_IDX; typedef uint32_t VCHAN_RING_IDX;
@ -44,6 +47,7 @@ struct libvchan {
int evfd; int evfd;
#endif #endif
int evport; int evport;
int devno;
VCHAN_RING_IDX *wr_cons, *wr_prod, *rd_cons, *rd_prod; VCHAN_RING_IDX *wr_cons, *wr_prod, *rd_cons, *rd_prod;
char *rd_ring, *wr_ring; char *rd_ring, *wr_ring;
int rd_ring_size, wr_ring_size; int rd_ring_size, wr_ring_size;
@ -51,6 +55,7 @@ struct libvchan {
}; };
struct libvchan *libvchan_server_init(int devno); struct libvchan *libvchan_server_init(int devno);
int libvchan_server_handle_connected(struct libvchan *ctrl);
struct libvchan *libvchan_client_init(int domain, int devno); struct libvchan *libvchan_client_init(int domain, int devno);
@ -63,3 +68,5 @@ int libvchan_fd_for_select(struct libvchan *ctrl);
int libvchan_is_eof(struct libvchan *ctrl); int libvchan_is_eof(struct libvchan *ctrl);
int libvchan_data_ready(struct libvchan *ctrl); int libvchan_data_ready(struct libvchan *ctrl);
int libvchan_buffer_space(struct libvchan *ctrl); int libvchan_buffer_space(struct libvchan *ctrl);
#endif /* _LIBVCHAN_H */