005QubesNetVm.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #!/usr/bin/python2
  2. # -*- coding: utf-8 -*-
  3. #
  4. # The Qubes OS Project, http://www.qubes-os.org
  5. #
  6. # Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
  7. # Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
  8. #
  9. # This program is free software; you can redistribute it and/or
  10. # modify it under the terms of the GNU General Public License
  11. # as published by the Free Software Foundation; either version 2
  12. # of the License, or (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. #
  23. #
  24. import sys
  25. import os.path
  26. import xen.lowlevel.xs
  27. from qubes.qubes import QubesVm,register_qubes_vm_class,vmm,dry_run
  28. from qubes.qubes import defaults,system_path,vm_files
  29. from qubes.qubes import QubesVmCollection,QubesException
  30. class QubesNetVm(QubesVm):
  31. """
  32. A class that represents a NetVM. A child of QubesCowVM.
  33. """
  34. # In which order load this VM type from qubes.xml
  35. load_order = 70
  36. def get_attrs_config(self):
  37. attrs_config = super(QubesNetVm, self).get_attrs_config()
  38. attrs_config['dir_path']['func'] = \
  39. lambda value: value if value is not None else \
  40. os.path.join(system_path["qubes_servicevms_dir"], self.name)
  41. attrs_config['label']['default'] = defaults["servicevm_label"]
  42. attrs_config['memory']['default'] = 300
  43. # New attributes
  44. attrs_config['netid'] = {
  45. 'save': lambda: str(self.netid),
  46. 'order': 30,
  47. 'func': lambda value: value if value is not None else
  48. self._collection.get_new_unused_netid() }
  49. attrs_config['netprefix'] = {
  50. 'func': lambda x: "10.137.{0}.".format(self.netid) }
  51. attrs_config['dispnetprefix'] = {
  52. 'func': lambda x: "10.138.{0}.".format(self.netid) }
  53. # Dont save netvm prop
  54. attrs_config['netvm'].pop('save')
  55. attrs_config['uses_default_netvm'].pop('save')
  56. return attrs_config
  57. def __init__(self, **kwargs):
  58. super(QubesNetVm, self).__init__(**kwargs)
  59. self.connected_vms = QubesVmCollection()
  60. self.__network = "10.137.{0}.0".format(self.netid)
  61. self.__netmask = defaults["vm_default_netmask"]
  62. self.__gateway = self.netprefix + "1"
  63. self.__secondary_dns = self.netprefix + "254"
  64. self.__external_ip_allowed_xids = set()
  65. self.log.debug('network={} netmask={} gateway={} secondary_dns={}'.format(
  66. self.network, self.netmask, self.gateway, self.secondary_dns))
  67. @property
  68. def type(self):
  69. return "NetVM"
  70. def is_netvm(self):
  71. return True
  72. @property
  73. def gateway(self):
  74. return self.__gateway
  75. @property
  76. def secondary_dns(self):
  77. return self.__secondary_dns
  78. @property
  79. def netmask(self):
  80. return self.__netmask
  81. @property
  82. def network(self):
  83. return self.__network
  84. def get_ip_for_vm(self, qid):
  85. lo = qid % 253 + 2
  86. assert lo >= 2 and lo <= 254, "Wrong IP address for VM"
  87. return self.netprefix + "{0}".format(lo)
  88. def get_ip_for_dispvm(self, dispid):
  89. lo = dispid % 254 + 1
  90. assert lo >= 1 and lo <= 254, "Wrong IP address for VM"
  91. return self.dispnetprefix + "{0}".format(lo)
  92. def update_external_ip_permissions(self, xid = -1):
  93. # TODO: VMs in __external_ip_allowed_xids should be notified via RPC
  94. # service on exteran IP change
  95. pass
  96. def start(self, **kwargs):
  97. if dry_run:
  98. return
  99. xid=super(QubesNetVm, self).start(**kwargs)
  100. # Connect vif's of already running VMs
  101. for vm in self.connected_vms.values():
  102. if not vm.is_running():
  103. continue
  104. if 'verbose' in kwargs and kwargs['verbose']:
  105. print >> sys.stderr, "--> Attaching network to '{0}'...".format(vm.name)
  106. # Cleanup stale VIFs
  107. vm.cleanup_vifs()
  108. # force frontend to forget about this device
  109. # module actually will be loaded back by udev, as soon as network is attached
  110. try:
  111. vm.run("modprobe -r xen-netfront xennet", user="root")
  112. except:
  113. pass
  114. try:
  115. vm.attach_network(wait=False)
  116. except QubesException as ex:
  117. print >> sys.stderr, ("WARNING: Cannot attach to network to '{0}': {1}".format(vm.name, ex))
  118. return xid
  119. def shutdown(self, force=False):
  120. if dry_run:
  121. return
  122. connected_vms = [vm for vm in self.connected_vms.values() if vm.is_running()]
  123. if connected_vms and not force:
  124. raise QubesException("There are other VMs connected to this VM: " + str([vm.name for vm in connected_vms]))
  125. super(QubesNetVm, self).shutdown(force=force)
  126. def add_external_ip_permission(self, xid):
  127. if int(xid) < 0:
  128. return
  129. self.__external_ip_allowed_xids.add(int(xid))
  130. self.update_external_ip_permissions()
  131. def remove_external_ip_permission(self, xid):
  132. self.__external_ip_allowed_xids.discard(int(xid))
  133. self.update_external_ip_permissions()
  134. register_qubes_vm_class(QubesNetVm)