Merge pull request #1123 from GNS3/filters_dynamips

Support packet filtering for Dynamips
This commit is contained in:
Jeremy Grossmann 2017-07-12 17:23:34 +07:00 committed by GitHub
commit 9d8a8c95f6
7 changed files with 64 additions and 17 deletions

View File

@ -599,7 +599,7 @@ class BaseNode:
yield from self._ubridge_send("bridge delete {name}".format(name=name)) yield from self._ubridge_send("bridge delete {name}".format(name=name))
@asyncio.coroutine @asyncio.coroutine
def _update_ubridge_udp_connection(self, bridge_name, source_nio, destination_nio): def update_ubridge_udp_connection(self, bridge_name, source_nio, destination_nio):
yield from self._ubridge_apply_filters(bridge_name, destination_nio.filters) yield from self._ubridge_apply_filters(bridge_name, destination_nio.filters)
@asyncio.coroutine @asyncio.coroutine

View File

@ -54,6 +54,14 @@ class NIOUDP(NIO):
self._node = node self._node = node
super().__init__(name, node.hypervisor) super().__init__(name, node.hypervisor)
@property
def filters(self):
return self._filters
@filters.setter
def filters(self, val):
self._filters = val
@asyncio.coroutine @asyncio.coroutine
def create(self): def create(self):
if not self._hypervisor: if not self._hypervisor:
@ -67,7 +75,7 @@ class NIOUDP(NIO):
return return
self._local_tunnel_lport = self._node.manager.port_manager.get_free_udp_port(self._node.project) self._local_tunnel_lport = self._node.manager.port_manager.get_free_udp_port(self._node.project)
self._local_tunnel_rport = self._node.manager.port_manager.get_free_udp_port(self._node.project) self._local_tunnel_rport = self._node.manager.port_manager.get_free_udp_port(self._node.project)
name = 'DYNAMIPS-{}-{}'.format(self._local_tunnel_lport, self._local_tunnel_rport) self._bridge_name = 'DYNAMIPS-{}-{}'.format(self._local_tunnel_lport, self._local_tunnel_rport)
yield from self._hypervisor.send("nio create_udp {name} {lport} {rhost} {rport}".format(name=self._name, yield from self._hypervisor.send("nio create_udp {name} {lport} {rhost} {rport}".format(name=self._name,
lport=self._local_tunnel_lport, lport=self._local_tunnel_lport,
rhost='127.0.0.1', rhost='127.0.0.1',
@ -77,23 +85,33 @@ class NIOUDP(NIO):
lport=self._lport, lport=self._lport,
rhost=self._rhost, rhost=self._rhost,
rport=self._rport)) rport=self._rport))
yield from self._node.add_ubridge_udp_connection(
name, self._source_nio = nio_udp.NIOUDP(self._local_tunnel_rport,
nio_udp.NIOUDP(self._local_tunnel_rport,
'127.0.0.1', '127.0.0.1',
self._local_tunnel_lport, self._local_tunnel_lport,
self._filters), {})
nio_udp.NIOUDP(self._lport, self._destination_nio = nio_udp.NIOUDP(self._lport,
self._rhost, self._rhost,
self._rport, self._rport,
self._filters) self._filters)
yield from self._node.add_ubridge_udp_connection(
self._bridge_name,
self._source_nio,
self._destination_nio
) )
@asyncio.coroutine
def update(self):
self._destination_nio.filters = self._filters
yield from self._node.update_ubridge_udp_connection(
self._bridge_name,
self._source_nio,
self._destination_nio)
@asyncio.coroutine @asyncio.coroutine
def close(self): def close(self):
if self._local_tunnel_lport: if self._local_tunnel_lport:
name = 'DYNAMIPS-{}-{}'.format(self._local_tunnel_lport, self._local_tunnel_rport) yield from self._node.ubridge_delete_bridge(self._bridge_name)
yield from self._node.ubridge_delete_bridge(name)
self._node.manager.port_manager.release_udp_port(self._local_tunnel_lport, self ._node.project) self._node.manager.port_manager.release_udp_port(self._local_tunnel_lport, self ._node.project)
if self._local_tunnel_rport: if self._local_tunnel_rport:
self._node.manager.port_manager.release_udp_port(self._local_tunnel_rport, self._node.project) self._node.manager.port_manager.release_udp_port(self._local_tunnel_rport, self._node.project)

