mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
Use uBridge for VirtualBox connections plus some cleaning. Ref #267.
This commit is contained in:
1 parent
d28fad223f
commit
d79fb231d3
20 files changed
+132
-88
No files matched your search
@@ -338,7 +338,7 @@ class BaseManager:
|
||||
|
||||
return False
|
||||
|
||||
def create_nio(self, executable, nio_settings):
|
||||
def create_nio(self, nio_settings):
|
||||
"""
|
||||
Creates a new NIO.
|
||||
|
||||
|
||||
@@ -544,8 +544,8 @@ class BaseNode:
|
||||
rport = m.get_free_udp_port(self.project)
|
||||
source_nio_settings = {'lport': lport, 'rhost': '127.0.0.1', 'rport': rport, 'type': 'nio_udp'}
|
||||
destination_nio_settings = {'lport': rport, 'rhost': '127.0.0.1', 'rport': lport, 'type': 'nio_udp'}
|
||||
source_nio = self.manager.create_nio(self.ubridge_path, source_nio_settings)
|
||||
destination_nio = self.manager.create_nio(self.ubridge_path, destination_nio_settings)
|
||||
source_nio = self.manager.create_nio(source_nio_settings)
|
||||
destination_nio = self.manager.create_nio(destination_nio_settings)
|
||||
log.info("{module}: '{name}' [{id}]:local UDP tunnel created between port {port1} and {port2}".format(module=self.manager.module_name,
|
||||
name=self.name,
|
||||
id=self.id,
|
||||
|
||||
@@ -1096,13 +1096,12 @@ class QemuVM(BaseNode):
|
||||
raise QemuError('Adapter {adapter_number} does not exist on QEMU VM "{name}"'.format(name=self._name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
if self.is_running():
|
||||
if self.ubridge:
|
||||
yield from self._add_ubridge_udp_connection("QEMU-{}-{}".format(self._id, adapter_number),
|
||||
self._local_udp_tunnels[adapter_number][1],
|
||||
nio)
|
||||
else:
|
||||
raise QemuError("Sorry, adding a link to a started Qemu VM is not supported without using uBridge.")
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._add_ubridge_udp_connection("QEMU-{}-{}".format(self._id, adapter_number),
|
||||
self._local_udp_tunnels[adapter_number][1],
|
||||
nio)
|
||||
elif self.is_running():
|
||||
raise QemuError("Sorry, adding a link to a started Qemu VM is not supported without using uBridge.")
|
||||
|
||||
adapter.add_nio(0, nio)
|
||||
log.info('QEMU VM "{name}" [{id}]: {nio} added to adapter {adapter_number}'.format(name=self._name,
|
||||
@@ -1126,11 +1125,10 @@ class QemuVM(BaseNode):
|
||||
raise QemuError('Adapter {adapter_number} does not exist on QEMU VM "{name}"'.format(name=self._name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
if self.is_running():
|
||||
if self.ubridge:
|
||||
yield from self._ubridge_send("bridge delete {name}".format(name="QEMU-{}-{}".format(self._id, adapter_number)))
|
||||
else:
|
||||
raise QemuError("Sorry, removing a link to a started Qemu VM is not supported without using uBridge.")
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send("bridge delete {name}".format(name="QEMU-{}-{}".format(self._id, adapter_number)))
|
||||
elif self.is_running():
|
||||
raise QemuError("Sorry, removing a link to a started Qemu VM is not supported without using uBridge.")
|
||||
|
||||
nio = adapter.get_nio(0)
|
||||
if isinstance(nio, NIOUDP):
|
||||
@@ -1171,7 +1169,7 @@ class QemuVM(BaseNode):
|
||||
|
||||
nio.startPacketCapture(output_file)
|
||||
|
||||
if self.is_running() and self.ubridge:
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send('bridge start_capture {name} "{output_file}"'.format(name="QEMU-{}-{}".format(self._id, adapter_number),
|
||||
output_file=output_file))
|
||||
|
||||
@@ -1198,7 +1196,7 @@ class QemuVM(BaseNode):
|
||||
|
||||
nio.stopPacketCapture()
|
||||
|
||||
if self.is_running() and self.ubridge:
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send('bridge stop_capture {name}'.format(name="QEMU-{}-{}".format(self._id, adapter_number)))
|
||||
|
||||
log.info("QEMU VM '{name}' [{id}]: stopping packet capture on adapter {adapter_number}".format(name=self.name,
|
||||
|
||||
@@ -59,6 +59,7 @@ class VirtualBoxVM(BaseNode):
|
||||
self._system_properties = {}
|
||||
self._telnet_server_thread = None
|
||||
self._serial_pipe = None
|
||||
self._local_udp_tunnels = {}
|
||||
|
||||
# VirtualBox settings
|
||||
self._adapters = adapters
|
||||
@@ -217,6 +218,15 @@ class VirtualBoxVM(BaseNode):
|
||||
# add a guest property to let the VM know about the GNS3 project directory
|
||||
yield from self.manager.execute("guestproperty", ["set", self._vmname, "ProjectDirInGNS3", self.working_dir])
|
||||
|
||||
if self.use_ubridge:
|
||||
yield from self._start_ubridge()
|
||||
for adapter_number in range(0, self._adapters):
|
||||
nio = self._ethernet_adapters[adapter_number].get_nio(0)
|
||||
if nio:
|
||||
yield from self._add_ubridge_udp_connection("VBOX-{}-{}".format(self._id, adapter_number),
|
||||
self._local_udp_tunnels[adapter_number][1],
|
||||
nio)
|
||||
|
||||
if self._enable_remote_console and self._console is not None:
|
||||
try:
|
||||
# wait for VirtualBox to create the pipe file.
|
||||
@@ -238,6 +248,7 @@ class VirtualBoxVM(BaseNode):
|
||||
"""
|
||||
|
||||
self._hw_virtualization = False
|
||||
yield from self._stop_ubridge()
|
||||
self._stop_remote_console()
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running" or vm_state == "paused" or vm_state == "stuck":
|
||||
@@ -426,6 +437,11 @@ class VirtualBoxVM(BaseNode):
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
|
||||
for udp_tunnel in self._local_udp_tunnels.values():
|
||||
self.manager.port_manager.release_udp_port(udp_tunnel[0].lport, self._project)
|
||||
self.manager.port_manager.release_udp_port(udp_tunnel[1].lport, self._project)
|
||||
self._local_udp_tunnels = {}
|
||||
|
||||
self.acpi_shutdown = False
|
||||
yield from self.stop()
|
||||
|
||||
@@ -774,7 +790,15 @@ class VirtualBoxVM(BaseNode):
|
||||
# set the backend to null to avoid a difference in the number of interfaces in the Guest.
|
||||
yield from self._modify_vm("--nic{} null".format(adapter_number + 1))
|
||||
yield from self._modify_vm("--cableconnected{} off".format(adapter_number + 1))
|
||||
nio = self._ethernet_adapters[adapter_number].get_nio(0)
|
||||
|
||||
if self.use_ubridge:
|
||||
# use a local UDP tunnel to connect to uBridge instead
|
||||
if adapter_number not in self._local_udp_tunnels:
|
||||
self._local_udp_tunnels[adapter_number] = self._create_local_udp_tunnel()
|
||||
nio = self._local_udp_tunnels[adapter_number][0]
|
||||
else:
|
||||
nio = self._ethernet_adapters[adapter_number].get_nio(0)
|
||||
|
||||
if nio:
|
||||
if not self._use_any_adapter and attachment not in ("none", "null", "generic"):
|
||||
raise VirtualBoxError("Attachment ({}) already configured on adapter {}. "
|
||||
@@ -916,22 +940,27 @@ class VirtualBoxVM(BaseNode):
|
||||
raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(name=self.name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running":
|
||||
if isinstance(nio, NIOUDP):
|
||||
# dynamically configure an UDP tunnel on the VirtualBox adapter
|
||||
yield from self._control_vm("nic{} generic UDPTunnel".format(adapter_number + 1))
|
||||
yield from self._control_vm("nicproperty{} sport={}".format(adapter_number + 1, nio.lport))
|
||||
yield from self._control_vm("nicproperty{} dest={}".format(adapter_number + 1, nio.rhost))
|
||||
yield from self._control_vm("nicproperty{} dport={}".format(adapter_number + 1, nio.rport))
|
||||
yield from self._control_vm("setlinkstate{} on".format(adapter_number + 1))
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._add_ubridge_udp_connection("VBOX-{}-{}".format(self._id, adapter_number),
|
||||
self._local_udp_tunnels[adapter_number][1],
|
||||
nio)
|
||||
else:
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running":
|
||||
if isinstance(nio, NIOUDP):
|
||||
# dynamically configure an UDP tunnel on the VirtualBox adapter
|
||||
yield from self._control_vm("nic{} generic UDPTunnel".format(adapter_number + 1))
|
||||
yield from self._control_vm("nicproperty{} sport={}".format(adapter_number + 1, nio.lport))
|
||||
yield from self._control_vm("nicproperty{} dest={}".format(adapter_number + 1, nio.rhost))
|
||||
yield from self._control_vm("nicproperty{} dport={}".format(adapter_number + 1, nio.rport))
|
||||
yield from self._control_vm("setlinkstate{} on".format(adapter_number + 1))
|
||||
|
||||
# check if the UDP tunnel has been correctly set
|
||||
vm_info = yield from self._get_vm_info()
|
||||
generic_driver_number = "generic{}".format(adapter_number + 1)
|
||||
if generic_driver_number not in vm_info and vm_info[generic_driver_number] != "UDPTunnel":
|
||||
log.warning("UDP tunnel has not been set on nic: {}".format(adapter_number + 1))
|
||||
self.project.emit("log.warning", {"message": "UDP tunnel has not been set on nic: {}".format(adapter_number + 1)})
|
||||
# check if the UDP tunnel has been correctly set
|
||||
vm_info = yield from self._get_vm_info()
|
||||
generic_driver_number = "generic{}".format(adapter_number + 1)
|
||||
if generic_driver_number not in vm_info and vm_info[generic_driver_number] != "UDPTunnel":
|
||||
log.warning("UDP tunnel has not been set on nic: {}".format(adapter_number + 1))
|
||||
self.project.emit("log.warning", {"message": "UDP tunnel has not been set on nic: {}".format(adapter_number + 1)})
|
||||
|
||||
adapter.add_nio(0, nio)
|
||||
log.info("VirtualBox VM '{name}' [{id}]: {nio} added to adapter {adapter_number}".format(name=self.name,
|
||||
@@ -955,11 +984,14 @@ class VirtualBoxVM(BaseNode):
|
||||
raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(name=self.name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running":
|
||||
# dynamically disable the VirtualBox adapter
|
||||
yield from self._control_vm("setlinkstate{} off".format(adapter_number + 1))
|
||||
yield from self._control_vm("nic{} null".format(adapter_number + 1))
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send("bridge delete {name}".format(name="VBOX-{}-{}".format(self._id, adapter_number)))
|
||||
else:
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running":
|
||||
# dynamically disable the VirtualBox adapter
|
||||
yield from self._control_vm("setlinkstate{} off".format(adapter_number + 1))
|
||||
yield from self._control_vm("nic{} null".format(adapter_number + 1))
|
||||
|
||||
nio = adapter.get_nio(0)
|
||||
if isinstance(nio, NIOUDP):
|
||||
@@ -987,9 +1019,10 @@ class VirtualBoxVM(BaseNode):
|
||||
raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(name=self.name,
|
||||
adapter_number=adapter_number))
|
||||
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running" or vm_state == "paused" or vm_state == "stuck":
|
||||
raise VirtualBoxError("Sorry, packet capturing on a started VirtualBox VM is not supported.")
|
||||
if not self.use_ubridge:
|
||||
vm_state = yield from self._get_vm_state()
|
||||
if vm_state == "running" or vm_state == "paused" or vm_state == "stuck":
|
||||
raise VirtualBoxError("Sorry, packet capturing on a started VirtualBox VM is not supported without using uBridge")
|
||||
|
||||
nio = adapter.get_nio(0)
|
||||
|
||||
@@ -1000,6 +1033,11 @@ class VirtualBoxVM(BaseNode):
|
||||
raise VirtualBoxError("Packet capture is already activated on adapter {adapter_number}".format(adapter_number=adapter_number))
|
||||
|
||||
nio.startPacketCapture(output_file)
|
||||
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send('bridge start_capture {name} "{output_file}"'.format(name="VBOX-{}-{}".format(self._id, adapter_number),
|
||||
output_file=output_file))
|
||||
|
||||
log.info("VirtualBox VM '{name}' [{id}]: starting packet capture on adapter {adapter_number}".format(name=self.name,
|
||||
id=self.id,
|
||||
adapter_number=adapter_number))
|
||||
@@ -1024,6 +1062,9 @@ class VirtualBoxVM(BaseNode):
|
||||
|
||||
nio.stopPacketCapture()
|
||||
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send('bridge stop_capture {name}'.format(name="VBOX-{}-{}".format(self._id, adapter_number)))
|
||||
|
||||
log.info("VirtualBox VM '{name}' [{id}]: stopping packet capture on adapter {adapter_number}".format(name=self.name,
|
||||
id=self.id,
|
||||
adapter_number=adapter_number))
|
||||
@@ -370,13 +370,16 @@ class VPCSVM(BaseNode):
|
||||
raise VPCSError("Port {port_number} doesn't exist in adapter {adapter}".format(adapter=self._ethernet_adapter,
|
||||
port_number=port_number))
|
||||
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._add_ubridge_udp_connection("VPCS-{}".format(self._id), self._local_udp_tunnel[1], nio)
|
||||
elif self.is_running():
|
||||
raise VPCSError("Sorry, adding a link to a started VPCS instance is not supported without using uBridge.")
|
||||
|
||||
self._ethernet_adapter.add_nio(port_number, nio)
|
||||
log.info('VPCS "{name}" [{id}]: {nio} added to port {port_number}'.format(name=self._name,
|
||||
id=self.id,
|
||||
nio=nio,
|
||||
port_number=port_number))
|
||||
if self._started and self.ubridge:
|
||||
yield from self._add_ubridge_udp_connection("VPCS-{}".format(self._id), self._local_udp_tunnel[1], nio)
|
||||
|
||||
return nio
|
||||
|
||||
@@ -394,14 +397,16 @@ class VPCSVM(BaseNode):
|
||||
raise VPCSError("Port {port_number} doesn't exist in adapter {adapter}".format(adapter=self._ethernet_adapter,
|
||||
port_number=port_number))
|
||||
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send("bridge delete {name}".format(name="VPCS-{}".format(self._id)))
|
||||
elif self.is_running():
|
||||
raise VPCSError("Sorry, adding a link to a started VPCS instance is not supported without using uBridge.")
|
||||
|
||||
nio = self._ethernet_adapter.get_nio(port_number)
|
||||
if isinstance(nio, NIOUDP):
|
||||
self.manager.port_manager.release_udp_port(nio.lport, self._project)
|
||||
self._ethernet_adapter.remove_nio(port_number)
|
||||
|
||||
if self._started and self.ubridge:
|
||||
yield from self._ubridge_send("bridge delete {name}".format(name="VPCS-{}".format(self._id)))
|
||||
|
||||
log.info('VPCS "{name}" [{id}]: {nio} removed from port {port_number}'.format(name=self._name,
|
||||
id=self.id,
|
||||
nio=nio,
|
||||
@@ -434,7 +439,7 @@ class VPCSVM(BaseNode):
|
||||
|
||||
nio.startPacketCapture(output_file)
|
||||
|
||||
if self._started and self.ubridge:
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send('bridge start_capture {name} "{output_file}"'.format(name="VPCS-{}".format(self._id),
|
||||
output_file=output_file))
|
||||
|
||||
@@ -461,7 +466,7 @@ class VPCSVM(BaseNode):
|
||||
|
||||
nio.stopPacketCapture()
|
||||
|
||||
if self._started and self.ubridge:
|
||||
if self.ubridge and self.ubridge.is_running():
|
||||
yield from self._ubridge_send('bridge stop_capture {name}'.format(name="VPCS-{}".format(self._id)))
|
||||
|
||||
log.info("VPCS '{name}' [{id}]: stopping packet capture on port {port_number}".format(name=self.name,
|
||||
|
||||
@@ -192,7 +192,7 @@ class CloudHandler:
|
||||
|
||||
builtin_manager = Builtin.instance()
|
||||
node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
nio = builtin_manager.create_nio(node, request.json)
|
||||
nio = builtin_manager.create_nio(request.json)
|
||||
port_number = int(request.match_info["port_number"])
|
||||
yield from node.add_nio(nio, port_number)
|
||||
response.set_status(201)
|
||||
|
||||
@@ -200,7 +200,7 @@ class DockerHandler:
|
||||
nio_type = request.json["type"]
|
||||
if nio_type != "nio_udp":
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = docker_manager.create_nio(int(request.match_info["adapter_number"]), request.json)
|
||||
nio = docker_manager.create_nio(request.json)
|
||||
yield from container.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -217,7 +217,7 @@ class EthernetHubHandler:
|
||||
|
||||
#builtin_manager = Builtin.instance()
|
||||
#node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
#nio = yield from builtin_manager.create_nio(node, request.json["nio"])
|
||||
#nio = yield from builtin_manager.create_nio(request.json["nio"])
|
||||
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -218,7 +218,7 @@ class EthernetSwitchHandler:
|
||||
|
||||
#builtin_manager = Builtin.instance()
|
||||
#node = builtin_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||
#nio = yield from builtin_manager.create_nio(node, request.json["nio"])
|
||||
#nio = yield from builtin_manager.create_nio(request.json["nio"])
|
||||
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -222,7 +222,7 @@ class IOUHandler:
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_tap", "nio_ethernet", "nio_generic_ethernet"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = iou_manager.create_nio(vm.iouyap_path, request.json)
|
||||
nio = iou_manager.create_nio(request.json)
|
||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), int(request.match_info["port_number"]), nio)
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -266,7 +266,7 @@ class QEMUHandler:
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_tap", "nio_nat"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = qemu_manager.create_nio(vm.qemu_path, request.json)
|
||||
nio = qemu_manager.create_nio(request.json)
|
||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -282,7 +282,7 @@ class VirtualBoxHandler:
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_nat"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = vbox_manager.create_nio(vbox_manager.vboxmanage_path, request.json)
|
||||
nio = vbox_manager.create_nio(request.json)
|
||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -255,7 +255,7 @@ class VMwareHandler:
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_vmnet", "nio_nat"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = vmware_manager.create_nio(None, request.json)
|
||||
nio = vmware_manager.create_nio(request.json)
|
||||
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
@@ -201,7 +201,7 @@ class VPCSHandler:
|
||||
nio_type = request.json["type"]
|
||||
if nio_type not in ("nio_udp", "nio_tap"):
|
||||
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
|
||||
nio = vpcs_manager.create_nio(vm.vpcs_path, request.json)
|
||||
nio = vpcs_manager.create_nio(request.json)
|
||||
yield from vm.port_add_nio_binding(int(request.match_info["port_number"]), nio)
|
||||
response.set_status(201)
|
||||
response.json(nio)
|
||||
|
||||
Reference in new issue
Block a user