From 4343255121c4a2e8f3fe0b6377ec9219de75eab1 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Mon, 17 Feb 2014 13:53:09 +0100 Subject: [PATCH] Fix #126 Routes configuration --- src/nepi/resources/ns3/ns3base.py | 2 +- src/nepi/resources/ns3/ns3ipv4l3protocol.py | 14 ++- src/nepi/resources/ns3/ns3netdevice.py | 21 +++- src/nepi/resources/ns3/ns3node.py | 12 +++ src/nepi/resources/ns3/ns3wrapper.py | 51 +++++++++ test/resources/linux/ns3/ns3simulation.py | 113 ++++++++++++++++++++ 6 files changed, 205 insertions(+), 8 deletions(-) diff --git a/src/nepi/resources/ns3/ns3base.py b/src/nepi/resources/ns3/ns3base.py index b0070593..e6816bf6 100644 --- a/src/nepi/resources/ns3/ns3base.py +++ b/src/nepi/resources/ns3/ns3base.py @@ -23,7 +23,7 @@ from nepi.execution.resource import ResourceManager, clsinit_copy, \ from nepi.execution.attribute import Flags from nepi.execution.trace import TraceAttr -reschedule_delay = "2s" +reschedule_delay = "1s" @clsinit_copy class NS3Base(ResourceManager): diff --git a/src/nepi/resources/ns3/ns3ipv4l3protocol.py b/src/nepi/resources/ns3/ns3ipv4l3protocol.py index 5dd08276..5eb3f45d 100644 --- a/src/nepi/resources/ns3/ns3ipv4l3protocol.py +++ b/src/nepi/resources/ns3/ns3ipv4l3protocol.py @@ -24,6 +24,11 @@ from nepi.resources.ns3.ns3base import NS3Base class NS3BaseIpv4L3Protocol(NS3Base): _rtype = "abstract::ns3::Ipv4L3Protocol" + def __init__(self, ec, guid): + super(NS3BaseIpv4L3Protocol, self).__init__(ec, guid) + self.list_routing_uuid = None + self.static_routing_uuid = None + @property def node(self): from nepi.resources.ns3.ns3node import NS3BaseNode @@ -45,11 +50,12 @@ class NS3BaseIpv4L3Protocol(NS3Base): def _configure_object(self): simulation = self.simulation - uuid_list_routing = simulation.create("Ipv4ListRouting") - simulation.invoke(self.uuid, "SetRoutingProtocol", uuid_list_routing) + self.list_routing_uuid = simulation.create("Ipv4ListRouting") + simulation.invoke(self.uuid, "SetRoutingProtocol", self.list_routing_uuid) - uuid_static_routing = simulation.create("Ipv4StaticRouting") - simulation.invoke(uuid_list_routing, "AddRoutingProtocol", uuid_static_routing, 1) + self.static_routing_uuid = simulation.create("Ipv4StaticRouting") + simulation.invoke(self.list_routing_uuid, "AddRoutingProtocol", + self.static_routing_uuid, 1) def _connect_object(self): pass diff --git a/src/nepi/resources/ns3/ns3netdevice.py b/src/nepi/resources/ns3/ns3netdevice.py index 074f0754..f136dd89 100644 --- a/src/nepi/resources/ns3/ns3netdevice.py +++ b/src/nepi/resources/ns3/ns3netdevice.py @@ -24,8 +24,6 @@ from nepi.resources.ns3.ns3base import NS3Base import ipaddr -# TODO: Validate that device must be connected to queue!! If not a segmentation fault occurs - @clsinit_copy class NS3BaseNetDevice(NS3Base): _rtype = "abstract::ns3::NetDevice" @@ -84,6 +82,18 @@ class NS3BaseNetDevice(NS3Base): return channels[0] + @property + def queue(self): + from nepi.resources.ns3.ns3queue import NS3BaseQueue + queue = self.get_connected(NS3BaseQueue.get_rtype()) + + if not queue: + msg = "Device not connected to queue" + self.error(msg) + raise RuntimeError, msg + + return queue[0] + @property def ascii_helper_uuid(self): if not self._ascii_helper_uuid: @@ -213,4 +223,9 @@ class NS3BaseNetDevice(NS3Base): if channel and channel.uuid not in self.connected: self.simulation.invoke(self.uuid, "Attach", channel.uuid) self._connected.add(channel.uuid) - + + queue = self.queue + # Verify that the device has a queue. If no queue is added a segfault + # error occurs + if queue and queue.uuid not in self.connected: + self._connected.add(queue.uuid) diff --git a/src/nepi/resources/ns3/ns3node.py b/src/nepi/resources/ns3/ns3node.py index b0e5dcf3..0d6f6917 100644 --- a/src/nepi/resources/ns3/ns3node.py +++ b/src/nepi/resources/ns3/ns3node.py @@ -50,6 +50,18 @@ class NS3BaseNode(NS3Base): if mobility: return mobility[0] return None + @property + def devices(self): + from nepi.resources.ns3.ns3netdevice import NS3BaseNetDevice + devices = self.get_connected(NS3BaseNetDevice.get_rtype()) + + if not devices: + msg = "Node not connected to devices" + self.error(msg) + raise RuntimeError, msg + + return devices + @property def _rms_to_wait(self): rms = set() diff --git a/src/nepi/resources/ns3/ns3wrapper.py b/src/nepi/resources/ns3/ns3wrapper.py index 4c2063ad..69e2b86e 100644 --- a/src/nepi/resources/ns3/ns3wrapper.py +++ b/src/nepi/resources/ns3/ns3wrapper.py @@ -210,6 +210,8 @@ class NS3Wrapper(object): def invoke(self, uuid, operation, *args, **kwargs): if operation == "isAppRunning": return self._is_app_running(uuid) + if operation == "addStaticRoute": + return self._add_static_route(uuid, *args) if uuid.startswith(SINGLETON): obj = self._singleton(uuid) @@ -459,3 +461,52 @@ class NS3Wrapper(object): return False + def _add_static_route(self, ipv4_uuid, network, prefix, nexthop): + ipv4 = self.get_object(ipv4_uuid) + + list_routing = ipv4.GetRoutingProtocol() + (static_routing, priority) = list_routing.GetRoutingProtocol(0) + + ifindex = self._find_ifindex(ipv4, nexthop) + if ifindex == -1: + return False + + nexthop = self.ns3.Ipv4Address(nexthop) + + if network in ["0.0.0.0", "0", None]: + # Default route: 0.0.0.0/0 + static_routing.SetDefaultRoute(nexthop, ifindex) + else: + mask = self.ns3.Ipv4Mask("/%s" % prefix) + network = self.ns3.Ipv4Address(network) + + if prefix == 32: + # Host route: x.y.z.w/32 + static_routing.AddHostRouteTo(network, nexthop, ifindex) + else: + # Network route: x.y.z.w/n + static_routing.AddNetworkRouteTo(network, mask, nexthop, + ifindex) + return True + + def _find_ifindex(self, ipv4, nexthop): + ifindex = -1 + + nexthop = self.ns3.Ipv4Address(nexthop) + + # For all the interfaces registered with the ipv4 object, find + # the one that matches the network of the nexthop + nifaces = ipv4.GetNInterfaces() + for ifidx in xrange(nifaces): + iface = ipv4.GetInterface(ifidx) + naddress = iface.GetNAddresses() + for addridx in xrange(naddress): + ifaddr = iface.GetAddress(addridx) + ifmask = ifaddr.GetMask() + + ifindex = ipv4.GetInterfaceForPrefix(nexthop, ifmask) + + if ifindex == ifidx: + return ifindex + return ifindex + diff --git a/test/resources/linux/ns3/ns3simulation.py b/test/resources/linux/ns3/ns3simulation.py index f289ca47..030422fc 100644 --- a/test/resources/linux/ns3/ns3simulation.py +++ b/test/resources/linux/ns3/ns3simulation.py @@ -511,6 +511,119 @@ class LinuxNS3ClientTest(unittest.TestCase): ec.shutdown() + def test_routing(self): + """ + network topology: + n4 + | + n1 -- p2p -- n2 -- csma -- n5 -- p2p -- n6 + | | + ping n6 n3 + + + """ + ec = ExperimentController(exp_id = "test-ns3-routes") + + node = ec.register_resource("LinuxNode") + ec.set(node, "hostname", self.fedora_host) + ec.set(node, "username", self.fedora_user) + ec.set(node, "identity", self.fedora_identity) + ec.set(node, "cleanProcesses", True) + #ec.set(node, "cleanHome", True) + + simu = ec.register_resource("LinuxNS3Simulation") + ec.set(simu, "verbose", True) + ec.register_connection(simu, node) + + nsnode1 = add_ns3_node(ec, simu) + p2p12 = add_point2point_device(ec, nsnode1, "10.0.0.1", "30") + + nsnode2 = add_ns3_node(ec, simu) + p2p21 = add_point2point_device(ec, nsnode2, "10.0.0.2", "30") + csma2 = add_csma_device(ec, nsnode2, "10.0.1.1", "24") + + nsnode3 = add_ns3_node(ec, simu) + csma3 = add_csma_device(ec, nsnode3, "10.0.1.2", "24") + + nsnode4 = add_ns3_node(ec, simu) + csma4 = add_csma_device(ec, nsnode4, "10.0.1.3", "24") + + nsnode5 = add_ns3_node(ec, simu) + p2p56 = add_point2point_device(ec, nsnode5, "10.0.2.1", "30") + csma5 = add_csma_device(ec, nsnode5, "10.0.1.4", "24") + + nsnode6 = add_ns3_node(ec, simu) + p2p65 = add_point2point_device(ec, nsnode6, "10.0.2.2", "30") + + # P2P chan1 + p2p_chan1 = ec.register_resource("ns3::PointToPointChannel") + ec.set(p2p_chan1, "Delay", "0s") + ec.register_connection(p2p_chan1, p2p12) + ec.register_connection(p2p_chan1, p2p21) + + # CSMA chan + csma_chan = ec.register_resource("ns3::CsmaChannel") + ec.set(csma_chan, "Delay", "0s") + ec.register_connection(csma_chan, csma2) + ec.register_connection(csma_chan, csma3) + ec.register_connection(csma_chan, csma4) + ec.register_connection(csma_chan, csma5) + + # P2P chan2 + p2p_chan2 = ec.register_resource("ns3::PointToPointChannel") + ec.set(p2p_chan2, "Delay", "0s") + ec.register_connection(p2p_chan2, p2p56) + ec.register_connection(p2p_chan2, p2p65) + + # Add routes - n1 - n6 + r1 = ec.register_resource("ns3::Route") + ec.set(r1, "Network", "10.0.2.0") + ec.set(r1, "Prefix", "30") + ec.set(r1, "Nexthop", "10.0.0.2") + ec.register_connection(r1, nsnode1) + + # Add routes - n2 - n6 + r2 = ec.register_resource("ns3::Route") + ec.set(r2, "Network", "10.0.2.0") + ec.set(r2, "Prefix", "30") + ec.set(r2, "Nexthop", "10.0.1.4") + ec.register_connection(r2, nsnode2) + + # Add routes - n5 - n1 + r5 = ec.register_resource("ns3::Route") + ec.set(r5, "Network", "10.0.0.0") + ec.set(r5, "Prefix", "30") + ec.set(r5, "Nexthop", "10.0.1.1") + ec.register_connection(r5, nsnode5) + + # Add routes - n6 - n1 + r6 = ec.register_resource("ns3::Route") + ec.set(r6, "Network", "10.0.0.0") + ec.set(r6, "Prefix", "30") + ec.set(r6, "Nexthop", "10.0.2.1") + ec.register_connection(r6, nsnode6) + + ### create pinger + ping = ec.register_resource("ns3::V4Ping") + ec.set (ping, "Remote", "10.0.2.2") + ec.set (ping, "Interval", "1s") + ec.set (ping, "Verbose", True) + ec.set (ping, "StartTime", "1s") + ec.set (ping, "StopTime", "21s") + ec.register_connection(ping, nsnode1) + + ec.deploy() + + ec.wait_finished([ping]) + + stdout = ec.trace(simu, "stdout") + + expected = "20 packets transmitted, 20 received, 0% packet loss" + self.assertTrue(stdout.find(expected) > -1) + + ec.shutdown() + + if __name__ == '__main__': unittest.main() -- 2.43.0