View File

@ -1290,7 +1290,7 @@ class Router(BaseNode):
:param port_number: port number :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
""" """
pass yield from nio.update()
@asyncio.coroutine @asyncio.coroutine
def slot_remove_nio_binding(self, slot_number, port_number): def slot_remove_nio_binding(self, slot_number, port_number):

View File

@ -397,7 +397,7 @@ class VPCSVM(BaseNode):
raise VPCSError("Port {port_number} doesn't exist in adapter {adapter}".format(adapter=self._ethernet_adapter, raise VPCSError("Port {port_number} doesn't exist in adapter {adapter}".format(adapter=self._ethernet_adapter,
port_number=port_number)) port_number=port_number))
if self.ubridge: if self.ubridge:
yield from self._update_ubridge_udp_connection("VPCS-{}".format(self._id), self._local_udp_tunnel[1], nio) yield from self.update_ubridge_udp_connection("VPCS-{}".format(self._id), self._local_udp_tunnel[1], nio)
elif self.is_running(): elif self.is_running():
raise VPCSError("Sorry, adding a link to a started VPCS instance is not supported without using uBridge.") raise VPCSError("Sorry, adding a link to a started VPCS instance is not supported without using uBridge.")

View File

@ -365,7 +365,7 @@ class Link:
:returns: None if no node support filtering else the node :returns: None if no node support filtering else the node
""" """
for node in self._nodes: for node in self._nodes:
if node["node"].node_type in ('vpcs', ): if node["node"].node_type in ('vpcs', 'dynamips'):
return node["node"] return node["node"]
return None return None

View File

@ -268,6 +268,35 @@ class DynamipsVMHandler:
response.set_status(201) response.set_status(201)
response.json(nio) response.json(nio)
@Route.put(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={
"project_id": "Project UUID",
"node_id": "Node UUID",
"adapter_number": "Network adapter where the nio is located",
"port_number": "Port from where the nio should be updated"
},
status_codes={
201: "NIO updated",
400: "Invalid request",
404: "Instance doesn't exist"
},
input=NIO_SCHEMA,
output=NIO_SCHEMA,
description="Update a NIO from a Dynamips instance")
def update_nio(request, response):
dynamips_manager = Dynamips.instance()
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
slot_number = int(request.match_info["adapter_number"])
port_number = int(request.match_info["port_number"])
nio = vm.slots[slot_number].get_nio(port_number)
if "filters" in request.json and nio:
nio.filters = request.json["filters"]
yield from vm.slot_update_nio_binding(slot_number, port_number, nio)
response.set_status(201)
response.json(request.json)
@Route.delete( @Route.delete(
r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio", r"/projects/{project_id}/dynamips/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio",
parameters={ parameters={

View File

@ -133,7 +133,7 @@ def test_update_ubridge_udp_connection(node, async_run):
snio = NIOUDP(1245, "localhost", 1246, []) snio = NIOUDP(1245, "localhost", 1246, [])
dnio = NIOUDP(1245, "localhost", 1244, filters) dnio = NIOUDP(1245, "localhost", 1244, filters)
with asyncio_patch("gns3server.compute.base_node.BaseNode._ubridge_apply_filters") as mock: with asyncio_patch("gns3server.compute.base_node.BaseNode._ubridge_apply_filters") as mock:
async_run(node._update_ubridge_udp_connection('VPCS-10', snio, dnio)) async_run(node.update_ubridge_udp_connection('VPCS-10', snio, dnio))
mock.assert_called_with("VPCS-10", filters) mock.assert_called_with("VPCS-10", filters)