1
0
mirror of https://github.com/GNS3/gns3-server synced 2025-07-09 16:18:29 +00:00

Dynamips NIO connections.

This commit is contained in:
Jeremy 2015-02-13 15:11:14 -07:00
parent 83edc649d2
commit a5ac7c5481
18 changed files with 515 additions and 270 deletions

View File

@ -20,6 +20,7 @@ import asyncio
from ..web.route import Route from ..web.route import Route
from ..schemas.dynamips import VM_CREATE_SCHEMA from ..schemas.dynamips import VM_CREATE_SCHEMA
from ..schemas.dynamips import VM_UPDATE_SCHEMA from ..schemas.dynamips import VM_UPDATE_SCHEMA
from ..schemas.dynamips import VM_NIO_SCHEMA
from ..schemas.dynamips import VM_OBJECT_SCHEMA from ..schemas.dynamips import VM_OBJECT_SCHEMA
from ..modules.dynamips import Dynamips from ..modules.dynamips import Dynamips
from ..modules.project_manager import ProjectManager from ..modules.project_manager import ProjectManager
@ -238,3 +239,54 @@ class DynamipsHandler:
vm = dynamips_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) vm = dynamips_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
yield from vm.reload() yield from vm.reload()
response.set_status(204) response.set_status(204)
@Route.post(
r"/projects/{project_id}/dynamips/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance",
"adapter_number": "Adapter where the nio should be added",
"port_number": "Port on the adapter"
},
status_codes={
201: "NIO created",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Add a NIO to a Dynamips VM instance",
input=VM_NIO_SCHEMA,
output=VM_NIO_SCHEMA)
def create_nio(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
nio = yield from dynamips_manager.create_nio(vm, request.json)
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
yield from vm.slot_add_nio_binding(slot_number, port_number, nio)
response.set_status(201)
response.json(nio)
@classmethod
@Route.delete(
r"/projects/{project_id}/dynamips/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "UUID for the project",
"vm_id": "UUID for the instance",
"adapter_number": "Adapter from where the nio should be removed",
"port_number": "Port on the adapter"
},
status_codes={
204: "NIO deleted",
400: "Invalid request",
404: "Instance doesn't exist"
},
description="Remove a NIO from a Dynamips VM instance")
def delete_nio(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
yield from vm.slot_remove_nio_binding(slot_number, port_number)
response.set_status(204)

View File

@ -252,12 +252,12 @@ class VirtualBoxHandler:
response.set_status(204) response.set_status(204)
@Route.post( @Route.post(
r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_id:\d+}/ports/{port_id:\d+}/nio", r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={ parameters={
"project_id": "UUID for the project", "project_id": "UUID for the project",
"vm_id": "UUID for the instance", "vm_id": "UUID for the instance",
"adapter_id": "Adapter where the nio should be added", "adapter_number": "Adapter where the nio should be added",
"port_id": "Port in the adapter (always 0 for virtualbox)" "port_number": "Port on the adapter (always 0)"
}, },
status_codes={ status_codes={
201: "NIO created", 201: "NIO created",
@ -272,18 +272,18 @@ class VirtualBoxHandler:
vbox_manager = VirtualBox.instance() vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
nio = vbox_manager.create_nio(vbox_manager.vboxmanage_path, request.json) nio = vbox_manager.create_nio(vbox_manager.vboxmanage_path, request.json)
yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_id"]), nio) yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio)
response.set_status(201) response.set_status(201)
response.json(nio) response.json(nio)
@classmethod @classmethod
@Route.delete( @Route.delete(
r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_id:\d+}/ports/{port_id:\d+}/nio", r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={ parameters={
"project_id": "UUID for the project", "project_id": "UUID for the project",
"vm_id": "UUID for the instance", "vm_id": "UUID for the instance",
"adapter_id": "Adapter from where the nio should be removed", "adapter_number": "Adapter from where the nio should be removed",
"port_id": "Port in the adapter (always 0 for virtualbox)" "port_number": "Port on the adapter (always)"
}, },
status_codes={ status_codes={
204: "NIO deleted", 204: "NIO deleted",
@ -295,15 +295,16 @@ class VirtualBoxHandler:
vbox_manager = VirtualBox.instance() vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
yield from vm.adapter_remove_nio_binding(int(request.match_info["adapter_id"])) yield from vm.adapter_remove_nio_binding(int(request.match_info["adapter_number"]))
response.set_status(204) response.set_status(204)
@Route.post( @Route.post(
r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_id:\d+}/start_capture", r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/start_capture",
parameters={ parameters={
"project_id": "UUID for the project", "project_id": "UUID for the project",
"vm_id": "UUID for the instance", "vm_id": "UUID for the instance",
"adapter_id": "Adapter to start a packet capture" "adapter_number": "Adapter to start a packet capture",
"port_number": "Port on the adapter (always 0)"
}, },
status_codes={ status_codes={
200: "Capture started", 200: "Capture started",
@ -316,17 +317,18 @@ class VirtualBoxHandler:
vbox_manager = VirtualBox.instance() vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
adapter_id = int(request.match_info["adapter_id"]) adapter_number = int(request.match_info["adapter_number"])
pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"]) pcap_file_path = os.path.join(vm.project.capture_working_directory(), request.json["capture_file_name"])
vm.start_capture(adapter_id, pcap_file_path) vm.start_capture(adapter_number, pcap_file_path)
response.json({"pcap_file_path": pcap_file_path}) response.json({"pcap_file_path": pcap_file_path})
@Route.post( @Route.post(
r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_id:\d+}/stop_capture", r"/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/stop_capture",
parameters={ parameters={
"project_id": "UUID for the project", "project_id": "UUID for the project",
"vm_id": "UUID for the instance", "vm_id": "UUID for the instance",
"adapter_id": "Adapter to stop a packet capture" "adapter_number": "Adapter to stop a packet capture",
"port_number": "Port on the adapter (always 0)"
}, },
status_codes={ status_codes={
204: "Capture stopped", 204: "Capture stopped",
@ -338,5 +340,5 @@ class VirtualBoxHandler:
vbox_manager = VirtualBox.instance() vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
vm.stop_capture(int(request.match_info["adapter_id"])) vm.stop_capture(int(request.match_info["adapter_number"]))
response.set_status(204) response.set_status(204)

View File

@ -21,7 +21,7 @@ from .adapter import Adapter
class EthernetAdapter(Adapter): class EthernetAdapter(Adapter):
""" """
VPCS Ethernet adapter. Ethernet adapter.
""" """
def __init__(self, interfaces=1): def __init__(self, interfaces=1):

View File

@ -21,7 +21,7 @@ from .adapter import Adapter
class SerialAdapter(Adapter): class SerialAdapter(Adapter):
""" """
VPCS Ethernet adapter. Ethernet adapter.
""" """
def __init__(self, interfaces=1): def __init__(self, interfaces=1):

View File

@ -170,35 +170,7 @@ class Dynamips(BaseManager):
return hypervisor return hypervisor
def create_nio(self, executable, nio_settings): @asyncio.coroutine
"""
Creates a new NIO.
:param nio_settings: information to create the NIO
:returns: a NIO object
"""
nio = None
if nio_settings["type"] == "nio_udp":
lport = nio_settings["lport"]
rhost = nio_settings["rhost"]
rport = nio_settings["rport"]
try:
# TODO: handle IPv6
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.connect((rhost, rport))
except OSError as e:
raise aiohttp.web.HTTPInternalServerError(text="Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e))
nio = NIOUDP(lport, rhost, rport)
elif nio_settings["type"] == "nio_tap":
tap_device = nio_settings["tap_device"]
if not self._has_privileged_access(executable):
raise aiohttp.web.HTTPForbidden(text="{} has no privileged access to {}.".format(executable, tap_device))
nio = NIOTAP(tap_device)
assert nio is not None
return nio
def create_nio(self, node, nio_settings): def create_nio(self, node, nio_settings):
""" """
Creates a new NIO. Creates a new NIO.
@ -221,12 +193,12 @@ class Dynamips(BaseManager):
except OSError as e: except OSError as e:
raise DynamipsError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e)) raise DynamipsError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e))
# check if we have an allocated NIO UDP auto # check if we have an allocated NIO UDP auto
nio = node.hypervisor.get_nio_udp_auto(lport) #nio = node.hypervisor.get_nio_udp_auto(lport)
if not nio: #if not nio:
# otherwise create an NIO UDP # otherwise create an NIO UDP
nio = NIOUDP(node.hypervisor, lport, rhost, rport) nio = NIOUDP(node.hypervisor, lport, rhost, rport)
else: #else:
nio.connect(rhost, rport) # nio.connect(rhost, rport)
elif nio_settings["type"] == "nio_generic_ethernet": elif nio_settings["type"] == "nio_generic_ethernet":
ethernet_device = nio_settings["ethernet_device"] ethernet_device = nio_settings["ethernet_device"]
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
@ -259,6 +231,8 @@ class Dynamips(BaseManager):
nio = NIOVDE(node.hypervisor, control_file, local_file) nio = NIOVDE(node.hypervisor, control_file, local_file)
elif nio_settings["type"] == "nio_null": elif nio_settings["type"] == "nio_null":
nio = NIONull(node.hypervisor) nio = NIONull(node.hypervisor)
yield from nio.create()
return nio return nio
# def set_ghost_ios(self, router): # def set_ghost_ios(self, router):

View File

@ -38,7 +38,7 @@ class NIO:
def __init__(self, name, hypervisor): def __init__(self, name, hypervisor):
self._hypervisor = hypervisor self._hypervisor = hypervisor
self._name = None self._name = name
self._bandwidth = None # no bandwidth constraint by default self._bandwidth = None # no bandwidth constraint by default
self._input_filter = None # no input filter applied by default self._input_filter = None # no input filter applied by default
self._output_filter = None # no output filter applied by default self._output_filter = None # no output filter applied by default

View File

@ -38,12 +38,11 @@ class NIOFIFO(NIO):
def __init__(self, hypervisor): def __init__(self, hypervisor):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOFIFO._instance_count
# create an unique ID
self._id = NIOFIFO._instance_count
NIOFIFO._instance_count += 1 NIOFIFO._instance_count += 1
self._name = 'nio_fifo' + str(self._id) name = 'nio_fifo' + str(nio_id)
NIO.__init__(name, self, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -71,3 +70,7 @@ class NIOFIFO(NIO):
nio=nio)) nio=nio))
log.info("NIO FIFO {name} crossconnected with {nio_name}.".format(name=self._name, nio_name=nio.name)) log.info("NIO FIFO {name} crossconnected with {nio_name}.".format(name=self._name, nio_name=nio.name))
def __json__(self):
return {"type": "nio_fifo"}

View File

@ -39,13 +39,12 @@ class NIOGenericEthernet(NIO):
def __init__(self, hypervisor, ethernet_device): def __init__(self, hypervisor, ethernet_device):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOGenericEthernet._instance_count
# create an unique ID
self._id = NIOGenericEthernet._instance_count
NIOGenericEthernet._instance_count += 1 NIOGenericEthernet._instance_count += 1
self._name = 'nio_gen_eth' + str(self._id) name = 'nio_gen_eth' + str(nio_id)
self._ethernet_device = ethernet_device self._ethernet_device = ethernet_device
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -73,3 +72,8 @@ class NIOGenericEthernet(NIO):
""" """
return self._ethernet_device return self._ethernet_device
def __json__(self):
return {"type": "nio_generic_ethernet",
"ethernet_device": self._ethernet_device}

View File

@ -39,13 +39,12 @@ class NIOLinuxEthernet(NIO):
def __init__(self, hypervisor, ethernet_device): def __init__(self, hypervisor, ethernet_device):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOLinuxEthernet._instance_count
# create an unique ID
self._id = NIOLinuxEthernet._instance_count
NIOLinuxEthernet._instance_count += 1 NIOLinuxEthernet._instance_count += 1
self._name = 'nio_linux_eth' + str(self._id) name = 'nio_linux_eth' + str(nio_id)
self._ethernet_device = ethernet_device self._ethernet_device = ethernet_device
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -73,3 +72,8 @@ class NIOLinuxEthernet(NIO):
""" """
return self._ethernet_device return self._ethernet_device
def __json__(self):
return {"type": "nio_linux_ethernet",
"ethernet_device": self._ethernet_device}

View File

@ -40,15 +40,14 @@ class NIOMcast(NIO):
def __init__(self, hypervisor, group, port): def __init__(self, hypervisor, group, port):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOMcast._instance_count
# create an unique ID
self._id = NIOMcast._instance_count
NIOMcast._instance_count += 1 NIOMcast._instance_count += 1
self._name = 'nio_mcast' + str(self._id) name = 'nio_mcast' + str(nio_id)
self._group = group self._group = group
self._port = port self._port = port
self._ttl = 1 # default TTL self._ttl = 1 # default TTL
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -109,3 +108,9 @@ class NIOMcast(NIO):
yield from self._hypervisor.send("nio set_mcast_ttl {name} {ttl}".format(name=self._name, yield from self._hypervisor.send("nio set_mcast_ttl {name} {ttl}".format(name=self._name,
ttl=ttl)) ttl=ttl))
self._ttl = ttl self._ttl = ttl
def __json__(self):
return {"type": "nio_mcast",
"mgroup": self._mgroup,
"mport": self._mport}

View File

@ -38,12 +38,11 @@ class NIONull(NIO):
def __init__(self, hypervisor): def __init__(self, hypervisor):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIONull._instance_count
# create an unique ID
self._id = NIONull._instance_count
NIONull._instance_count += 1 NIONull._instance_count += 1
self._name = 'nio_null' + str(self._id) name = 'nio_null' + str(nio_id)
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -58,3 +57,7 @@ class NIONull(NIO):
yield from self._hypervisor.send("nio create_null {}".format(self._name)) yield from self._hypervisor.send("nio create_null {}".format(self._name))
log.info("NIO NULL {name} created.".format(name=self._name)) log.info("NIO NULL {name} created.".format(name=self._name))
def __json__(self):
return {"type": "nio_null"}

View File

@ -39,13 +39,12 @@ class NIOTAP(NIO):
def __init__(self, hypervisor, tap_device): def __init__(self, hypervisor, tap_device):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOTAP._instance_count
# create an unique ID
self._id = NIOTAP._instance_count
NIOTAP._instance_count += 1 NIOTAP._instance_count += 1
self._name = 'nio_tap' + str(self._id) name = 'nio_tap' + str(nio_id)
self._tap_device = tap_device self._tap_device = tap_device
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -70,3 +69,8 @@ class NIOTAP(NIO):
""" """
return self._tap_device return self._tap_device
def __json__(self):
return {"type": "nio_tap",
"tap_device": self._tap_device}

View File

@ -41,15 +41,14 @@ class NIOUDP(NIO):
def __init__(self, hypervisor, lport, rhost, rport): def __init__(self, hypervisor, lport, rhost, rport):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOUDP._instance_count
# create an unique ID
self._id = NIOUDP._instance_count
NIOUDP._instance_count += 1 NIOUDP._instance_count += 1
self._name = 'nio_udp' + str(self._id) name = 'nio_udp' + str(nio_id)
self._lport = lport self._lport = lport
self._rhost = rhost self._rhost = rhost
self._rport = rport self._rport = rport
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -101,3 +100,10 @@ class NIOUDP(NIO):
""" """
return self._rport return self._rport
def __json__(self):
return {"type": "nio_udp",
"lport": self._lport,
"rport": self._rport,
"rhost": self._rhost}

View File

@ -41,17 +41,15 @@ class NIOUDPAuto(NIO):
def __init__(self, hypervisor, laddr, lport_start, lport_end): def __init__(self, hypervisor, laddr, lport_start, lport_end):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOUDPAuto._instance_count
# create an unique ID
self._id = NIOUDPAuto._instance_count
NIOUDPAuto._instance_count += 1 NIOUDPAuto._instance_count += 1
self._name = 'nio_udp_auto' + str(self._id) name = 'nio_udp_auto' + str(nio_id)
self._laddr = laddr self._laddr = laddr
self._lport = None self._lport = None
self._raddr = None self._raddr = None
self._rport = None self._rport = None
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -133,3 +131,10 @@ class NIOUDPAuto(NIO):
log.info("NIO UDP AUTO {name} connected to {raddr}:{rport}".format(name=self._name, log.info("NIO UDP AUTO {name} connected to {raddr}:{rport}".format(name=self._name,
raddr=raddr, raddr=raddr,
rport=rport)) rport=rport))
def __json__(self):
return {"type": "nio_udp_auto",
"lport": self._lport,
"rport": self._rport,
"raddr": self._raddr}

View File

@ -40,14 +40,13 @@ class NIOUNIX(NIO):
def __init__(self, hypervisor, local_file, remote_file): def __init__(self, hypervisor, local_file, remote_file):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOUNIX._instance_count
# create an unique ID
self._id = NIOUNIX._instance_count
NIOUNIX._instance_count += 1 NIOUNIX._instance_count += 1
self._name = 'nio_unix' + str(self._id) name = 'nio_unix' + str(nio_id)
self._local_file = local_file self._local_file = local_file
self._remote_file = remote_file self._remote_file = remote_file
NIO.__init__(self, name, hypervisor)
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -87,3 +86,9 @@ class NIOUNIX(NIO):
""" """
return self._remote_file return self._remote_file
def __json__(self):
return {"type": "nio_unix",
"local_file": self._local_file,
"remote_file": self._remote_file}

View File

@ -19,6 +19,7 @@
Interface for VDE (Virtual Distributed Ethernet) NIOs (Unix based OSes only). Interface for VDE (Virtual Distributed Ethernet) NIOs (Unix based OSes only).
""" """
import asyncio
from .nio import NIO from .nio import NIO
import logging import logging
@ -39,22 +40,13 @@ class NIOVDE(NIO):
def __init__(self, hypervisor, control_file, local_file): def __init__(self, hypervisor, control_file, local_file):
NIO.__init__(self, hypervisor) # create an unique ID and name
nio_id = NIOVDE._instance_count
# create an unique ID
self._id = NIOVDE._instance_count
NIOVDE._instance_count += 1 NIOVDE._instance_count += 1
self._name = 'nio_vde' + str(self._id) name = 'nio_vde' + str(nio_id)
self._control_file = control_file self._control_file = control_file
self._local_file = local_file self._local_file = local_file
NIO.__init__(self, name, hypervisor)
self._hypervisor.send("nio create_vde {name} {control} {local}".format(name=self._name,
control=control_file,
local=local_file))
log.info("NIO VDE {name} created with control={control}, local={local}".format(name=self._name,
control=control_file,
local=local_file))
@classmethod @classmethod
def reset(cls): def reset(cls):
@ -64,6 +56,17 @@ class NIOVDE(NIO):
cls._instance_count = 0 cls._instance_count = 0
@asyncio.coroutine
def create(self):
self._hypervisor.send("nio create_vde {name} {control} {local}".format(name=self._name,
control=self._control_file,
local=self._local_file))
log.info("NIO VDE {name} created with control={control}, local={local}".format(name=self._name,
control=self._control_file,
local=self._local_file))
@property @property
def control_file(self): def control_file(self):
""" """
@ -83,3 +86,9 @@ class NIOVDE(NIO):
""" """
return self._local_file return self._local_file
def __json__(self):
return {"type": "nio_vde",
"local_file": self._local_file,
"control_file": self._control_file}

View File

@ -145,16 +145,16 @@ class Router(BaseVM):
"system_id": self._system_id} "system_id": self._system_id}
# FIXME: add default slots/wics # FIXME: add default slots/wics
# slot_id = 0 # slot_number = 0
# for slot in self._slots: # for slot in self._slots:
# if slot: # if slot:
# slot = str(slot) # slot = str(slot)
# router_defaults["slot" + str(slot_id)] = slot # router_defaults["slot" + str(slot_number)] = slot
# slot_id += 1 # slot_number += 1
# if self._slots[0] and self._slots[0].wics: # if self._slots[0] and self._slots[0].wics:
# for wic_slot_id in range(0, len(self._slots[0].wics)): # for wic_slot_number in range(0, len(self._slots[0].wics)):
# router_defaults["wic" + str(wic_slot_id)] = None # router_defaults["wic" + str(wic_slot_number)] = None
return router_info return router_info
@ -991,23 +991,23 @@ class Router(BaseVM):
return slot_bindings return slot_bindings
@asyncio.coroutine @asyncio.coroutine
def slot_add_binding(self, slot_id, adapter): def slot_add_binding(self, slot_number, adapter):
""" """
Adds a slot binding (a module into a slot). Adds a slot binding (a module into a slot).
:param slot_id: slot ID :param slot_number: slot number
:param adapter: device to add in the corresponding slot :param adapter: device to add in the corresponding slot
""" """
try: try:
slot = self._slots[slot_id] slot = self._slots[slot_number]
except IndexError: except IndexError:
raise DynamipsError('Slot {slot_id} does not exist on router "{name}"'.format(name=self._name, slot_id=slot_id)) raise DynamipsError('Slot {slot_number} does not exist on router "{name}"'.format(name=self._name, slot_number=slot_number))
if slot is not None: if slot is not None:
current_adapter = slot current_adapter = slot
raise DynamipsError('Slot {slot_id} is already occupied by adapter {adapter} on router "{name}"'.format(name=self._name, raise DynamipsError('Slot {slot_number} is already occupied by adapter {adapter} on router "{name}"'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
adapter=current_adapter)) adapter=current_adapter))
is_running = yield from self.is_running() is_running = yield from self.is_running()
@ -1019,42 +1019,44 @@ class Router(BaseVM):
raise DynamipsError('Adapter {adapter} cannot be added while router "{name}" is running'.format(adapter=adapter, raise DynamipsError('Adapter {adapter} cannot be added while router "{name}" is running'.format(adapter=adapter,
name=self._name)) name=self._name))
yield from self._hypervisor.send('vm slot_add_binding "{name}" {slot_id} 0 {adapter}'.format(name=self._name, yield from self._hypervisor.send('vm slot_add_binding "{name}" {slot_number} 0 {adapter}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
adapter=adapter)) adapter=adapter))
log.info('Router "{name}" [{id}]: adapter {adapter} inserted into slot {slot_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: adapter {adapter} inserted into slot {slot_number}'.format(name=self._name,
id=self._id, id=self._id,
adapter=adapter, adapter=adapter,
slot_id=slot_id)) slot_number=slot_number))
self._slots[slot_id] = adapter self._slots[slot_number] = adapter
# Generate an OIR event if the router is running # Generate an OIR event if the router is running
if is_running: if is_running:
yield from self._hypervisor.send('vm slot_oir_start "{name}" {slot_id} 0'.format(name=self._name, slot_id=slot_id)) yield from self._hypervisor.send('vm slot_oir_start "{name}" {slot_number} 0'.format(name=self._name,
slot_number=slot_number))
log.info('Router "{name}" [{id}]: OIR start event sent to slot {slot_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: OIR start event sent to slot {slot_number}'.format(name=self._name,
id=self._id, id=self._id,
slot_id=slot_id)) slot_number=slot_number))
@asyncio.coroutine @asyncio.coroutine
def slot_remove_binding(self, slot_id): def slot_remove_binding(self, slot_number):
""" """
Removes a slot binding (a module from a slot). Removes a slot binding (a module from a slot).
:param slot_id: slot ID :param slot_number: slot number
""" """
try: try:
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
except IndexError: except IndexError:
raise DynamipsError('Slot {slot_id} does not exist on router "{name}"'.format(name=self._name, slot_id=slot_id)) raise DynamipsError('Slot {slot_number} does not exist on router "{name}"'.format(name=self._name,
slot_number=slot_number))
if adapter is None: if adapter is None:
raise DynamipsError('No adapter in slot {slot_id} on router "{name}"'.format(name=self._name, raise DynamipsError('No adapter in slot {slot_number} on router "{name}"'.format(name=self._name,
slot_id=slot_id)) slot_number=slot_number))
is_running = yield from self.is_running() is_running = yield from self.is_running()
@ -1068,239 +1070,245 @@ class Router(BaseVM):
# Generate an OIR event if the router is running # Generate an OIR event if the router is running
if is_running: if is_running:
yield from self._hypervisor.send('vm slot_oir_stop "{name}" {slot_id} 0'.format(name=self._name, slot_id=slot_id)) yield from self._hypervisor.send('vm slot_oir_stop "{name}" {slot_number} 0'.format(name=self._name,
slot_number=slot_number))
log.info('Router "{name}" [{id}]: OIR stop event sent to slot {slot_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: OIR stop event sent to slot {slot_number}'.format(name=self._name,
id=self._id, id=self._id,
slot_id=slot_id)) slot_number=slot_number))
yield from self._hypervisor.send('vm slot_remove_binding "{name}" {slot_id} 0'.format(name=self._name, slot_id=slot_id)) yield from self._hypervisor.send('vm slot_remove_binding "{name}" {slot_number} 0'.format(name=self._name,
slot_number=slot_number))
log.info('Router "{name}" [{id}]: adapter {adapter} removed from slot {slot_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: adapter {adapter} removed from slot {slot_number}'.format(name=self._name,
id=self._id, id=self._id,
adapter=adapter, adapter=adapter,
slot_id=slot_id)) slot_number=slot_number))
self._slots[slot_id] = None self._slots[slot_number] = None
@asyncio.coroutine @asyncio.coroutine
def install_wic(self, wic_slot_id, wic): def install_wic(self, wic_slot_number, wic):
""" """
Installs a WIC adapter into this router. Installs a WIC adapter into this router.
:param wic_slot_id: WIC slot ID :param wic_slot_number: WIC slot number
:param wic: WIC to be installed :param wic: WIC to be installed
""" """
# WICs are always installed on adapters in slot 0 # WICs are always installed on adapters in slot 0
slot_id = 0 slot_number = 0
# Do not check if slot has an adapter because adapters with WICs interfaces # Do not check if slot has an adapter because adapters with WICs interfaces
# must be inserted by default in the router and cannot be removed. # must be inserted by default in the router and cannot be removed.
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
if wic_slot_id > len(adapter.wics) - 1: if wic_slot_number > len(adapter.wics) - 1:
raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(wic_slot_id=wic_slot_id)) raise DynamipsError("WIC slot {wic_slot_number} doesn't exist".format(wic_slot_number=wic_slot_number))
if not adapter.wic_slot_available(wic_slot_id): if not adapter.wic_slot_available(wic_slot_number):
raise DynamipsError("WIC slot {wic_slot_id} is already occupied by another WIC".format(wic_slot_id=wic_slot_id)) raise DynamipsError("WIC slot {wic_slot_number} is already occupied by another WIC".format(wic_slot_number=wic_slot_number))
# Dynamips WICs slot IDs start on a multiple of 16 # Dynamips WICs slot IDs start on a multiple of 16
# WIC1 = 16, WIC2 = 32 and WIC3 = 48 # WIC1 = 16, WIC2 = 32 and WIC3 = 48
internal_wic_slot_id = 16 * (wic_slot_id + 1) internal_wic_slot_number = 16 * (wic_slot_number + 1)
yield from self._hypervisor.send('vm slot_add_binding "{name}" {slot_id} {wic_slot_id} {wic}'.format(name=self._name, yield from self._hypervisor.send('vm slot_add_binding "{name}" {slot_number} {wic_slot_number} {wic}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
wic_slot_id=internal_wic_slot_id, wic_slot_number=internal_wic_slot_number,
wic=wic)) wic=wic))
log.info('Router "{name}" [{id}]: {wic} inserted into WIC slot {wic_slot_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: {wic} inserted into WIC slot {wic_slot_number}'.format(name=self._name,
id=self._id, id=self._id,
wic=wic, wic=wic,
wic_slot_id=wic_slot_id)) wic_slot_number=wic_slot_number))
adapter.install_wic(wic_slot_id, wic) adapter.install_wic(wic_slot_number, wic)
@asyncio.coroutine @asyncio.coroutine
def uninstall_wic(self, wic_slot_id): def uninstall_wic(self, wic_slot_number):
""" """
Uninstalls a WIC adapter from this router. Uninstalls a WIC adapter from this router.
:param wic_slot_id: WIC slot ID :param wic_slot_number: WIC slot number
""" """
# WICs are always installed on adapters in slot 0 # WICs are always installed on adapters in slot 0
slot_id = 0 slot_number = 0
# Do not check if slot has an adapter because adapters with WICs interfaces # Do not check if slot has an adapter because adapters with WICs interfaces
# must be inserted by default in the router and cannot be removed. # must be inserted by default in the router and cannot be removed.
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
if wic_slot_id > len(adapter.wics) - 1: if wic_slot_number > len(adapter.wics) - 1:
raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(wic_slot_id=wic_slot_id)) raise DynamipsError("WIC slot {wic_slot_number} doesn't exist".format(wic_slot_number=wic_slot_number))
if adapter.wic_slot_available(wic_slot_id): if adapter.wic_slot_available(wic_slot_number):
raise DynamipsError("No WIC is installed in WIC slot {wic_slot_id}".format(wic_slot_id=wic_slot_id)) raise DynamipsError("No WIC is installed in WIC slot {wic_slot_number}".format(wic_slot_number=wic_slot_number))
# Dynamips WICs slot IDs start on a multiple of 16 # Dynamips WICs slot IDs start on a multiple of 16
# WIC1 = 16, WIC2 = 32 and WIC3 = 48 # WIC1 = 16, WIC2 = 32 and WIC3 = 48
internal_wic_slot_id = 16 * (wic_slot_id + 1) internal_wic_slot_number = 16 * (wic_slot_number + 1)
yield from self._hypervisor.send('vm slot_remove_binding "{name}" {slot_id} {wic_slot_id}'.format(name=self._name, yield from self._hypervisor.send('vm slot_remove_binding "{name}" {slot_number} {wic_slot_number}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
wic_slot_id=internal_wic_slot_id)) wic_slot_number=internal_wic_slot_number))
log.info('Router "{name}" [{id}]: {wic} removed from WIC slot {wic_slot_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: {wic} removed from WIC slot {wic_slot_number}'.format(name=self._name,
id=self._id, id=self._id,
wic=adapter.wics[wic_slot_id], wic=adapter.wics[wic_slot_number],
wic_slot_id=wic_slot_id)) wic_slot_number=wic_slot_number))
adapter.uninstall_wic(wic_slot_id) adapter.uninstall_wic(wic_slot_number)
@asyncio.coroutine @asyncio.coroutine
def get_slot_nio_bindings(self, slot_id): def get_slot_nio_bindings(self, slot_number):
""" """
Returns slot NIO bindings. Returns slot NIO bindings.
:param slot_id: slot ID :param slot_number: slot number
:returns: list of NIO bindings :returns: list of NIO bindings
""" """
nio_bindings = yield from self._hypervisor.send('vm slot_nio_bindings "{name}" {slot_id}'.format(name=self._name, nio_bindings = yield from self._hypervisor.send('vm slot_nio_bindings "{name}" {slot_number}'.format(name=self._name,
slot_id=slot_id)) slot_number=slot_number))
return nio_bindings return nio_bindings
@asyncio.coroutine @asyncio.coroutine
def slot_add_nio_binding(self, slot_id, port_id, nio): def slot_add_nio_binding(self, slot_number, port_number, nio):
""" """
Adds a slot NIO binding. Adds a slot NIO binding.
:param slot_id: slot ID :param slot_number: slot number
:param port_id: port ID :param port_number: port number
:param nio: NIO instance to add to the slot/port :param nio: NIO instance to add to the slot/port
""" """
try: try:
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
except IndexError: except IndexError:
raise DynamipsError('Slot {slot_id} does not exist on router "{name}"'.format(name=self._name, raise DynamipsError('Slot {slot_number} does not exist on router "{name}"'.format(name=self._name,
slot_id=slot_id)) slot_number=slot_number))
if not adapter.port_exists(port_id): if not adapter.port_exists(port_number):
raise DynamipsError("Port {port_id} does not exist in adapter {adapter}".format(adapter=adapter, raise DynamipsError("Port {port_number} does not exist in adapter {adapter}".format(adapter=adapter,
port_id=port_id)) port_number=port_number))
yield from self._hypervisor.send('vm slot_add_nio_binding "{name}" {slot_id} {port_id} {nio}'.format(name=self._name, yield from self._hypervisor.send('vm slot_add_nio_binding "{name}" {slot_number} {port_number} {nio}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id, port_number=port_number,
nio=nio)) nio=nio))
log.info('Router "{name}" [{id}]: NIO {nio_name} bound to port {slot_id}/{port_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: NIO {nio_name} bound to port {slot_number}/{port_number}'.format(name=self._name,
id=self._id, id=self._id,
nio_name=nio.name, nio_name=nio.name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
yield from self.slot_enable_nio(slot_id, port_id) yield from self.slot_enable_nio(slot_number, port_number)
adapter.add_nio(port_id, nio) adapter.add_nio(port_number, nio)
@asyncio.coroutine @asyncio.coroutine
def slot_remove_nio_binding(self, slot_id, port_id): def slot_remove_nio_binding(self, slot_number, port_number):
""" """
Removes a slot NIO binding. Removes a slot NIO binding.
:param slot_id: slot ID :param slot_number: slot number
:param port_id: port ID :param port_number: port number
:returns: removed NIO instance :returns: removed NIO instance
""" """
try: try:
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
except IndexError: except IndexError:
raise DynamipsError('Slot {slot_id} does not exist on router "{name}"'.format(name=self._name, slot_id=slot_id)) raise DynamipsError('Slot {slot_number} does not exist on router "{name}"'.format(name=self._name,
if not adapter.port_exists(port_id): slot_number=slot_number))
raise DynamipsError("Port {port_id} does not exist in adapter {adapter}".format(adapter=adapter, port_id=port_id)) if not adapter.port_exists(port_number):
raise DynamipsError("Port {port_number} does not exist in adapter {adapter}".format(adapter=adapter,
port_number=port_number))
yield from self.slot_disable_nio(slot_id, port_id) yield from self.slot_disable_nio(slot_number, port_number)
yield from self._hypervisor.send('vm slot_remove_nio_binding "{name}" {slot_id} {port_id}'.format(name=self._name, yield from self._hypervisor.send('vm slot_remove_nio_binding "{name}" {slot_number} {port_number}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
nio = adapter.get_nio(port_id) nio = adapter.get_nio(port_number)
adapter.remove_nio(port_id) adapter.remove_nio(port_number)
log.info('Router "{name}" [{id}]: NIO {nio_name} removed from port {slot_id}/{port_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: NIO {nio_name} removed from port {slot_number}/{port_number}'.format(name=self._name,
id=self._id, id=self._id,
nio_name=nio.name, nio_name=nio.name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
return nio return nio
@asyncio.coroutine @asyncio.coroutine
def slot_enable_nio(self, slot_id, port_id): def slot_enable_nio(self, slot_number, port_number):
""" """
Enables a slot NIO binding. Enables a slot NIO binding.
:param slot_id: slot ID :param slot_number: slot number
:param port_id: port ID :param port_number: port number
""" """
is_running = yield from self.is_running() is_running = yield from self.is_running()
if is_running: # running router if is_running: # running router
yield from self._hypervisor.send('vm slot_enable_nio "{name}" {slot_id} {port_id}'.format(name=self._name, yield from self._hypervisor.send('vm slot_enable_nio "{name}" {slot_number} {port_number}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
log.info('Router "{name}" [{id}]: NIO enabled on port {slot_id}/{port_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: NIO enabled on port {slot_number}/{port_number}'.format(name=self._name,
id=self._id, id=self._id,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
@asyncio.coroutine @asyncio.coroutine
def slot_disable_nio(self, slot_id, port_id): def slot_disable_nio(self, slot_number, port_number):
""" """
Disables a slot NIO binding. Disables a slot NIO binding.
:param slot_id: slot ID :param slot_number: slot number
:param port_id: port ID :param port_number: port number
""" """
is_running = yield from self.is_running() is_running = yield from self.is_running()
if is_running: # running router if is_running: # running router
yield from self._hypervisor.send('vm slot_disable_nio "{name}" {slot_id} {port_id}'.format(name=self._name, yield from self._hypervisor.send('vm slot_disable_nio "{name}" {slot_number} {port_number}'.format(name=self._name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
log.info('Router "{name}" [{id}]: NIO disabled on port {slot_id}/{port_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: NIO disabled on port {slot_number}/{port_number}'.format(name=self._name,
id=self._id, id=self._id,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
@asyncio.coroutine @asyncio.coroutine
def start_capture(self, slot_id, port_id, output_file, data_link_type="DLT_EN10MB"): def start_capture(self, slot_number, port_number, output_file, data_link_type="DLT_EN10MB"):
""" """
Starts a packet capture. Starts a packet capture.
:param slot_id: slot ID :param slot_number: slot number
:param port_id: port ID :param port_number: port number
:param output_file: PCAP destination file for the capture :param output_file: PCAP destination file for the capture
:param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB :param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
""" """
try: try:
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
except IndexError: except IndexError:
raise DynamipsError('Slot {slot_id} does not exist on router "{name}"'.format(name=self._name, slot_id=slot_id)) raise DynamipsError('Slot {slot_number} does not exist on router "{name}"'.format(name=self._name,
if not adapter.port_exists(port_id): slot_number=slot_number))
raise DynamipsError("Port {port_id} does not exist in adapter {adapter}".format(adapter=adapter, port_id=port_id)) if not adapter.port_exists(port_number):
raise DynamipsError("Port {port_number} does not exist in adapter {adapter}".format(adapter=adapter,
port_number=port_number))
data_link_type = data_link_type.lower() data_link_type = data_link_type.lower()
if data_link_type.startswith("dlt_"): if data_link_type.startswith("dlt_"):
data_link_type = data_link_type[4:] data_link_type = data_link_type[4:]
nio = adapter.get_nio(port_id) nio = adapter.get_nio(port_number)
if nio.input_filter[0] is not None and nio.output_filter[0] is not None: if nio.input_filter[0] is not None and nio.output_filter[0] is not None:
raise DynamipsError("Port {port_id} has already a filter applied on {adapter}".format(adapter=adapter, raise DynamipsError("Port {port_number} has already a filter applied on {adapter}".format(adapter=adapter,
port_id=port_id)) port_number=port_number))
# FIXME: capture # FIXME: capture
# try: # try:
@ -1311,36 +1319,38 @@ class Router(BaseVM):
yield from nio.bind_filter("both", "capture") yield from nio.bind_filter("both", "capture")
yield from nio.setup_filter("both", '{} "{}"'.format(data_link_type, output_file)) yield from nio.setup_filter("both", '{} "{}"'.format(data_link_type, output_file))
log.info('Router "{name}" [{id}]: starting packet capture on port {slot_id}/{port_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: starting packet capture on port {slot_number}/{port_number}'.format(name=self._name,
id=self._id, id=self._id,
nio_name=nio.name, nio_name=nio.name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
@asyncio.coroutine @asyncio.coroutine
def stop_capture(self, slot_id, port_id): def stop_capture(self, slot_number, port_number):
""" """
Stops a packet capture. Stops a packet capture.
:param slot_id: slot ID :param slot_number: slot number
:param port_id: port ID :param port_number: port number
""" """
try: try:
adapter = self._slots[slot_id] adapter = self._slots[slot_number]
except IndexError: except IndexError:
raise DynamipsError('Slot {slot_id} does not exist on router "{name}"'.format(name=self._name, slot_id=slot_id)) raise DynamipsError('Slot {slot_number} does not exist on router "{name}"'.format(name=self._name,
if not adapter.port_exists(port_id): slot_number=slot_number))
raise DynamipsError("Port {port_id} does not exist in adapter {adapter}".format(adapter=adapter, port_id=port_id)) if not adapter.port_exists(port_number):
raise DynamipsError("Port {port_number} does not exist in adapter {adapter}".format(adapter=adapter,
port_number=port_number))
nio = adapter.get_nio(port_id) nio = adapter.get_nio(port_number)
yield from nio.unbind_filter("both") yield from nio.unbind_filter("both")
log.info('Router "{name}" [{id}]: stopping packet capture on port {slot_id}/{port_id}'.format(name=self._name, log.info('Router "{name}" [{id}]: stopping packet capture on port {slot_number}/{port_number}'.format(name=self._name,
id=self._id, id=self._id,
nio_name=nio.name, nio_name=nio.name,
slot_id=slot_id, slot_number=slot_number,
port_id=port_id)) port_number=port_number))
def _create_slots(self, numslots): def _create_slots(self, numslots):
""" """

View File

@ -46,6 +46,12 @@ VM_CREATE_SCHEMA = {
"minLength": 1, "minLength": 1,
"pattern": "^c[0-9]{4}$" "pattern": "^c[0-9]{4}$"
}, },
"chassis": {
"description": "router chassis model",
"type": "string",
"minLength": 1,
"pattern": "^[0-9]{4}(XM)?$"
},
"image": { "image": {
"description": "path to the IOS image", "description": "path to the IOS image",
"type": "string", "type": "string",
@ -265,6 +271,12 @@ VM_UPDATE_SCHEMA = {
"minLength": 1, "minLength": 1,
"pattern": "^c[0-9]{4}$" "pattern": "^c[0-9]{4}$"
}, },
"chassis": {
"description": "router chassis model",
"type": "string",
"minLength": 1,
"pattern": "^[0-9]{4}(XM)?$"
},
"image": { "image": {
"description": "path to the IOS image", "description": "path to the IOS image",
"type": "string", "type": "string",
@ -467,6 +479,147 @@ VM_UPDATE_SCHEMA = {
"additionalProperties": False, "additionalProperties": False,
} }
VM_NIO_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Request validation to add a NIO for a Dynamips VM instance",
"type": "object",
"definitions": {
"UDP": {
"description": "UDP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_udp"]
},
"lport": {
"description": "Local port",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"rhost": {
"description": "Remote host",
"type": "string",
"minLength": 1
},
"rport": {
"description": "Remote port",
"type": "integer",
"minimum": 1,
"maximum": 65535
}
},
"required": ["type", "lport", "rhost", "rport"],
"additionalProperties": False
},
"Ethernet": {
"description": "Generic Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_generic_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"LinuxEthernet": {
"description": "Linux Ethernet Network Input/Output",
"properties": {
"type": {
"enum": ["nio_linux_ethernet"]
},
"ethernet_device": {
"description": "Ethernet device name e.g. eth0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "ethernet_device"],
"additionalProperties": False
},
"TAP": {
"description": "TAP Network Input/Output",
"properties": {
"type": {
"enum": ["nio_tap"]
},
"tap_device": {
"description": "TAP device name e.g. tap0",
"type": "string",
"minLength": 1
},
},
"required": ["type", "tap_device"],
"additionalProperties": False
},
"UNIX": {
"description": "UNIX Network Input/Output",
"properties": {
"type": {
"enum": ["nio_unix"]
},
"local_file": {
"description": "path to the UNIX socket file (local)",
"type": "string",
"minLength": 1
},
"remote_file": {
"description": "path to the UNIX socket file (remote)",
"type": "string",
"minLength": 1
},
},
"required": ["type", "local_file", "remote_file"],
"additionalProperties": False
},
"VDE": {
"description": "VDE Network Input/Output",
"properties": {
"type": {
"enum": ["nio_vde"]
},
"control_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
"local_file": {
"description": "path to the VDE control file",
"type": "string",
"minLength": 1
},
},
"required": ["type", "control_file", "local_file"],
"additionalProperties": False
},
"NULL": {
"description": "NULL Network Input/Output",
"properties": {
"type": {
"enum": ["nio_null"]
},
},
"required": ["type"],
"additionalProperties": False
},
},
"oneOf": [
{"$ref": "#/definitions/UDP"},
{"$ref": "#/definitions/Ethernet"},
{"$ref": "#/definitions/LinuxEthernet"},
{"$ref": "#/definitions/TAP"},
{"$ref": "#/definitions/UNIX"},
{"$ref": "#/definitions/VDE"},
{"$ref": "#/definitions/NULL"},
],
"additionalProperties": True,
"required": ["type"]
}
VM_OBJECT_SCHEMA = { VM_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Dynamips VM instance", "description": "Dynamips VM instance",
@ -501,6 +654,12 @@ VM_OBJECT_SCHEMA = {
"minLength": 1, "minLength": 1,
"pattern": "^c[0-9]{4}$" "pattern": "^c[0-9]{4}$"
}, },
"chassis": {
"description": "router chassis model",
"type": "string",
"minLength": 1,
"pattern": "^[0-9]{4}(XM)?$"
},
"image": { "image": {
"description": "path to the IOS image", "description": "path to the IOS image",
"type": "string", "type": "string",