From 7fec46aecf3064b3a64b337e34d09302434b7ebd Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Wed, 20 Jun 2007 12:07:31 -0700 Subject: [PATCH 001/278] test --- SConstruct | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SConstruct b/SConstruct index 44f168c6b..95b3b2804 100644 --- a/SConstruct +++ b/SConstruct @@ -1,4 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +# +# +# import os.path import build From 89ea0a9911118c72db9a9ee2fc7b07536c34ac25 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 28 Jun 2007 14:29:46 -0700 Subject: [PATCH 002/278] test --- SConstruct | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/SConstruct b/SConstruct index 95b3b2804..b52a16cf5 100644 --- a/SConstruct +++ b/SConstruct @@ -1,7 +1,5 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -# -# -# + import os.path import build From b22e98aa017b2628e49228e0e9522be6afd00102 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 28 Jun 2007 14:39:56 -0700 Subject: [PATCH 003/278] test --- SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SConstruct b/SConstruct index b52a16cf5..aa77efa0d 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +# + import os.path import build From a5e90a8deae122ed11a1d62f255304f0b166f83e Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 28 Jun 2007 14:54:42 -0700 Subject: [PATCH 004/278] test --- SConstruct | 2 -- 1 file changed, 2 deletions(-) diff --git a/SConstruct b/SConstruct index aa77efa0d..b52a16cf5 100644 --- a/SConstruct +++ b/SConstruct @@ -1,7 +1,5 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -# - import os.path import build From 58d341cea3bdbe69dd1478fd3b749ffe4418038f Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 3 Jul 2007 12:43:39 -0700 Subject: [PATCH 005/278] test --- SConstruct | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SConstruct b/SConstruct index b52a16cf5..aa77efa0d 100644 --- a/SConstruct +++ b/SConstruct @@ -1,5 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +# + import os.path import build From 418275589cf5f4f19f38fc0493c1bf2ffa22969b Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 5 Jul 2007 23:27:28 -0700 Subject: [PATCH 006/278] beginnings of static routing --- src/routing/static-router.cc | 38 ++++++++++++++++ src/routing/static-router.h | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/routing/static-router.cc create mode 100644 src/routing/static-router.h diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc new file mode 100644 index 000000000..60ff0e189 --- /dev/null +++ b/src/routing/static-router.cc @@ -0,0 +1,38 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/debug.h" +#include "static-router.h" + +NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); + +namespace ns3 { + +const InterfaceId StaticRouter::iid = + MakeInterfaceId ("StaticRouter", Object::iid); + +StaticRouter::StaticRouter () +{ + SetInterfaceId (StaticRouter::iid); + NS_DEBUG("StaticRouter::StaticRouter ()"); +} + +StaticRouter::~StaticRouter () +{ + NS_DEBUG("StaticRouter::~StaticRouter ()"); +} + +} // namespace ns3 diff --git a/src/routing/static-router.h b/src/routing/static-router.h new file mode 100644 index 000000000..dcb14b570 --- /dev/null +++ b/src/routing/static-router.h @@ -0,0 +1,85 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef STATIC_ROUTER_H +#define STATIC_ROUTER_H + +#include +#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" + +namespace ns3 { + +// +// Roughly equivalent to a static incarnation of the OSPF link state header +// combined with a single Router-LSA Link Record. Since it's static, there's +// no need for age or sequence number. +// + +class StaticRouterLinkRecord +{ +public: + IpV4Address m_originator; // Router ID of this router + + enum LinkType { + PointToPoint = 1, + TransitNetwork, + StubNetwork, + VirtualLink + }; + + LinkType m_linkType; // What kind of link this is + + Ipv4Address m_linkId; // Neighbor's router ID + + union { + uint32_t m_interfaceIndex; // For unnumbered links + uint32_t m_networkMask; // For Stub Network (self) + } u; + + uint32_t m_metric; // Abstract cost of sending packets +}; + +// +// An interface aggregated to a node that provides static routing information +// to a global route manager. The presence of the interface indicates that +// the node is a router. The interface is the mechanism by which the router +// advertises its connections to neighboring routers. We're basically +// allowing the route manager to query for link state advertisements. +// + +class StaticRouter : public Object +{ +public: + static const InterfaceId iid; + StaticRouter (); + + void SetRouterId (IpV4Address routerId); + + uint32_t GetNumLinkRecords (void); + bool GetLinkRecord (uint32_t n, StaticRouterLinkRecord &lsa); + +protected: + virtual ~StaticRouter (); + + IpV4Address m_routerId; // Router ID of this router + +private: +}; + +} // namespace ns3 + +#endif /* STATIC_ROUTER_H */ From 4156e28d78834b2a877cb10d7b1f73954e70ca99 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 13:13:43 -0700 Subject: [PATCH 007/278] add example static routing script; a few changes to static-router LSAs --- SConstruct | 6 + examples/simple-static-routing.cc | 191 ++++++++++++++++++++++++++++++ src/routing/static-router.h | 73 +++++++----- 3 files changed, 239 insertions(+), 31 deletions(-) create mode 100644 examples/simple-static-routing.cc diff --git a/SConstruct b/SConstruct index aa77efa0d..4cc78440f 100644 --- a/SConstruct +++ b/SConstruct @@ -475,4 +475,10 @@ ns3.add(example_simple_p2p) example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications']) example_simple_p2p.add_source('simple-p2p.cc') +example_static_routing = build.Ns3Module('simple-static-routing', 'examples') +example_static_routing.set_executable() +ns3.add(example_static_routing) +example_static_routing.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications']) +example_static_routing.add_source('simple-static-routing.cc') + ns3.generate_dependencies() diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc new file mode 100644 index 000000000..9ad235b5e --- /dev/null +++ b/examples/simple-static-routing.cc @@ -0,0 +1,191 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ns-2 simple.tcl script (ported from ns-2) + * Originally authored by Steve McCanne, 12/19/1996 + */ + +// Port of ns-2/tcl/ex/simple.tcl to ns-3 +// +// Network topology +// +// n0 +// \ 5 Mb/s, 2ms +// \ 1.5Mb/s, 10ms +// n2 -------------------------n3 +// / +// / 5 Mb/s, 2ms +// n1 +// +// - all links are p2p links with indicated one-way BW/delay +// - CBR/UDP flows from n0 to n3, and from n3 to n1 +// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. +// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. +// (i.e., DataRate of 448,000 bps) +// - DropTail queues +// - Tracing of queues and packet receptions to file "simple-p2p.tr" + +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/p2p-channel.h" +#include "ns3/p2p-net-device.h" +#include "ns3/mac-address.h" +#include "ns3/ipv4-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/p2p-topology.h" +#include "ns3/onoff-application.h" + +using namespace ns3; + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + DebugComponentEnable("Object"); + DebugComponentEnable("Queue"); + DebugComponentEnable("DropTailQueue"); + DebugComponentEnable("Channel"); + DebugComponentEnable("PointToPointChannel"); + DebugComponentEnable("PointToPointNetDevice"); +#endif + + // Set up some default values for the simulation. Use the Bind() + // technique to tell the system what subclass of Queue to use, + // and what the queue limit is + + // The below Bind command tells the queue factory which class to + // instantiate, when the queue factory is invoked in the topology code + Bind ("Queue", "DropTailQueue"); + + Bind ("OnOffApplicationPacketSize", "210"); + Bind ("OnOffApplicationDataRate", "448kb/s"); + + //Bind ("DropTailQueue::m_maxPackets", 30); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n2, DataRate(5000000), MilliSeconds(2)); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(5000000), MilliSeconds(2)); + + Ptr channel2 = + PointToPointTopology::AddPointToPointLink ( + n2, n3, DataRate(1500000), MilliSeconds(10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.1.1"), + n2, Ipv4Address("10.1.1.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel2, n2, Ipv4Address("10.1.3.1"), + n3, Ipv4Address("10.1.3.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + PointToPointTopology::AddIpv4Routes(n0, n2, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + PointToPointTopology::AddIpv4Routes(n2, n3, channel2); + + + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + Ptr ooff = Create ( + n0, + Ipv4Address("10.1.3.2"), + 80, + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.0)); + ooff->Stop (Seconds(10.0)); + + // Create a similar flow from n3 to n1, starting at time 1.1 seconds + ooff = Create ( + n3, + Ipv4Address("10.1.2.1"), + 80, + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.1)); + ooff->Stop (Seconds(10.0)); + + // Here, finish off packet routing configuration + // This will likely set by some global StaticRouting object in the future + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); + ipv4 = n3->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-p2p.tr file + AsciiTrace asciitrace ("simple-p2p.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named simple-p2p.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("simple-p2p.pcap"); + pcaptrace.TraceAllIp (); + + Simulator::Run (); + + Simulator::Destroy (); +} diff --git a/src/routing/static-router.h b/src/routing/static-router.h index dcb14b570..41ea45aea 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -23,16 +23,15 @@ namespace ns3 { -// -// Roughly equivalent to a static incarnation of the OSPF link state header -// combined with a single Router-LSA Link Record. Since it's static, there's -// no need for age or sequence number. -// - +/** + * \brief A single link record for a link state advertisement + * + */ class StaticRouterLinkRecord { public: - IpV4Address m_originator; // Router ID of this router + uint32_t m_linkId; + Ipv4Address m_linkData; enum LinkType { PointToPoint = 1, @@ -40,44 +39,56 @@ public: StubNetwork, VirtualLink }; + + uint32_t m_metric; +} - LinkType m_linkType; // What kind of link this is +/** + * \brief a Link State Advertisement (LSA) for a router, used in static routing + * + * Roughly equivalent to a static incarnation of the OSPF link state header + * combined with a list of Link Records. Since it's static, there's + * no need for age or sequence number. See RFC 2328, Appendix A. + */ +class StaticRouterLSA +{ +public: + enum LSType { + RouterLSA = 1, + NetworkLSA + } m_LSType; + uint32_t m_linkStateId; + Ipv4Address m_advertising_rtr; + uint32_t m_numLinks; - Ipv4Address m_linkId; // Neighbor's router ID - - union { - uint32_t m_interfaceIndex; // For unnumbered links - uint32_t m_networkMask; // For Stub Network (self) - } u; - - uint32_t m_metric; // Abstract cost of sending packets + typedef std::list type_listOfLinkRecords; + type_listOfLinkRecords m_listOfLinkRecords; + type_listOfLinkRecords::iterator m_iter; }; -// -// An interface aggregated to a node that provides static routing information -// to a global route manager. The presence of the interface indicates that -// the node is a router. The interface is the mechanism by which the router -// advertises its connections to neighboring routers. We're basically -// allowing the route manager to query for link state advertisements. -// - +/** + * \brief An interface aggregated to a node to provide static routing info + * + * An interface aggregated to a node that provides static routing information + * to a global route manager. The presence of the interface indicates that + * the node is a router. The interface is the mechanism by which the router + * advertises its connections to neighboring routers. We're basically + * allowing the route manager to query for link state advertisements. + */ class StaticRouter : public Object { public: static const InterfaceId iid; - StaticRouter (); + StaticRouter (Ptr node); - void SetRouterId (IpV4Address routerId); - - uint32_t GetNumLinkRecords (void); - bool GetLinkRecord (uint32_t n, StaticRouterLinkRecord &lsa); + uint32_t GetNumLSAs (void); + bool GetLSA (uint32_t n, StaticRouterLSA &lsa); protected: virtual ~StaticRouter (); - IpV4Address m_routerId; // Router ID of this router - private: + Ptr m_node; }; } // namespace ns3 From fdda9161fe86dcbba2ee6f62d57057716c67d1c0 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 14:19:40 -0700 Subject: [PATCH 008/278] a few fixes to the LSAs --- src/routing/static-router.h | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 41ea45aea..cf3bcfe9c 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -26,21 +26,34 @@ namespace ns3 { /** * \brief A single link record for a link state advertisement * + * For Type 3 link (Stub), */ class StaticRouterLinkRecord { public: - uint32_t m_linkId; - Ipv4Address m_linkData; + // + // For Type 1 link (PointToPoint), set m_linkId to Router ID of + // neighboring router. + // + // For Type 3 link (Stub), set m_linkId to neighbor's IP address + // + Ipv4Address m_linkId; + + // + // For Type 1 link (PointToPoint), set m_linkData to local IP address + // + // For Type 3 link (Stub), set m_linkData to mask 0xffffffff + // + Ipv4Address m_linkData; // for links to RouterLSA, enum LinkType { PointToPoint = 1, TransitNetwork, StubNetwork, VirtualLink - }; + } m_linkType; - uint32_t m_metric; + uint32_t m_metric; } /** @@ -53,14 +66,10 @@ public: class StaticRouterLSA { public: - enum LSType { - RouterLSA = 1, - NetworkLSA - } m_LSType; - uint32_t m_linkStateId; - Ipv4Address m_advertising_rtr; - uint32_t m_numLinks; + Ipv4Address m_linkStateId; // set to the NodeId + Ipv4Address m_advertising_rtr; // set to the NodeId + uint32_t m_numLinks; typedef std::list type_listOfLinkRecords; type_listOfLinkRecords m_listOfLinkRecords; type_listOfLinkRecords::iterator m_iter; From 59633b8ba6edf939aee03d7b4a7da395123922f9 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 14:47:01 -0700 Subject: [PATCH 009/278] remove p2p strings in simple-static-routing example --- examples/simple-static-routing.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 9ad235b5e..b1e40033f 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -29,13 +29,13 @@ // / 5 Mb/s, 2ms // n1 // -// - all links are p2p links with indicated one-way BW/delay +// - all links are point-to-point links with indicated one-way BW/delay // - CBR/UDP flows from n0 to n3, and from n3 to n1 // - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. // - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. // (i.e., DataRate of 448,000 bps) // - DropTail queues -// - Tracing of queues and packet receptions to file "simple-p2p.tr" +// - Tracing of queues and packet receptions to file "simple-static-routing.tr" #include #include @@ -173,8 +173,8 @@ int main (int argc, char *argv[]) ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); // Configure tracing of all enqueue, dequeue, and NetDevice receive events - // Trace output will be sent to the simple-p2p.tr file - AsciiTrace asciitrace ("simple-p2p.tr"); + // Trace output will be sent to the simple-static-routing.tr file + AsciiTrace asciitrace ("simple-static-routing.tr"); asciitrace.TraceAllQueues (); asciitrace.TraceAllNetDeviceRx (); @@ -182,7 +182,7 @@ int main (int argc, char *argv[]) // The output files will be named simple-p2p.pcap-- // and can be read by the "tcpdump -r" command (use "-tt" option to // display timestamps correctly) - PcapTrace pcaptrace ("simple-p2p.pcap"); + PcapTrace pcaptrace ("simple-static-routing.pcap"); pcaptrace.TraceAllIp (); Simulator::Run (); From 7979a013711d5a197ed5a9b9e7854c277ed86c7d Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 6 Jul 2007 15:03:59 -0700 Subject: [PATCH 010/278] static routing --- examples/simple-static-routing.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 9ad235b5e..7e194c6a3 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -88,6 +88,11 @@ int main (int argc, char *argv[]) // instantiate, when the queue factory is invoked in the topology code Bind ("Queue", "DropTailQueue"); + // This bind tells the system to use global static routing. It results in + // a StaticRouter interface being aggregated to the internet nodes and the + // creation of a Route Manager component to oversee the route generation. + Bind ("DoStaticRouting", "true"); + Bind ("OnOffApplicationPacketSize", "210"); Bind ("OnOffApplicationDataRate", "448kb/s"); From 2f5acd74d97ef688fedfcc31e47dc7f955130c7a Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 6 Jul 2007 15:04:33 -0700 Subject: [PATCH 011/278] static routing --- src/internet-node/internet-node.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index 85a6a0dec..611b6c9a5 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -23,6 +23,8 @@ #include "ns3/composite-trace-resolver.h" #include "ns3/net-device.h" +#include "ns3/routing-environment.h" +#include "ns3/static-router.h" #include "l3-demux.h" #include "ipv4-l4-demux.h" @@ -37,7 +39,6 @@ namespace ns3 { - InternetNode::InternetNode() { Construct (); @@ -76,9 +77,19 @@ InternetNode::Construct (void) Object::AddInterface (udpImpl); Object::AddInterface (l3Demux); Object::AddInterface (ipv4L4Demux); +// +// If static routing has been enabled via bind(), all nodes will have the +// capacity to participate in the global static routing scheme. The presence +// of the StaticRouter interface tells the route manager that it needs to +// ask a given node about any link state records that it may want to advertise. +// + if (RoutingEnvironment::StaticRoutingEnabled()) + { + Ptr staticRouter = Create (this); + Object::AddInterface (staticRouter); + } } - TraceResolver * InternetNode::DoCreateTraceResolver (TraceContext const &context) { From d0ff4c3306651bedfccdcfe64995c8b381406df7 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 6 Jul 2007 15:05:47 -0700 Subject: [PATCH 012/278] static routing --- src/routing/static-router.cc | 4 +++- src/routing/static-router.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 60ff0e189..02b8fb95b 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -15,6 +15,7 @@ */ #include "ns3/debug.h" +#include "ns3/internet-node.h" #include "static-router.h" NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); @@ -24,7 +25,8 @@ namespace ns3 { const InterfaceId StaticRouter::iid = MakeInterfaceId ("StaticRouter", Object::iid); -StaticRouter::StaticRouter () +StaticRouter::StaticRouter (Ptr node) + : m_node(node) { SetInterfaceId (StaticRouter::iid); NS_DEBUG("StaticRouter::StaticRouter ()"); diff --git a/src/routing/static-router.h b/src/routing/static-router.h index cf3bcfe9c..234755aae 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -17,6 +17,7 @@ #define STATIC_ROUTER_H #include +#include #include "ns3/object.h" #include "ns3/ptr.h" #include "ns3/ipv4-address.h" @@ -54,7 +55,7 @@ public: } m_linkType; uint32_t m_metric; -} +}; /** * \brief a Link State Advertisement (LSA) for a router, used in static routing From 42bc462559411ecd1b08ed255e7d5e9edaf0d653 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 6 Jul 2007 15:06:26 -0700 Subject: [PATCH 013/278] static routing --- src/routing/routing-environment.cc | 39 ++++++++++++++++++++++++++++++ src/routing/routing-environment.h | 32 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/routing/routing-environment.cc create mode 100644 src/routing/routing-environment.h diff --git a/src/routing/routing-environment.cc b/src/routing/routing-environment.cc new file mode 100644 index 000000000..160bd8668 --- /dev/null +++ b/src/routing/routing-environment.cc @@ -0,0 +1,39 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/debug.h" +#include "ns3/default-value.h" + +#include "routing-environment.h" + +NS_DEBUG_COMPONENT_DEFINE ("RoutingEnvironment"); + +namespace ns3 { +namespace RoutingEnvironment { + +BooleanDefaultValue g_doStaticRoutingDefaultValue ("DoStaticRouting", + "Enable global static routing", false); + + bool +StaticRoutingEnabled(void) +{ + return g_doStaticRoutingDefaultValue.GetValue(); +} + +} // namespace RoutingEnvironment +} // namespace ns3 diff --git a/src/routing/routing-environment.h b/src/routing/routing-environment.h new file mode 100644 index 000000000..abf9da4d8 --- /dev/null +++ b/src/routing/routing-environment.h @@ -0,0 +1,32 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef ROUTING_ENVIRONMENT_H +#define ROUTING_ENVIRONMENT_H + +#include +#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" + +namespace ns3 { +namespace RoutingEnvironment { + +bool StaticRoutingEnabled(void); + +} // namespace RoutingEnvironment +} // namespace ns3 + +#endif /* ROUTING_ENVIRONMENT_H */ From 5a7dd756872ffe0f80684c9a9ec852314e41e207 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 6 Jul 2007 15:07:03 -0700 Subject: [PATCH 014/278] static routing --- SConstruct | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/SConstruct b/SConstruct index 4cc78440f..049711378 100644 --- a/SConstruct +++ b/SConstruct @@ -1,7 +1,5 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -# - import os.path import build @@ -47,8 +45,6 @@ for wscript in [ ns3.add_extra_dist('waf') ns3.add_extra_dist('waf.bat') - - # # The Core module # @@ -115,7 +111,7 @@ def config_core (env, config): core.add_config (config_core) # -# The Simu module +# The Simulator module # simu = build.Ns3Module('simulator', 'src/simulator') ns3.add(simu) @@ -178,7 +174,6 @@ def config_simulator (env, config): return retval simu.add_config (config_simulator) - # # The Common module # @@ -226,6 +221,9 @@ common.add_inst_headers([ 'data-rate.h', ]) +# +# The Node module +# node = build.Ns3Module ('node', 'src/node') ns3.add (node) node.add_deps (['core', 'common', 'simulator']) @@ -264,6 +262,9 @@ node.add_inst_headers ([ 'application.h', ]) +# +# The Applications module +# applications = build.Ns3Module ('applications', 'src/applications') ns3.add (applications) applications.add_deps (['node']) @@ -274,6 +275,9 @@ applications.add_inst_headers ([ 'onoff-application.h', ]) +# +# The Internet Node module +# inode = build.Ns3Module ('internet-node', 'src/internet-node') ns3.add (inode) inode.add_deps (['node']) @@ -339,8 +343,9 @@ inode.add_inst_headers ([ 'pcap-trace.h', ]) - - +# +# The Point-to-point module +# p2p = build.Ns3Module ('p2p', 'src/devices/p2p') ns3.add (p2p) p2p.add_deps (['node']) @@ -355,6 +360,22 @@ p2p.add_inst_headers ([ 'p2p-topology.h', ]) +# +# The Routing module +# +routing = build.Ns3Module('routing', 'src/routing') +routing.add_deps(['core']) +ns3.add(routing) +routing.add_sources([ + 'routing-environment.cc', + 'static-router.cc', + ]) +routing.add_headers ([ + ]) +routing.add_inst_headers([ + 'routing-environment.h', + 'static-router.h', + ]) # utils run_tests = build.Ns3Module('run-tests', 'utils') @@ -441,7 +462,7 @@ sample_test.add_source('main-test.cc') sample_simple = build.Ns3Module('sample-simple', 'samples') sample_simple.set_executable() ns3.add(sample_simple) -sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node']) +sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node', 'routing']) sample_simple.add_source('main-simple.cc') sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples') @@ -472,13 +493,13 @@ sample_component_manager.add_source('main-component-manager.cc') example_simple_p2p = build.Ns3Module('simple-p2p', 'examples') example_simple_p2p.set_executable() ns3.add(example_simple_p2p) -example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications']) +example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications', 'routing']) example_simple_p2p.add_source('simple-p2p.cc') example_static_routing = build.Ns3Module('simple-static-routing', 'examples') example_static_routing.set_executable() ns3.add(example_static_routing) -example_static_routing.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications']) +example_static_routing.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications', 'routing']) example_static_routing.add_source('simple-static-routing.cc') ns3.generate_dependencies() From 4d9b0f615783236d288ab41f8899616bd04e015b Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 16:21:50 -0700 Subject: [PATCH 015/278] Add routing dependency to inode in SConstruct --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index 023e15517..a91b232cf 100644 --- a/SConstruct +++ b/SConstruct @@ -284,7 +284,7 @@ applications.add_inst_headers ([ # inode = build.Ns3Module ('internet-node', 'src/internet-node') ns3.add (inode) -inode.add_deps (['node']) +inode.add_deps (['node', 'routing']) inode.add_sources ([ 'internet-node.cc', 'l3-demux.cc', From 60685f35d8d91bfb4a3b531f2ba1f29c02ba40b0 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 16:44:58 -0700 Subject: [PATCH 016/278] Add static-route-manager scaffolding --- SConstruct | 2 ++ examples/simple-static-routing.cc | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/SConstruct b/SConstruct index a91b232cf..bd90edd57 100644 --- a/SConstruct +++ b/SConstruct @@ -373,12 +373,14 @@ ns3.add(routing) routing.add_sources([ 'routing-environment.cc', 'static-router.cc', + 'static-route-manager.cc', ]) routing.add_headers ([ ]) routing.add_inst_headers([ 'routing-environment.h', 'static-router.h', + 'static-route-manager.h', ]) # utils diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 1fc92fd04..50bc38a17 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -63,6 +63,7 @@ #include "ns3/ipv4-route.h" #include "ns3/p2p-topology.h" #include "ns3/onoff-application.h" +#include "ns3/static-route-manager.h" using namespace ns3; @@ -135,6 +136,10 @@ int main (int argc, char *argv[]) channel2, n2, Ipv4Address("10.1.3.1"), n3, Ipv4Address("10.1.3.2")); + // Here, we will use the StaticRoutingManager to build routes + Ptr route_manager = Create (); + + // XXX this goes away once static routing is in place // Finally, we add static routes. These three steps (Channel and // NetDevice creation, IP Address assignment, and routing) are // separated because there may be a need to postpone IP Address From 1194823a738d56addd24784313f376e7158168fa Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 16:57:35 -0700 Subject: [PATCH 017/278] Add more scaffolding --- examples/simple-static-routing.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 50bc38a17..86726f827 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -137,7 +137,11 @@ int main (int argc, char *argv[]) n3, Ipv4Address("10.1.3.2")); // Here, we will use the StaticRoutingManager to build routes - Ptr route_manager = Create (); + Ptr routeManager = Create (); + // The below functions might better be placed in some kind of + // Simulator::Initialization function (for further study) + routeManager->BuildStaticRoutingDatabase (); + routeManager->InitializeRoutes (); // XXX this goes away once static routing is in place // Finally, we add static routes. These three steps (Channel and From 3aa83b20ff3aed7bf41225f5cf1903f842e920ae Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 6 Jul 2007 17:13:49 -0700 Subject: [PATCH 018/278] include node.h --- src/routing/static-router.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 234755aae..27070888f 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -20,6 +20,7 @@ #include #include "ns3/object.h" #include "ns3/ptr.h" +#include "ns3/node.h" #include "ns3/ipv4-address.h" namespace ns3 { From 4d0e208a2e690bf2533625d85a8695d1a5de8614 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 8 Jul 2007 13:55:03 -0700 Subject: [PATCH 019/278] Add routing module to run_tests; add node module as dependency to routing --- SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SConstruct b/SConstruct index bd90edd57..5fcd7d29b 100644 --- a/SConstruct +++ b/SConstruct @@ -368,7 +368,7 @@ p2p.add_inst_headers ([ # The Routing module # routing = build.Ns3Module('routing', 'src/routing') -routing.add_deps(['core']) +routing.add_deps(['core', 'node']) ns3.add(routing) routing.add_sources([ 'routing-environment.cc', @@ -387,7 +387,7 @@ routing.add_inst_headers([ run_tests = build.Ns3Module('run-tests', 'utils') ns3.add(run_tests) run_tests.set_executable() -run_tests.add_deps(['core', 'simulator', 'common']) +run_tests.add_deps(['core', 'simulator', 'common', 'routing']) run_tests.add_source('run-tests.cc') bench_object = build.Ns3Module('bench-object', 'utils') From 2447ea37ca70a3f5f3ae1e3d0c2a7c3c4785b11d Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 8 Jul 2007 13:55:39 -0700 Subject: [PATCH 020/278] Add Set methods to class Ipv4Address (like the non-default ctors) --- src/node/ipv4-address.cc | 11 +++++++++++ src/node/ipv4-address.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index f8ff9f7a6..2973c1775 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -135,6 +135,17 @@ Ipv4Address::Ipv4Address (char const *address) m_address = AsciiToIpv4Host (address); } +void +Ipv4Address::Set (uint32_t address) +{ + m_address = address; +} +void +Ipv4Address::Set (char const *address) +{ + m_address = AsciiToIpv4Host (address); +} + bool Ipv4Address::IsEqual (Ipv4Address other) const { diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index dc834052a..b4a020380 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -49,6 +49,22 @@ public: */ Ipv4Address (char const *address); + /** + * input address is in host order. + * \param address The host order 32-bit address + */ + void Set (uint32_t address); + /** + * \brief Sets an Ipv4Address by parsing a the input C-string + * + * Input address is in format: + * hhh.xxx.xxx.lll + * where h is the high byte and l the + * low byte + * \param address C-string containing the address as described above + */ + void Set (char const *address); + /** * \brief Comparison operation between two Ipv4Addresses * \param other address to which to compare this address From 37783c34462d62ee681c681c70807c0f44b1b3cd Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 8 Jul 2007 15:12:50 -0700 Subject: [PATCH 021/278] Add ctor/dtor to StaticRouterLSA, add the Add() method to add link records, misc. cleanup --- src/routing/static-route-manager.cc | 105 ++++++++++++++++++++++++++++ src/routing/static-route-manager.h | 94 +++++++++++++++++++++++++ src/routing/static-router.cc | 24 +++++++ src/routing/static-router.h | 8 ++- 4 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/routing/static-route-manager.cc create mode 100644 src/routing/static-route-manager.h diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc new file mode 100644 index 000000000..f9e56a841 --- /dev/null +++ b/src/routing/static-route-manager.cc @@ -0,0 +1,105 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include "ns3/assert.h" +#include "ns3/fatal-error.h" +#include "ns3/debug.h" +#include "ns3/node-list.h" +#include "static-router.h" +#include "static-route-manager.h" + +NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); + +namespace ns3 { + +StaticRouteManager::StaticRouteManager () +{ +} + +StaticRouteManager::~StaticRouteManager () +{} + +void +StaticRouteManager::BuildStaticRoutingDatabase () +{ + // walk list of nodes. QI for StaticRouter interface. + // if node has a StaticRouter interface, grab the LSAs + // from it and stick them in the LSDB + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) + { + Ptr node = *i; + NS_DEBUG_UNCOND ("node="<< node->GetId () ); + } +} + +void +StaticRouteManager::InitializeRoutes () +{ + // For each node that is a static router (which can be determined by + // the presence of StaticRouter interface), run Dijkstra SPF calculation + // on the database rooted at that router, and populate the node + // forwarding tables +} + +} // namespace ns3 + +#ifdef RUN_SELF_TESTS + +#include "ns3/test.h" + +namespace ns3 { + +class StaticRouteManagerTest : public Test { +public: + StaticRouteManagerTest (); + virtual ~StaticRouteManagerTest (); + virtual bool RunTests (void); +}; + +StaticRouteManagerTest::StaticRouteManagerTest () + : Test ("StaticRouteManager") +{ +} + +StaticRouteManagerTest::~StaticRouteManagerTest () +{} + +bool +StaticRouteManagerTest::RunTests (void) +{ + DebugComponentEnable("StaticRouteManager"); + bool ok = true; + StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord(); + lr1->m_linkId.Set(1); + lr1->m_linkData.Set(0xffffffff); + lr1->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr1->m_metric = 1; + StaticRouterLSA* lsa1 = new StaticRouterLSA(); + lsa1->m_linkStateId.Set(1); + lsa1->m_advertisingRtr.Set(1); + lsa1->Add(lr1); + + delete lsa1; + return ok; +} + +static StaticRouteManagerTest g_staticRouteManagerTest; + +} // namespace ns3 + +#endif diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h new file mode 100644 index 000000000..7b8ea5c74 --- /dev/null +++ b/src/routing/static-route-manager.h @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef STATIC_ROUTE_MANAGER_H +#define STATIC_ROUTE_MANAGER_H + +#include +#include +#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" + +namespace ns3 { + +/** + * \brief Vertex used in shortest path first (SPF) computations + * + * See RFC 2328, Section 16. + */ +class SPFVertex +{ +public: + enum VertexType { + VertexRouter = 1, + VertexNetwork + } m_vertexType; + + Ipv4Address m_vertexId; + + uint32_t m_distanceFromRoot; + + typedef std::list type_listOfSPFVertex; + type_listOfSPFVertex m_parents; + type_listOfSPFVertex m_children; + type_listOfSPFVertex::iterator m_iter; +}; + +/** + * \brief The Link State DataBase (LSDB) of a static router + */ +class StaticRouteManagerLSDB +{ +public: +}; + +/** + * \brief A global static router + * + * This singleton object can query interface each node in the system + * for a StaticRouter interface. For those nodes, it fetches one or + * more LSAs and stores them in a local database. Then, it + * can compute shortest paths on a per-node basis to all routers, and + * finally configure each of the node's forwarding tables. + * + * The design is guided by OSPFv2 RFC 2328 section 16.1.1 + * and quagga ospfd + */ +class StaticRouteManager : public Object +{ +public: + static const InterfaceId iid; + StaticRouteManager (); + /** + * \brief Build routing database by gathering LSA from each routing node + */ + virtual void BuildStaticRoutingDatabase(); + /** + * \brief Compute routes using Dijkstra SPF computation, and populate + * per-node forwarding tables + */ + virtual void InitializeRoutes(); + +protected: + virtual ~StaticRouteManager (); + +private: + StaticRouteManagerLSDB m_lsdb; +}; + +} // namespace ns3 + +#endif /* STATIC_ROUTE_MANAGER_H */ diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 02b8fb95b..5d35afc84 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -22,6 +22,30 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); namespace ns3 { +StaticRouterLSA::StaticRouterLSA () : m_linkStateId(0x66666666), + m_advertisingRtr(0x66666666), m_numLinks(0) +{ + NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); +} +StaticRouterLSA::~StaticRouterLSA () +{ + NS_DEBUG("StaticRouterLSA::~StaticRouterLSA ()"); + for (m_iter = m_listOfLinkRecords.begin(); + m_iter != m_listOfLinkRecords.end(); m_iter++) + { + NS_DEBUG_UNCOND("Deleting"); + StaticRouterLinkRecord* temp = *m_iter; + delete temp; + } +} + +uint32_t +StaticRouterLSA::Add (StaticRouterLinkRecord* lr) +{ + m_listOfLinkRecords.push_back (lr); + return m_listOfLinkRecords.size (); +} + const InterfaceId StaticRouter::iid = MakeInterfaceId ("StaticRouter", Object::iid); diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 27070888f..1a157c03b 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -67,14 +67,18 @@ public: */ class StaticRouterLSA { +public: + StaticRouterLSA(); + virtual ~StaticRouterLSA (); public: Ipv4Address m_linkStateId; // set to the NodeId - Ipv4Address m_advertising_rtr; // set to the NodeId + Ipv4Address m_advertisingRtr; // set to the NodeId uint32_t m_numLinks; - typedef std::list type_listOfLinkRecords; + typedef std::list type_listOfLinkRecords; type_listOfLinkRecords m_listOfLinkRecords; type_listOfLinkRecords::iterator m_iter; + uint32_t Add (StaticRouterLinkRecord* lr); }; /** From 9c3fa17ce21b9d69aae66488fd4a2c3f21ae7a6d Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 8 Jul 2007 15:17:45 -0700 Subject: [PATCH 022/278] Remove NS_DEBUG in destructor --- src/routing/static-router.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 5d35afc84..2edf15752 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -33,7 +33,6 @@ StaticRouterLSA::~StaticRouterLSA () for (m_iter = m_listOfLinkRecords.begin(); m_iter != m_listOfLinkRecords.end(); m_iter++) { - NS_DEBUG_UNCOND("Deleting"); StaticRouterLinkRecord* temp = *m_iter; delete temp; } From 849c347d2e31299f68cad14c9f7194e26d23ecd1 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 8 Jul 2007 15:30:17 -0700 Subject: [PATCH 023/278] Remove m_numLinks LSA member (redundant with list.size() method) --- src/routing/static-router.cc | 4 ++-- src/routing/static-router.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 2edf15752..7b9d8f143 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -22,8 +22,8 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); namespace ns3 { -StaticRouterLSA::StaticRouterLSA () : m_linkStateId(0x66666666), - m_advertisingRtr(0x66666666), m_numLinks(0) +StaticRouterLSA::StaticRouterLSA () : + m_linkStateId(0x66666666), m_advertisingRtr(0x66666666) { NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); } diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 1a157c03b..bacdfcf57 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -70,15 +70,15 @@ class StaticRouterLSA public: StaticRouterLSA(); virtual ~StaticRouterLSA (); + uint32_t Add (StaticRouterLinkRecord* lr); + public: Ipv4Address m_linkStateId; // set to the NodeId Ipv4Address m_advertisingRtr; // set to the NodeId - uint32_t m_numLinks; typedef std::list type_listOfLinkRecords; type_listOfLinkRecords m_listOfLinkRecords; type_listOfLinkRecords::iterator m_iter; - uint32_t Add (StaticRouterLinkRecord* lr); }; /** From dfb744bdf194d20440a14ddbb228b8de3ec62a69 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 9 Jul 2007 02:41:33 -0700 Subject: [PATCH 024/278] Fill out self-tests example --- src/routing/static-route-manager.cc | 115 ++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 7 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 6e9eb67a3..c327b1955 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -89,21 +89,122 @@ StaticRouteManagerTest::~StaticRouteManagerTest () bool StaticRouteManagerTest::RunTests (void) { - DebugComponentEnable("StaticRouteManager"); bool ok = true; -#if 0 + + // Build fake link state database; four routers (0-3), 3 point-to-point + // links + // + // n0 + // \ link 0 + // \ link 2 + // n2 -------------------------n3 + // / + // / link 1 + // n1 + // + // link0: 10.1.1.1/30, 10.1.1.2/30 + // link1: 10.1.2.1/30, 10.1.2.2/30 + // link2: 10.1.3.1/30, 10.1.3.2/30 + // + // Router 0 + StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord(); + lr0->m_linkId.Set(2); // router ID 0.0.0.2 + lr0->m_linkData.Set("10.1.1.1"); + lr0->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr0->m_metric = 1; StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord(); - lr1->m_linkId.Set(1); - lr1->m_linkData.Set(0xffffffff); - lr1->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr1->m_linkId.Set("10.1.1.1"); + lr1->m_linkData.Set("255.255.255.252"); + lr1->m_linkType = StaticRouterLinkRecord::StubNetwork; lr1->m_metric = 1; + StaticRouterLSA* lsa0 = new StaticRouterLSA(); + lsa0->m_linkStateId.Set(1); + lsa0->m_advertisingRtr.Set(1); + lsa0->AddLinkRecord(lr0); + lsa0->AddLinkRecord(lr1); + + // Router 1 + StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord(); + lr2->m_linkId.Set(2); // router ID 0.0.0.2 + lr2->m_linkData.Set("10.1.2.1"); + lr2->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr2->m_metric = 1; + StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord(); + lr3->m_linkId.Set("10.1.2.1"); + lr3->m_linkData.Set("255.255.255.252"); + lr3->m_linkType = StaticRouterLinkRecord::StubNetwork; + lr3->m_metric = 1; StaticRouterLSA* lsa1 = new StaticRouterLSA(); lsa1->m_linkStateId.Set(1); lsa1->m_advertisingRtr.Set(1); - lsa1->Add(lr1); + lsa1->AddLinkRecord(lr2); + lsa1->AddLinkRecord(lr3); + // Router 2 + StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord(); + lr4->m_linkId.Set("0.0.0.0"); + lr4->m_linkData.Set("10.1.1.2"); + lr4->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr4->m_metric = 1; + StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord(); + lr5->m_linkId.Set("10.1.1.2"); + lr5->m_linkData.Set("255.255.255.252"); + lr5->m_linkType = StaticRouterLinkRecord::StubNetwork; + lr5->m_metric = 1; + StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord(); + lr6->m_linkId.Set(1); + lr6->m_linkData.Set("10.1.2.2"); + lr6->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr6->m_metric = 1; + StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord(); + lr7->m_linkId.Set("10.1.2.2"); + lr7->m_linkData.Set("255.255.255.252"); + lr7->m_linkType = StaticRouterLinkRecord::StubNetwork; + lr7->m_metric = 1; + StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord(); + lr8->m_linkId.Set(3); + lr8->m_linkData.Set("10.1.3.2"); + lr8->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr8->m_metric = 1; + StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord(); + lr9->m_linkId.Set("10.1.3.2"); + lr9->m_linkData.Set("255.255.255.252"); + lr9->m_linkType = StaticRouterLinkRecord::StubNetwork; + lr9->m_metric = 1; + StaticRouterLSA* lsa2 = new StaticRouterLSA(); + lsa2->m_linkStateId.Set(2); + lsa2->m_advertisingRtr.Set(2); + lsa2->AddLinkRecord(lr4); + lsa2->AddLinkRecord(lr5); + lsa2->AddLinkRecord(lr6); + lsa2->AddLinkRecord(lr7); + lsa2->AddLinkRecord(lr8); + lsa2->AddLinkRecord(lr9); + + // Router 3 + StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord(); + lr10->m_linkId.Set(2); // router ID 0.0.0.2 + lr10->m_linkData.Set("10.1.2.1"); + lr10->m_linkType = StaticRouterLinkRecord::PointToPoint; + lr10->m_metric = 1; + StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord(); + lr11->m_linkId.Set("10.1.2.1"); + lr11->m_linkData.Set("255.255.255.252"); + lr11->m_linkType = StaticRouterLinkRecord::StubNetwork; + lr11->m_metric = 1; + StaticRouterLSA* lsa3 = new StaticRouterLSA(); + lsa3->m_linkStateId.Set(3); + lsa3->m_advertisingRtr.Set(3); + lsa3->AddLinkRecord(lr2); + lsa3->AddLinkRecord(lr3); + + // Add four LSAs to the database; XXX todo next + + delete lsa0; delete lsa1; -#endif + delete lsa2; + delete lsa3; + return ok; } From bd0cbfb5b80559613f84b66d96652fec62f1908c Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 9 Jul 2007 15:16:27 -0700 Subject: [PATCH 025/278] checkpoint --- examples/simple-static-routing.cc | 4 +- src/devices/p2p/p2p-channel.cc | 24 ++--- src/devices/p2p/p2p-channel.h | 4 +- src/node/channel.h | 27 +++-- src/routing/static-route-manager.cc | 9 ++ src/routing/static-router.cc | 161 +++++++++++++++++++++++++--- src/routing/static-router.h | 18 ++-- 7 files changed, 202 insertions(+), 45 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 86726f827..bb9dcf21e 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -42,6 +42,8 @@ #include #include +#include "ns3/debug.h" + #include "ns3/command-line.h" #include "ns3/default-value.h" #include "ns3/ptr.h" @@ -80,6 +82,7 @@ int main (int argc, char *argv[]) DebugComponentEnable("PointToPointChannel"); DebugComponentEnable("PointToPointNetDevice"); #endif + DebugComponentEnable("StaticRouter"); // Set up some default values for the simulation. Use the Bind() // technique to tell the system what subclass of Queue to use, @@ -152,7 +155,6 @@ int main (int argc, char *argv[]) PointToPointTopology::AddIpv4Routes(n1, n2, channel1); PointToPointTopology::AddIpv4Routes(n2, n3, channel2); - // Create the OnOff application to send UDP datagrams of size // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc index 2833c8bb1..c91fe368c 100644 --- a/src/devices/p2p/p2p-channel.cc +++ b/src/devices/p2p/p2p-channel.cc @@ -1,8 +1,5 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2007 University of Washington - * All rights reserved. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; @@ -15,8 +12,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Craig Dowell */ #include "p2p-channel.h" @@ -32,6 +27,7 @@ namespace ns3 { // // By default, you get a channel with the name "PointToPoint Channel" that // has an "infitely" fast transmission speed and zero delay. +// PointToPointChannel::PointToPointChannel() : Channel ("PointToPoint Channel"), @@ -91,7 +87,7 @@ PointToPointChannel::Attach(Ptr device) } } -bool + bool PointToPointChannel::TransmitStart(Packet& p, Ptr src) { NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << @@ -116,7 +112,7 @@ PointToPointChannel::TransmitStart(Packet& p, Ptr src) return true; } -bool + bool PointToPointChannel::TransmitEnd(Packet& p, Ptr src) { NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")"); @@ -144,7 +140,7 @@ PointToPointChannel::TransmitEnd(Packet& p, Ptr src) return true; } -void + void PointToPointChannel::PropagationCompleteEvent( Packet p, Ptr src) @@ -162,20 +158,25 @@ PointToPointChannel::PropagationCompleteEvent( m_link[wire].m_dst->Receive (p); } - -uint32_t + uint32_t PointToPointChannel::GetNDevices (void) const { return m_nDevices; } -Ptr + Ptr PointToPointChannel::GetDevice (uint32_t i) const { NS_ASSERT(i < 2); return m_link[i].m_src; } + Channel::ChannelType +PointToPointChannel::GetType (void) const +{ + return Channel::PointToPoint; +} + DataRate PointToPointChannel::GetDataRate (void) { @@ -188,5 +189,4 @@ PointToPointChannel::GetDelay (void) return m_delay; } - } // namespace ns3 diff --git a/src/devices/p2p/p2p-channel.h b/src/devices/p2p/p2p-channel.h index 97a251177..6bd849741 100644 --- a/src/devices/p2p/p2p-channel.h +++ b/src/devices/p2p/p2p-channel.h @@ -1,7 +1,5 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2007 University of Washington - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; @@ -96,6 +94,8 @@ public: virtual uint32_t GetNDevices (void) const; virtual Ptr GetDevice (uint32_t i) const; + virtual ChannelType GetType (void) const; + virtual DataRate GetDataRate (void); virtual Time GetDelay (void); diff --git a/src/node/channel.h b/src/node/channel.h index b2feb280b..0fa8d9656 100644 --- a/src/node/channel.h +++ b/src/node/channel.h @@ -1,7 +1,5 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2007 University of Washington - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; @@ -14,11 +12,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Craig Dowell - * - * Wed Feb 14 16:05:46 PST 2007 craigdo: Created */ + #ifndef CHANNEL_H #define CHANNEL_H @@ -41,6 +36,13 @@ class Channel : public Object { public: static const InterfaceId iid; + enum ChannelType + { + Unknown = 0, + PointToPoint, + Multipoint + }; + Channel (); Channel (std::string name); @@ -61,9 +63,18 @@ public: */ virtual Ptr GetDevice (uint32_t i) const = 0; + /** + * \returns the abstract type of this channel. Right now this is only + * PointToPoint (p2p) or Multipoint (Ethernet). + * + * This method must be implemented by subclasses. + */ + virtual ChannelType GetType (void) const = 0; + protected: - virtual ~Channel (); - std::string m_name; + virtual ~Channel (); + std::string m_name; + ChannelType m_channelType; private: }; diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index f9e56a841..6e9eb67a3 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -44,6 +44,13 @@ StaticRouteManager::BuildStaticRoutingDatabase () { Ptr node = *i; NS_DEBUG_UNCOND ("node="<< node->GetId () ); + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); + NS_ASSERT_MSG(rtr, "QI for interface failed"); + + uint32_t numLSAs = rtr->GetNumLSAs(); + NS_DEBUG_UNCOND (numLSAs << "LSAs"); } } @@ -84,6 +91,7 @@ StaticRouteManagerTest::RunTests (void) { DebugComponentEnable("StaticRouteManager"); bool ok = true; +#if 0 StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord(); lr1->m_linkId.Set(1); lr1->m_linkData.Set(0xffffffff); @@ -95,6 +103,7 @@ StaticRouteManagerTest::RunTests (void) lsa1->Add(lr1); delete lsa1; +#endif return ok; } diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 7b9d8f143..6c8f0fc28 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -15,44 +15,61 @@ */ #include "ns3/debug.h" +#include "ns3/assert.h" +#include "ns3/channel.h" +#include "ns3/net-device.h" #include "ns3/internet-node.h" +#include "ns3/ipv4.h" #include "static-router.h" NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); namespace ns3 { -StaticRouterLSA::StaticRouterLSA () : - m_linkStateId(0x66666666), m_advertisingRtr(0x66666666) +StaticRouterLSA::StaticRouterLSA() + : + m_linkStateId("0.0.0.0"), + m_advertisingRtr("0.0.0.0"), + m_linkRecords() { NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); } -StaticRouterLSA::~StaticRouterLSA () + +StaticRouterLSA::~StaticRouterLSA() { NS_DEBUG("StaticRouterLSA::~StaticRouterLSA ()"); - for (m_iter = m_listOfLinkRecords.begin(); - m_iter != m_listOfLinkRecords.end(); m_iter++) - { - StaticRouterLinkRecord* temp = *m_iter; - delete temp; - } + + for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); + i != m_linkRecords.end (); + i++) + { + NS_DEBUG("StaticRouterLSA::~StaticRouterLSA (): free link record"); + + StaticRouterLinkRecord *p = *i; + delete p; + p = 0; + + *i = 0; + } + NS_DEBUG("StaticRouterLSA::~StaticRouterLSA (): clear list"); + m_linkRecords.clear(); } -uint32_t -StaticRouterLSA::Add (StaticRouterLinkRecord* lr) + uint32_t +StaticRouterLSA::AddLinkRecord (StaticRouterLinkRecord* lr) { - m_listOfLinkRecords.push_back (lr); - return m_listOfLinkRecords.size (); + m_linkRecords.push_back (lr); + return m_linkRecords.size (); } const InterfaceId StaticRouter::iid = MakeInterfaceId ("StaticRouter", Object::iid); StaticRouter::StaticRouter (Ptr node) - : m_node(node) + : m_node(node), m_numLSAs(0) { - SetInterfaceId (StaticRouter::iid); NS_DEBUG("StaticRouter::StaticRouter ()"); + SetInterfaceId (StaticRouter::iid); } StaticRouter::~StaticRouter () @@ -60,4 +77,118 @@ StaticRouter::~StaticRouter () NS_DEBUG("StaticRouter::~StaticRouter ()"); } +// +// Return the number of Link State Advertisements this node has to advertise. +// + uint32_t +StaticRouter::GetNumLSAs (void) +{ + NS_DEBUG("StaticRouter::GetNumLSAs ()"); + NS_ASSERT_MSG(m_node, " interface not set"); +// +// We're aggregated to a node. We need to ask the node for a pointer to its +// Ipv4 interface. This is where the information regarding the attached +// interfaces lives. +// + Ptr ipv4 = m_node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4, "QI for interface failed"); +// +// Now, we need to ask Ipv4 for the number of interfaces attached to this +// node. This isn't necessarily equal to the number of links to adjacent +// nodes (other routers); the number of interfaces may include interfaces +// connected to stub networks (e.g., ethernets, etc.). So we have to walk +// through the list of net devices and see if they are directly connected +// to another router. +// +// We'll start out at the maximum possible number of LSAs and reduce that +// number if we discover a link that's not actually connected to another +// router. +// + m_numLSAs = ipv4->GetNInterfaces(); + + NS_DEBUG("StaticRouter::GetNumLSAs (): m_numLSAs = " << m_numLSAs); + + for (uint32_t i = 0; i < m_numLSAs; ++i) + { + Ptr nd = ipv4->GetNetDevice(i); + Ptr ch = nd->GetChannel(); + + if (!nd->IsPointToPoint ()) + { + NS_DEBUG("StaticRouter::GetNumLSAs (): non-point-to-point device"); + --m_numLSAs; + continue; + } + + NS_DEBUG("StaticRouter::GetNumLSAs (): point-to-point device"); +// +// Find the net device on the other end of the point-to-point channel. This +// is where our adjacent router is running. The adjacent net device is +// aggregated to a node. We need to ask that net device for its node, then +// ask that node for its Ipv4 interface and then ask the Ipv4 for the IP +// address. To do this, we have to get the interface index associated with +// that net device in order to find the correct interface on the adjacent node. +// + Ptr ndAdjacent = GetAdjacent(nd, ch); + uint32_t ifIndexAdjacent = ndAdjacent->GetIfIndex(); + Ptr nodeAdjacent = ndAdjacent->GetNode(); + Ptr ipv4Adjacent = nodeAdjacent->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4Adjacent, "QI for adjacent interface failed"); +// +// Okay, all of the preliminaries are done. We can get the IP address and +// net mask for the adjacent router. +// + Ipv4Address addrAdjacent = ipv4Adjacent->GetAddress(ifIndexAdjacent); + Ipv4Mask maskAdjacent = ipv4->GetNetworkMask(ifIndexAdjacent); + + NS_DEBUG("StaticRouter::GetNumLSAs (): Adjacent to " << addrAdjacent << + " & " << maskAdjacent); + } + + return m_numLSAs; +} + + bool +StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) +{ + return false; +} + + Ptr +StaticRouter::GetAdjacent(Ptr nd, Ptr ch) +{ +// +// Double-check that channel agrees with device that it's a point-to-point +// + NS_ASSERT(ch->GetType () == Channel::PointToPoint); + + uint32_t nDevices = ch->GetNDevices(); + NS_ASSERT_MSG(nDevices == 2, + "Point to point channel with other than two devices is not expected"); +// +// This is a point to point channel with two endpoints. Get both of them. +// + Ptr nd1 = ch->GetDevice(0); + Ptr nd2 = ch->GetDevice(1); +// +// One of the endpoints is going to be "us" -- that is the net device attached +// to the node on which we're running -- i.e., "nd". The other endpoint (the +// one to which we are connected via the channel) is the adjacent router. +// + if (nd1 == nd) + { + return nd2; + } + else if (nd2 == nd) + { + return nd1; + } + else + { + NS_ASSERT_MSG(0, + "Neither channel endpoint thinks it is connected to this net device"); + return 0; + } +} + } // namespace ns3 diff --git a/src/routing/static-router.h b/src/routing/static-router.h index bacdfcf57..9d2b4cc6a 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -21,6 +21,7 @@ #include "ns3/object.h" #include "ns3/ptr.h" #include "ns3/node.h" +#include "ns3/channel.h" #include "ns3/ipv4-address.h" namespace ns3 { @@ -69,16 +70,15 @@ class StaticRouterLSA { public: StaticRouterLSA(); - virtual ~StaticRouterLSA (); - uint32_t Add (StaticRouterLinkRecord* lr); + ~StaticRouterLSA(); + + uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); -public: Ipv4Address m_linkStateId; // set to the NodeId Ipv4Address m_advertisingRtr; // set to the NodeId - typedef std::list type_listOfLinkRecords; - type_listOfLinkRecords m_listOfLinkRecords; - type_listOfLinkRecords::iterator m_iter; + typedef std::list ListOfLinkRecords_t; + ListOfLinkRecords_t m_linkRecords; }; /** @@ -102,8 +102,12 @@ public: protected: virtual ~StaticRouter (); + Ptr m_node; + uint32_t m_numLSAs; + + Ptr GetAdjacent(Ptr nd, Ptr ch); + private: - Ptr m_node; }; } // namespace ns3 From 7ce874f5d00abfaedb18311a4dded46473480fa3 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 9 Jul 2007 22:03:41 -0700 Subject: [PATCH 026/278] checkpoint --- SConstruct | 2 +- src/routing/static-router.cc | 84 ++++++++++++++++++++++++++---------- src/routing/static-router.h | 1 + 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/SConstruct b/SConstruct index 5fcd7d29b..00a799f90 100644 --- a/SConstruct +++ b/SConstruct @@ -334,8 +334,8 @@ inode.add_headers ([ 'ipv4-end-point-demux.h', 'ipv4-end-point.h', 'ipv4-header.h', - 'udp-header.h', 'ipv4-interface.h', + 'udp-header.h', 'sgi-hashmap.h', 'udp-impl.h', ]) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 6c8f0fc28..94f393357 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -20,6 +20,7 @@ #include "ns3/net-device.h" #include "ns3/internet-node.h" #include "ns3/ipv4.h" +#include "ns3/ipv4-interface.h" #include "static-router.h" NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); @@ -90,8 +91,8 @@ StaticRouter::GetNumLSAs (void) // Ipv4 interface. This is where the information regarding the attached // interfaces lives. // - Ptr ipv4 = m_node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4, "QI for interface failed"); + Ptr ipv4Local = m_node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4Local, "QI for interface failed"); // // Now, we need to ask Ipv4 for the number of interfaces attached to this // node. This isn't necessarily equal to the number of links to adjacent @@ -104,23 +105,40 @@ StaticRouter::GetNumLSAs (void) // number if we discover a link that's not actually connected to another // router. // - m_numLSAs = ipv4->GetNInterfaces(); - - NS_DEBUG("StaticRouter::GetNumLSAs (): m_numLSAs = " << m_numLSAs); - - for (uint32_t i = 0; i < m_numLSAs; ++i) + m_numLSAs = 0; + uint32_t numDevices = m_node->GetNDevices(); + NS_DEBUG("StaticRouter::GetNumLSAs (): numDevices = " << numDevices); +// +// Loop through the devices looking for those connected to a point-to-point +// channel. These are the ones that are used to route packets. +// + for (uint32_t i = 0; i < numDevices; ++i) { - Ptr nd = ipv4->GetNetDevice(i); - Ptr ch = nd->GetChannel(); + Ptr nd = m_node->GetDevice(i); if (!nd->IsPointToPoint ()) { NS_DEBUG("StaticRouter::GetNumLSAs (): non-point-to-point device"); - --m_numLSAs; continue; } - NS_DEBUG("StaticRouter::GetNumLSAs (): point-to-point device"); + NS_DEBUG("StaticRouter::GetNumLSAs (): Point-to-point device"); +// +// Now, we have to find the Ipv4 interface whose netdevice is the one we +// just found. This is the IP on the local side of the channel. There is +// a function to do this used down in the guts of the stack, but its not +// exported so we had to whip up an equivalent. +// + uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, nd); +// +// Now that we have the Ipv4 interface index, we can get the address and mask +// we need. +// + Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); + Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); + NS_DEBUG("Working with local address " << addrLocal); + + Ptr ch = nd->GetChannel(); // // Find the net device on the other end of the point-to-point channel. This // is where our adjacent router is running. The adjacent net device is @@ -129,20 +147,23 @@ StaticRouter::GetNumLSAs (void) // address. To do this, we have to get the interface index associated with // that net device in order to find the correct interface on the adjacent node. // - Ptr ndAdjacent = GetAdjacent(nd, ch); - uint32_t ifIndexAdjacent = ndAdjacent->GetIfIndex(); - Ptr nodeAdjacent = ndAdjacent->GetNode(); - Ptr ipv4Adjacent = nodeAdjacent->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4Adjacent, "QI for adjacent interface failed"); + Ptr ndRemote = GetAdjacent(nd, ch); + Ptr nodeRemote = ndRemote->GetNode(); + Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4Remote, "QI for remote interface failed"); // -// Okay, all of the preliminaries are done. We can get the IP address and -// net mask for the adjacent router. +// Now, just like we did above, we need to get the IP interface index for the +// net device on the other end of the point-to-point channel. // - Ipv4Address addrAdjacent = ipv4Adjacent->GetAddress(ifIndexAdjacent); - Ipv4Mask maskAdjacent = ipv4->GetNetworkMask(ifIndexAdjacent); - - NS_DEBUG("StaticRouter::GetNumLSAs (): Adjacent to " << addrAdjacent << - " & " << maskAdjacent); + uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote); +// +// Now that we have the Ipv4 interface, we can get the address and mask we +// need. +// + Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote); + Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); + NS_DEBUG("Working with remote address " << addrRemote); + ++m_numLSAs; } return m_numLSAs; @@ -191,4 +212,21 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) } } + uint32_t +StaticRouter::FindIfIndexForDevice(Ptr node, Ptr nd) +{ + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4, "QI for interface failed"); + for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i ) + { + if (ipv4->GetNetDevice(i) == nd) + { + return i; + } + } + + NS_ASSERT_MSG(0, "Cannot find interface for device"); + return 0; +} + } // namespace ns3 diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 9d2b4cc6a..a3d56001e 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -106,6 +106,7 @@ protected: uint32_t m_numLSAs; Ptr GetAdjacent(Ptr nd, Ptr ch); + uint32_t FindIfIndexForDevice(Ptr node, Ptr nd); private: }; From 5487c20beb541a80073f1313d57e80f91892d192 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 9 Jul 2007 22:12:58 -0700 Subject: [PATCH 027/278] forgot to remove a header include --- src/routing/static-router.cc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 94f393357..b76565b9f 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -20,7 +20,6 @@ #include "ns3/net-device.h" #include "ns3/internet-node.h" #include "ns3/ipv4.h" -#include "ns3/ipv4-interface.h" #include "static-router.h" NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); @@ -137,17 +136,17 @@ StaticRouter::GetNumLSAs (void) Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); NS_DEBUG("Working with local address " << addrLocal); - +// +// Now, we're going to link to the remote net device on the other end of the +// point-to-point channel we know we have. This is where our adjacent router +// (to use OSPF lingo) is running. +// Ptr ch = nd->GetChannel(); -// -// Find the net device on the other end of the point-to-point channel. This -// is where our adjacent router is running. The adjacent net device is -// aggregated to a node. We need to ask that net device for its node, then -// ask that node for its Ipv4 interface and then ask the Ipv4 for the IP -// address. To do this, we have to get the interface index associated with -// that net device in order to find the correct interface on the adjacent node. -// Ptr ndRemote = GetAdjacent(nd, ch); +// +// The adjacent net device is aggregated to a node. We need to ask that net +// device for its node, then ask that node for its Ipv4 interface. +// Ptr nodeRemote = ndRemote->GetNode(); Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4Remote, "QI for remote interface failed"); @@ -157,8 +156,8 @@ StaticRouter::GetNumLSAs (void) // uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote); // -// Now that we have the Ipv4 interface, we can get the address and mask we -// need. +// Now that we have the Ipv4 interface, we can get the (remote) address and +// mask we need. // Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote); Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); From 75070e1bfaa50da0afeed93904bcfbbba7ab3428 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 9 Jul 2007 22:21:01 -0700 Subject: [PATCH 028/278] Add LSDB functions --- src/routing/static-route-manager.cc | 51 ++++++++++++++++++++++++++++- src/routing/static-route-manager.h | 9 +++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index c327b1955..fc962fd95 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -25,6 +25,49 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); namespace ns3 { +StaticRouteManagerLSDB::~StaticRouteManagerLSDB() +{ + NS_DEBUG_UNCOND("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); + +#if 0 + for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); + i != m_linkRecords.end (); + i++) + { + NS_DEBUG("StaticRouterLSA::~StaticRouterLSA (): free link record"); + + StaticRouterLinkRecord *p = *i; + delete p; + p = 0; + + *i = 0; + } +#endif + NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear list"); + //m_linkRecords.clear(); +} + +void +StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) +{ + m_database.insert(LSDBPair_t(addr, lsa)); +} + +StaticRouterLSA* +StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) +{ + // Look up an LSA by its address + LSDBMap_t::iterator i; + for (i= m_database.begin(); i!= m_database.end(); i++) + { + //Ipv4Address temp = i->first; + if (i->first == addr) + { + return i->second; + } + } + return 0; +} StaticRouteManager::StaticRouteManager () { @@ -198,7 +241,13 @@ StaticRouteManagerTest::RunTests (void) lsa3->AddLinkRecord(lr2); lsa3->AddLinkRecord(lr3); - // Add four LSAs to the database; XXX todo next + // Test the database + StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); + srmlsdb->Insert(lsa0->m_linkStateId ,lsa0); + srmlsdb->Insert(lsa1->m_linkStateId ,lsa1); + srmlsdb->Insert(lsa2->m_linkStateId ,lsa2); + srmlsdb->Insert(lsa3->m_linkStateId ,lsa3); + NS_ASSERT(lsa2 == srmlsdb->GetLSA(lsa2->m_linkStateId)); delete lsa0; delete lsa1; diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 7b8ea5c74..120252c6b 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -18,9 +18,11 @@ #include #include +#include #include "ns3/object.h" #include "ns3/ptr.h" #include "ns3/ipv4-address.h" +#include "static-router.h" namespace ns3 { @@ -53,6 +55,13 @@ public: class StaticRouteManagerLSDB { public: + ~StaticRouteManagerLSDB (); + void Insert(Ipv4Address addr, StaticRouterLSA* lsa); + StaticRouterLSA* GetLSA (Ipv4Address addr); + + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; + LSDBMap_t m_database; }; /** From d07e17d85c022a5c8aab68946e4ce2ce21693485 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 9 Jul 2007 23:07:51 -0700 Subject: [PATCH 029/278] Add LSDB destructor --- src/routing/static-route-manager.cc | 48 +++++++++++++---------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index fc962fd95..3c3cf14d6 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -27,24 +27,17 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); namespace ns3 { StaticRouteManagerLSDB::~StaticRouteManagerLSDB() { - NS_DEBUG_UNCOND("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); + NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); -#if 0 - for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); - i != m_linkRecords.end (); - i++) - { - NS_DEBUG("StaticRouterLSA::~StaticRouterLSA (): free link record"); - - StaticRouterLinkRecord *p = *i; - delete p; - p = 0; - - *i = 0; + LSDBMap_t::iterator i; + for (i= m_database.begin(); i!= m_database.end(); i++) + { + NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): free LSA"); + StaticRouterLSA* temp = i->second; + delete temp; } -#endif - NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear list"); - //m_linkRecords.clear(); + NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); + m_database.clear(); } void @@ -60,7 +53,6 @@ StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) LSDBMap_t::iterator i; for (i= m_database.begin(); i!= m_database.end(); i++) { - //Ipv4Address temp = i->first; if (i->first == addr) { return i->second; @@ -161,8 +153,8 @@ StaticRouteManagerTest::RunTests (void) lr1->m_linkType = StaticRouterLinkRecord::StubNetwork; lr1->m_metric = 1; StaticRouterLSA* lsa0 = new StaticRouterLSA(); - lsa0->m_linkStateId.Set(1); - lsa0->m_advertisingRtr.Set(1); + lsa0->m_linkStateId.Set("0.0.0.0"); + lsa0->m_advertisingRtr.Set("0.0.0.0"); lsa0->AddLinkRecord(lr0); lsa0->AddLinkRecord(lr1); @@ -243,20 +235,22 @@ StaticRouteManagerTest::RunTests (void) // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); - srmlsdb->Insert(lsa0->m_linkStateId ,lsa0); - srmlsdb->Insert(lsa1->m_linkStateId ,lsa1); - srmlsdb->Insert(lsa2->m_linkStateId ,lsa2); - srmlsdb->Insert(lsa3->m_linkStateId ,lsa3); + srmlsdb->Insert(lsa0->m_linkStateId, lsa0); + srmlsdb->Insert(lsa1->m_linkStateId, lsa1); + srmlsdb->Insert(lsa2->m_linkStateId, lsa2); + srmlsdb->Insert(lsa3->m_linkStateId, lsa3); NS_ASSERT(lsa2 == srmlsdb->GetLSA(lsa2->m_linkStateId)); - delete lsa0; - delete lsa1; - delete lsa2; - delete lsa3; + // This delete clears the LSDB, which clears the LSAs, which destroy + // the LinkRecords. + delete srmlsdb; + + // XXX next, calculate routes based on the manually created LSDB return ok; } +// Instantiate this class for the unit tests static StaticRouteManagerTest g_staticRouteManagerTest; } // namespace ns3 From 3640d302e11718ad6f61a4d656e28fd1bc74a00d Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 01:28:19 -0700 Subject: [PATCH 030/278] checkpoint --- examples/simple-static-routing.cc | 2 +- src/routing/routing-environment.cc | 9 +- src/routing/routing-environment.h | 1 + src/routing/static-route-manager.cc | 13 +- src/routing/static-router.cc | 195 ++++++++++++++++++++++++---- src/routing/static-router.h | 28 +++- 6 files changed, 212 insertions(+), 36 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index bb9dcf21e..7a366f736 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -81,8 +81,8 @@ int main (int argc, char *argv[]) DebugComponentEnable("Channel"); DebugComponentEnable("PointToPointChannel"); DebugComponentEnable("PointToPointNetDevice"); -#endif DebugComponentEnable("StaticRouter"); +#endif // Set up some default values for the simulation. Use the Bind() // technique to tell the system what subclass of Queue to use, diff --git a/src/routing/routing-environment.cc b/src/routing/routing-environment.cc index 160bd8668..73e936ca8 100644 --- a/src/routing/routing-environment.cc +++ b/src/routing/routing-environment.cc @@ -29,11 +29,18 @@ namespace RoutingEnvironment { BooleanDefaultValue g_doStaticRoutingDefaultValue ("DoStaticRouting", "Enable global static routing", false); - bool + bool StaticRoutingEnabled(void) { return g_doStaticRoutingDefaultValue.GetValue(); } + uint32_t +AllocateRouterId(void) +{ + static uint32_t routerId = 0; + return ++routerId; +} + } // namespace RoutingEnvironment } // namespace ns3 diff --git a/src/routing/routing-environment.h b/src/routing/routing-environment.h index abf9da4d8..51ee61f2b 100644 --- a/src/routing/routing-environment.h +++ b/src/routing/routing-environment.h @@ -25,6 +25,7 @@ namespace ns3 { namespace RoutingEnvironment { bool StaticRoutingEnabled(void); +uint32_t AllocateRouterId(void); } // namespace RoutingEnvironment } // namespace ns3 diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 3c3cf14d6..393128967 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -85,7 +85,18 @@ StaticRouteManager::BuildStaticRoutingDatabase () NS_ASSERT_MSG(rtr, "QI for interface failed"); uint32_t numLSAs = rtr->GetNumLSAs(); - NS_DEBUG_UNCOND (numLSAs << "LSAs"); + NS_DEBUG_UNCOND ("Found " << numLSAs << " LSAs"); + + for (uint32_t j = 0; j < numLSAs; ++j) + { + StaticRouterLSA lsa; + rtr->GetLSA(j, lsa); + NS_DEBUG_UNCOND ("LSA " << j); + NS_DEBUG_UNCOND ("----------------------------------------"); + NS_DEBUG_UNCOND("m_linkStateId = " << lsa.m_linkStateId); + NS_DEBUG_UNCOND("m_advertisingRtr = " << lsa.m_advertisingRtr); + NS_DEBUG_UNCOND ("----------------------------------------"); + } } } diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index b76565b9f..fa72622e4 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -35,15 +35,57 @@ StaticRouterLSA::StaticRouterLSA() NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); } +// +// Copy constructor for StaticRouterLSA +// +StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) + : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr) +{ + NS_DEBUG("StaticRouterLSA Copy Constructor"); + NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty before copy"); + + for ( ListOfLinkRecords_t::iterator i = lsa.m_linkRecords.begin (); + i != lsa.m_linkRecords.end (); + i++) + { + StaticRouterLinkRecord *pSrc = *i; + StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; + pDst->m_linkId = pSrc->m_linkId; + pDst->m_linkData = pSrc->m_linkData; + m_linkRecords.push_back(pDst); + pDst = 0; + } +} + +// +// Assignment operator for StaticRouterLSA +// +// This uses the non-obvious trick of taking the source LSA passed by +// value instead of by reference. This causes the copy constructor to be +// invoked (where the real work is done -- see above). All we have to do +// here is to return the newly constructed LSA. +// + StaticRouterLSA& +StaticRouterLSA::operator= (StaticRouterLSA lsa) +{ + NS_DEBUG("StaticRouterLSA Operator ="); + return *this; +} + StaticRouterLSA::~StaticRouterLSA() { NS_DEBUG("StaticRouterLSA::~StaticRouterLSA ()"); + ClearLinkRecords (); +} + void +StaticRouterLSA::ClearLinkRecords(void) +{ for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); i != m_linkRecords.end (); i++) { - NS_DEBUG("StaticRouterLSA::~StaticRouterLSA (): free link record"); + NS_DEBUG("StaticRouterLSA::ClearLinkRecords (): free link record"); StaticRouterLinkRecord *p = *i; delete p; @@ -51,7 +93,7 @@ StaticRouterLSA::~StaticRouterLSA() *i = 0; } - NS_DEBUG("StaticRouterLSA::~StaticRouterLSA (): clear list"); + NS_DEBUG("StaticRouterLSA::ClearLinkRecords(): clear list"); m_linkRecords.clear(); } @@ -62,19 +104,77 @@ StaticRouterLSA::AddLinkRecord (StaticRouterLinkRecord* lr) return m_linkRecords.size (); } + bool +StaticRouterLSA::IsEmpty (void) +{ + return m_linkRecords.size () == 0; +} + + void +StaticRouterLSA::Print (std::ostream &os) +{ + os << "m_linkStateId = " << m_linkStateId << std::endl << + "m_advertisingRtr = " << m_advertisingRtr << std::endl; + + for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); + i != m_linkRecords.end (); + i++) + { + StaticRouterLinkRecord *p = *i; + os << "----------" << std::endl; + os << "m_linkId = " << p->m_linkId << std::endl; + os << "m_linkData = " << p->m_linkData << std::endl; + } +} + +std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa) +{ + lsa.Print (os); + return os; +} + const InterfaceId StaticRouter::iid = MakeInterfaceId ("StaticRouter", Object::iid); StaticRouter::StaticRouter (Ptr node) - : m_node(node), m_numLSAs(0) + : m_node(node), m_LSAs() { NS_DEBUG("StaticRouter::StaticRouter ()"); SetInterfaceId (StaticRouter::iid); + m_routerId.Set(RoutingEnvironment::AllocateRouterId()); } StaticRouter::~StaticRouter () { NS_DEBUG("StaticRouter::~StaticRouter ()"); + ClearLSAs(); +} + + void +StaticRouter::ClearLSAs () +{ + NS_DEBUG("StaticRouter::ClearLSAs ()"); + + for ( ListOfLSAs_t::iterator i = m_LSAs.begin (); + i != m_LSAs.end (); + i++) + { + NS_DEBUG("StaticRouter::ClearLSAs (): free LSA"); + + StaticRouterLSA *p = *i; + delete p; + p = 0; + + *i = 0; + } + NS_DEBUG("StaticRouter::ClearLSAs (): clear list"); + m_LSAs.clear(); +} + + Ipv4Address + StaticRouter::GetRouterId (void) +{ + return m_routerId; } // @@ -85,6 +185,7 @@ StaticRouter::GetNumLSAs (void) { NS_DEBUG("StaticRouter::GetNumLSAs ()"); NS_ASSERT_MSG(m_node, " interface not set"); + ClearLSAs (); // // We're aggregated to a node. We need to ask the node for a pointer to its // Ipv4 interface. This is where the information regarding the attached @@ -93,29 +194,24 @@ StaticRouter::GetNumLSAs (void) Ptr ipv4Local = m_node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4Local, "QI for interface failed"); // -// Now, we need to ask Ipv4 for the number of interfaces attached to this -// node. This isn't necessarily equal to the number of links to adjacent -// nodes (other routers); the number of interfaces may include interfaces -// connected to stub networks (e.g., ethernets, etc.). So we have to walk -// through the list of net devices and see if they are directly connected -// to another router. +// We need to ask the node for the number of net devices attached. This isn't +// necessarily equal to the number of links to adjacent nodes (other routers) +// as the number of devices may include those for stub networks (e.g., +// ethernets, etc.). So we have to walk through the list of net devices and +// pay attention to those that are directly connected to another router through +// a point-to-point channel. // -// We'll start out at the maximum possible number of LSAs and reduce that -// number if we discover a link that's not actually connected to another -// router. -// - m_numLSAs = 0; uint32_t numDevices = m_node->GetNDevices(); NS_DEBUG("StaticRouter::GetNumLSAs (): numDevices = " << numDevices); // // Loop through the devices looking for those connected to a point-to-point -// channel. These are the ones that are used to route packets. +// channel. // for (uint32_t i = 0; i < numDevices; ++i) { - Ptr nd = m_node->GetDevice(i); + Ptr ndLocal = m_node->GetDevice(i); - if (!nd->IsPointToPoint ()) + if (!ndLocal->IsPointToPoint ()) { NS_DEBUG("StaticRouter::GetNumLSAs (): non-point-to-point device"); continue; @@ -124,11 +220,11 @@ StaticRouter::GetNumLSAs (void) NS_DEBUG("StaticRouter::GetNumLSAs (): Point-to-point device"); // // Now, we have to find the Ipv4 interface whose netdevice is the one we -// just found. This is the IP on the local side of the channel. There is -// a function to do this used down in the guts of the stack, but its not +// just found. This is still the IP on the local side of the channel. There +// is a function to do this used down in the guts of the stack, but it's not // exported so we had to whip up an equivalent. // - uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, nd); + uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal); // // Now that we have the Ipv4 interface index, we can get the address and mask // we need. @@ -137,12 +233,12 @@ StaticRouter::GetNumLSAs (void) Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); NS_DEBUG("Working with local address " << addrLocal); // -// Now, we're going to link to the remote net device on the other end of the -// point-to-point channel we know we have. This is where our adjacent router -// (to use OSPF lingo) is running. +// Now, we're going to walk over to the remote net device on the other end of +// the point-to-point channel we now know we have. This is where our adjacent +// router (to use OSPF lingo) is running. // - Ptr ch = nd->GetChannel(); - Ptr ndRemote = GetAdjacent(nd, ch); + Ptr ch = ndLocal->GetChannel(); + Ptr ndRemote = GetAdjacent(ndLocal, ch); // // The adjacent net device is aggregated to a node. We need to ask that net // device for its node, then ask that node for its Ipv4 interface. @@ -151,6 +247,15 @@ StaticRouter::GetNumLSAs (void) Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4Remote, "QI for remote interface failed"); // +// Per the OSPF spec, we're going to need the remote router ID, so we might as +// well get it now. +// + Ptr srRemote = + nodeRemote->QueryInterface (StaticRouter::iid); + NS_ASSERT_MSG(srRemote, "QI for remote failed"); + Ipv4Address rtrIdRemote = srRemote->GetRouterId(); + NS_DEBUG("Working with remote router " << rtrIdRemote); +// // Now, just like we did above, we need to get the IP interface index for the // net device on the other end of the point-to-point channel. // @@ -162,15 +267,51 @@ StaticRouter::GetNumLSAs (void) Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote); Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); NS_DEBUG("Working with remote address " << addrRemote); - ++m_numLSAs; +// +// Now we can fill out the link state advertisement for this link. +// + StaticRouterLSA *pLSA = new StaticRouterLSA; + pLSA->m_linkStateId = m_routerId; + pLSA->m_advertisingRtr = m_routerId; + + StaticRouterLinkRecord *plr = new StaticRouterLinkRecord; + plr->m_linkType = StaticRouterLinkRecord::PointToPoint; + plr->m_linkId = rtrIdRemote; + plr->m_linkData = addrLocal; + pLSA->AddLinkRecord(plr); + plr = 0; + + plr = new StaticRouterLinkRecord; + plr->m_linkType = StaticRouterLinkRecord::StubNetwork; + plr->m_linkId = addrRemote; + plr->m_linkData.Set(maskRemote.GetHostOrder()); // Frown + pLSA->AddLinkRecord(plr); + plr = 0; + + m_LSAs.push_back (pLSA); + NS_DEBUG(*pLSA); } - return m_numLSAs; + return m_LSAs.size (); } bool StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) { + NS_ASSERT_MSG(lsa.IsEmpty(), "Must pass empty LSA"); + + ListOfLSAs_t::iterator i = m_LSAs.begin (); + uint32_t j = 0; + + for (; i != m_LSAs.end (); i++, j++) + { + if (j == n) + { + StaticRouterLSA *p = *i; + lsa = *p; + return true; + } + } return false; } diff --git a/src/routing/static-router.h b/src/routing/static-router.h index a3d56001e..5ed6b3e79 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -23,6 +23,7 @@ #include "ns3/node.h" #include "ns3/channel.h" #include "ns3/ipv4-address.h" +#include "ns3/routing-environment.h" namespace ns3 { @@ -70,17 +71,26 @@ class StaticRouterLSA { public: StaticRouterLSA(); + StaticRouterLSA (StaticRouterLSA& lsa); ~StaticRouterLSA(); - uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); + StaticRouterLSA& operator= (StaticRouterLSA lsa); - Ipv4Address m_linkStateId; // set to the NodeId - Ipv4Address m_advertisingRtr; // set to the NodeId + uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); + void ClearLinkRecords(void); + bool IsEmpty(void); + + void Print (std::ostream &os); + + Ipv4Address m_linkStateId; + Ipv4Address m_advertisingRtr; typedef std::list ListOfLinkRecords_t; ListOfLinkRecords_t m_linkRecords; }; +std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); + /** * \brief An interface aggregated to a node to provide static routing info * @@ -96,18 +106,24 @@ public: static const InterfaceId iid; StaticRouter (Ptr node); + Ipv4Address GetRouterId(void); uint32_t GetNumLSAs (void); bool GetLSA (uint32_t n, StaticRouterLSA &lsa); protected: virtual ~StaticRouter (); - - Ptr m_node; - uint32_t m_numLSAs; + void ClearLSAs (void); Ptr GetAdjacent(Ptr nd, Ptr ch); uint32_t FindIfIndexForDevice(Ptr node, Ptr nd); + Ptr m_node; + + typedef std::list ListOfLSAs_t; + ListOfLSAs_t m_LSAs; + + Ipv4Address m_routerId; + private: }; From 0068da44d43dc44e53d496281ed1408a2488e174 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 09:31:07 -0700 Subject: [PATCH 031/278] first working router --- src/routing/static-route-manager.cc | 6 ++---- src/routing/static-router.cc | 28 +++++++++++++++++----------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 393128967..9c7097b02 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -92,10 +92,8 @@ StaticRouteManager::BuildStaticRoutingDatabase () StaticRouterLSA lsa; rtr->GetLSA(j, lsa); NS_DEBUG_UNCOND ("LSA " << j); - NS_DEBUG_UNCOND ("----------------------------------------"); - NS_DEBUG_UNCOND("m_linkStateId = " << lsa.m_linkStateId); - NS_DEBUG_UNCOND("m_advertisingRtr = " << lsa.m_advertisingRtr); - NS_DEBUG_UNCOND ("----------------------------------------"); + NS_DEBUG_UNCOND ("----------------------------"); + NS_DEBUG_UNCOND(lsa); } } } diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index fa72622e4..6f48a0f36 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -35,9 +35,6 @@ StaticRouterLSA::StaticRouterLSA() NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); } -// -// Copy constructor for StaticRouterLSA -// StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr) { @@ -57,18 +54,27 @@ StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) } } -// -// Assignment operator for StaticRouterLSA -// -// This uses the non-obvious trick of taking the source LSA passed by -// value instead of by reference. This causes the copy constructor to be -// invoked (where the real work is done -- see above). All we have to do -// here is to return the newly constructed LSA. -// StaticRouterLSA& StaticRouterLSA::operator= (StaticRouterLSA lsa) { NS_DEBUG("StaticRouterLSA Operator ="); + NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty before assignment"); + + m_linkStateId = lsa.m_linkStateId; + m_advertisingRtr = lsa.m_advertisingRtr; + + for ( ListOfLinkRecords_t::iterator i = lsa.m_linkRecords.begin (); + i != lsa.m_linkRecords.end (); + i++) + { + StaticRouterLinkRecord *pSrc = *i; + StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; + pDst->m_linkId = pSrc->m_linkId; + pDst->m_linkData = pSrc->m_linkData; + m_linkRecords.push_back(pDst); + pDst = 0; + } + return *this; } From dc80efa426602d8dd2ad4764bddf5289b9abad5a Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 10:56:27 -0700 Subject: [PATCH 032/278] convert LSDB to class SPFVertex --- src/routing/static-route-manager.cc | 182 +++++++++++++++++++++++++--- src/routing/static-route-manager.h | 16 ++- 2 files changed, 177 insertions(+), 21 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 9c7097b02..228d57078 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -25,6 +25,13 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); namespace ns3 { + +SPFVertex::~SPFVertex () +{ + delete m_lsa; +} + + StaticRouteManagerLSDB::~StaticRouteManagerLSDB() { NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); @@ -32,8 +39,8 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB() LSDBMap_t::iterator i; for (i= m_database.begin(); i!= m_database.end(); i++) { - NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): free LSA"); - StaticRouterLSA* temp = i->second; + NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB():free vertex"); + SPFVertex* temp = i->second; delete temp; } NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); @@ -41,13 +48,13 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB() } void -StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) +StaticRouteManagerLSDB::Insert(Ipv4Address addr, SPFVertex* vertex) { - m_database.insert(LSDBPair_t(addr, lsa)); + m_database.insert(LSDBPair_t(addr, vertex)); } -StaticRouterLSA* -StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) +SPFVertex* +StaticRouteManagerLSDB::GetVertex (Ipv4Address addr) { // Look up an LSA by its address LSDBMap_t::iterator i; @@ -98,15 +105,148 @@ StaticRouteManager::BuildStaticRoutingDatabase () } } -void -StaticRouteManager::InitializeRoutes () -{ // For each node that is a static router (which can be determined by // the presence of StaticRouter interface), run Dijkstra SPF calculation // on the database rooted at that router, and populate the node // forwarding tables + // +void +StaticRouteManager::InitializeRoutes () +{ +// This function parallels RFC2328, Section 16.1.1, and quagga ospfd +// +// This calculation yields the set of intra-area routes associated +// with an area (called hereafter Area A). A router calculates the +// shortest-path tree using itself as the root. The formation +// of the shortest path tree is done here in two stages. In the +// first stage, only links between routers and transit networks are +// considered. Using the Dijkstra algorithm, a tree is formed from +// this subset of the link state database. In the second stage, +// leaves are added to the tree by considering the links to stub +// networks. + +// The area's link state database is represented as a directed graph. +// The graph's vertices are routers, transit networks and stub networks. +// The first stage of the procedure (i.e., the Dijkstra algorithm) +// can now be summarized as follows. At each iteration of the +// algorithm, there is a list of candidate vertices. Paths from +// the root to these vertices have been found, but not necessarily +// the shortest ones. However, the paths to the candidate vertex +// that is closest to the root are guaranteed to be shortest; this +// vertex is added to the shortest-path tree, removed from the +// candidate list, and its adjacent vertices are examined for +// possible addition to/modification of the candidate list. The +// algorithm then iterates again. It terminates when the candidate +// list becomes empty. + + // For each node that is a router in the topology + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) + { + Ptr node = *i; + NS_DEBUG_UNCOND ("node="<< node->GetId () ); + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); + NS_ASSERT_MSG(rtr, "QI for interface failed"); + if (rtr && rtr->GetNumLSAs () ) + { + SPFCalculate(); + } + } } + +// quagga ospf_spf_next +void +StaticRouteManager::SPFNext() +{ + // if LSA == Router_LSA, examine links + // a) if link to stub, skip + // b) W is transit +} + +void +StaticRouteManager::SPFCalculate() +{ + NS_DEBUG("StaticRouteManager::SPFCalculate ()"); + /* + * struct pqueue* candidate; + * struct vertex* v; + */ + // Initialize the shortest-path tree to only the router doing the + // calculation. + // + +#if 0 + ospf_spf_init (area); + v = area->spf; + + + /* Create a new heap for the candidates. */ + candidate = pqueue_create(); + candidate->cmp = cmp; + candidate->update = update_stat; + + /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the + * * spanning tree. */ + *(v->stat) = LSA_SPF_IN_SPFTREE; + + /* Set Area A's TransitCapability to FALSE. */ + area->transit = OSPF_TRANSIT_FALSE; + area->shortcut_capability = 1; + + for (;;) + { + /* RFC2328 16.1. (2). */ + ospf_spf_next (v, area, candidate); + + /* RFC2328 16.1. (3). */ + /* If at this step the candidate list is empty, the shortest- + * path tree (of transit vertices) has been completely built and + * this stage of the procedure terminates. */ + if (candidate->size == 0) + break; + + /* Otherwise, choose the vertex belonging to the candidate list + * that is closest to the root, and add it to the shortest-path + * tree (removing it from the candidate list in the + * process). */ + /* Extract from the candidates the node with the lower key. */ + v = (struct vertex *) pqueue_dequeue (candidate); + /* Update stat field in vertex. */ + *(v->stat) = LSA_SPF_IN_SPFTREE; + + ospf_vertex_add_parent (v); + /* Note that when there is a choice of vertices closest to the + * root, network vertices must be chosen before router vertices + * in order to necessarily find all equal-cost paths. */ + /* We don't do this at this moment, we should add the treatment + * above codes. -- kunihiro. */ + + /* RFC2328 16.1. (4). */ + if (v->type == OSPF_VERTEX_ROUTER) + ospf_intra_add_router (new_rtrs, v, area); + else + ospf_intra_add_transit (new_table, v, area); + + /* RFC2328 16.1. (5). */ + /* Iterate the algorithm by returning to Step 2. */ + + } /* end loop until no more candidate vertices */ + + /* Second stage of SPF calculation procedure's */ + ospf_spf_process_stubs (area, area->spf, new_table); + + /* Free candidate queue. */ + pqueue_delete (candidate); + +#endif + + +} + + } // namespace ns3 #ifdef RUN_SELF_TESTS @@ -242,16 +382,26 @@ StaticRouteManagerTest::RunTests (void) lsa3->AddLinkRecord(lr2); lsa3->AddLinkRecord(lr3); + // Create four vertices to store these four LSAs + SPFVertex* v0 = new SPFVertex (); + v0->m_lsa = lsa0; + SPFVertex* v1 = new SPFVertex (); + v1->m_lsa = lsa1; + SPFVertex* v2 = new SPFVertex (); + v2->m_lsa = lsa2; + SPFVertex* v3 = new SPFVertex (); + v3->m_lsa = lsa3; + // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); - srmlsdb->Insert(lsa0->m_linkStateId, lsa0); - srmlsdb->Insert(lsa1->m_linkStateId, lsa1); - srmlsdb->Insert(lsa2->m_linkStateId, lsa2); - srmlsdb->Insert(lsa3->m_linkStateId, lsa3); - NS_ASSERT(lsa2 == srmlsdb->GetLSA(lsa2->m_linkStateId)); + srmlsdb->Insert(lsa0->m_linkStateId, v0); + srmlsdb->Insert(lsa1->m_linkStateId, v1); + srmlsdb->Insert(lsa2->m_linkStateId, v2); + srmlsdb->Insert(lsa3->m_linkStateId, v3); + NS_ASSERT(v2 == srmlsdb->GetVertex(lsa2->m_linkStateId)); - // This delete clears the LSDB, which clears the LSAs, which destroy - // the LinkRecords. + // This delete clears the LSDB, which clears the vertices, which deletes + // the matching LSAs, which destroys the LinkRecords. delete srmlsdb; // XXX next, calculate routes based on the manually created LSDB diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 120252c6b..1d4ce0c1e 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -34,6 +34,8 @@ namespace ns3 { class SPFVertex { public: + ~SPFVertex(); + enum VertexType { VertexRouter = 1, VertexNetwork @@ -41,12 +43,14 @@ public: Ipv4Address m_vertexId; - uint32_t m_distanceFromRoot; + StaticRouterLSA* m_lsa; // This pointer owns LSA for mem. mgmt purposes typedef std::list type_listOfSPFVertex; type_listOfSPFVertex m_parents; type_listOfSPFVertex m_children; type_listOfSPFVertex::iterator m_iter; + + uint32_t m_distanceFromRoot; }; /** @@ -56,11 +60,11 @@ class StaticRouteManagerLSDB { public: ~StaticRouteManagerLSDB (); - void Insert(Ipv4Address addr, StaticRouterLSA* lsa); - StaticRouterLSA* GetLSA (Ipv4Address addr); + void Insert(Ipv4Address addr, SPFVertex* vertex); + SPFVertex* GetVertex (Ipv4Address addr); - typedef std::map LSDBMap_t; - typedef std::pair LSDBPair_t; + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; LSDBMap_t m_database; }; @@ -96,6 +100,8 @@ protected: private: StaticRouteManagerLSDB m_lsdb; + void SPFCalculate (); + void SPFNext (); }; } // namespace ns3 From 71d55ebf18e431a56564fe487a6c9e0752fdea25 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 11:29:08 -0700 Subject: [PATCH 033/278] more plumbing around SPFCalculate() --- src/routing/static-route-manager.cc | 49 ++++++++++++++++++++++++----- src/routing/static-route-manager.h | 15 +++++++-- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 228d57078..867baeadd 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -68,12 +68,24 @@ StaticRouteManagerLSDB::GetVertex (Ipv4Address addr) return 0; } -StaticRouteManager::StaticRouteManager () +StaticRouteManager::StaticRouteManager () { + m_lsdb = new StaticRouteManagerLSDB (); } StaticRouteManager::~StaticRouteManager () -{} +{ + if (m_lsdb) + delete m_lsdb; +} + +void +StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) +{ + if (m_lsdb) + delete m_lsdb; + m_lsdb = lsdb; +} void StaticRouteManager::BuildStaticRoutingDatabase () @@ -113,6 +125,7 @@ StaticRouteManager::BuildStaticRoutingDatabase () void StaticRouteManager::InitializeRoutes () { + NS_DEBUG_UNCOND("StaticRouteManager::InitializeRoutes ()"); // This function parallels RFC2328, Section 16.1.1, and quagga ospfd // // This calculation yields the set of intra-area routes associated @@ -151,7 +164,7 @@ StaticRouteManager::InitializeRoutes () NS_ASSERT_MSG(rtr, "QI for interface failed"); if (rtr && rtr->GetNumLSAs () ) { - SPFCalculate(); + SPFCalculate(rtr->GetRouterId ()); } } } @@ -166,8 +179,16 @@ StaticRouteManager::SPFNext() // b) W is transit } +// quagga ospf_spf_calculate void -StaticRouteManager::SPFCalculate() +StaticRouteManager::DebugSPFCalculate(Ipv4Address root) +{ + SPFCalculate(root); +} + +// quagga ospf_spf_calculate +void +StaticRouteManager::SPFCalculate(Ipv4Address root) { NS_DEBUG("StaticRouteManager::SPFCalculate ()"); /* @@ -385,12 +406,20 @@ StaticRouteManagerTest::RunTests (void) // Create four vertices to store these four LSAs SPFVertex* v0 = new SPFVertex (); v0->m_lsa = lsa0; + v0->m_vertexType = SPFVertex::VertexRouter; + v0->m_distanceFromRoot = 0xffffffff; SPFVertex* v1 = new SPFVertex (); v1->m_lsa = lsa1; + v0->m_vertexType = SPFVertex::VertexRouter; + v0->m_distanceFromRoot = 0xffffffff; SPFVertex* v2 = new SPFVertex (); v2->m_lsa = lsa2; + v0->m_vertexType = SPFVertex::VertexRouter; + v0->m_distanceFromRoot = 0xffffffff; SPFVertex* v3 = new SPFVertex (); v3->m_lsa = lsa3; + v0->m_vertexType = SPFVertex::VertexRouter; + v0->m_distanceFromRoot = 0xffffffff; // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); @@ -400,11 +429,15 @@ StaticRouteManagerTest::RunTests (void) srmlsdb->Insert(lsa3->m_linkStateId, v3); NS_ASSERT(v2 == srmlsdb->GetVertex(lsa2->m_linkStateId)); - // This delete clears the LSDB, which clears the vertices, which deletes - // the matching LSAs, which destroys the LinkRecords. - delete srmlsdb; - // XXX next, calculate routes based on the manually created LSDB + StaticRouteManager* srm = new StaticRouteManager(); + srm->DebugUseLsdb (srmlsdb); + srm->DebugSPFCalculate(lsa0->m_linkStateId); // node n0 + + // This delete clears the srm, which deletes the LSDB, which clears + // all of the vertices, which each destroy the matching LSAs, which each + // destroys the attached LinkRecords. + delete srm; return ok; } diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 1d4ce0c1e..6e0ac608f 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -95,12 +95,21 @@ public: */ virtual void InitializeRoutes(); -protected: + /** + * \brief Debugging routine; allow client code to supply a pre-built LSDB + */ + void DebugUseLsdb (StaticRouteManagerLSDB*); + /** + * \brief Debugging routine; call the core SPF from the unit tests + */ + void DebugSPFCalculate (Ipv4Address root); + virtual ~StaticRouteManager (); +protected: private: - StaticRouteManagerLSDB m_lsdb; - void SPFCalculate (); + StaticRouteManagerLSDB* m_lsdb; + void SPFCalculate (Ipv4Address root); void SPFNext (); }; From 05d649ef54db2ec8fafb007dbeab020dfedb072c Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 12:38:51 -0700 Subject: [PATCH 034/278] doxygen --- src/routing/static-router.cc | 25 +++++- src/routing/static-router.h | 152 ++++++++++++++++++++++++++++++++--- 2 files changed, 161 insertions(+), 16 deletions(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 6f48a0f36..6f1fd245b 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -55,7 +55,7 @@ StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) } StaticRouterLSA& -StaticRouterLSA::operator= (StaticRouterLSA lsa) +StaticRouterLSA::operator= (StaticRouterLSA& lsa) { NS_DEBUG("StaticRouterLSA Operator ="); NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty before assignment"); @@ -274,7 +274,10 @@ StaticRouter::GetNumLSAs (void) Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); NS_DEBUG("Working with remote address " << addrRemote); // -// Now we can fill out the link state advertisement for this link. +// Now we can fill out the link state advertisement for this link. There +// are always two link records; the first is a point-to-point record +// describing the link and the second is a stub network record with the +// network number. // StaticRouterLSA *pLSA = new StaticRouterLSA; pLSA->m_linkStateId = m_routerId; @@ -301,11 +304,18 @@ StaticRouter::GetNumLSAs (void) return m_LSAs.size (); } +// +// Get the nth link state advertisement from this router. +// bool StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) { NS_ASSERT_MSG(lsa.IsEmpty(), "Must pass empty LSA"); - +// +// All of the work was done in GetNumLSAs. All we have to do here is to +// walk the list of link state advertisements created there and return the +// one the client is interested in. +// ListOfLSAs_t::iterator i = m_LSAs.begin (); uint32_t j = 0; @@ -318,9 +328,14 @@ StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) return true; } } + return false; } +// +// Link through the given channel and find the net device that's on the +// other end. This only makes sense with a point-to-point channel. +// Ptr StaticRouter::GetAdjacent(Ptr nd, Ptr ch) { @@ -358,6 +373,10 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) } } +// +// Given a node and a net device, find the IPV4 interface index that +// corresponds to that net device. +// uint32_t StaticRouter::FindIfIndexForDevice(Ptr node, Ptr nd) { diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 5ed6b3e79..0d0cd09ac 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -28,7 +28,11 @@ namespace ns3 { /** - * \brief A single link record for a link state advertisement + * \brief A single link record for a link state advertisement. + * + * The StaticRouterLinkRecord is modeled after the OSPF link record field of + * a Link State Advertisement. Right now we will only see two types of link + * records corresponding to a stub network and a point-to-point link (channel). * * For Type 3 link (Stub), */ @@ -49,14 +53,24 @@ public: // For Type 3 link (Stub), set m_linkData to mask 0xffffffff // Ipv4Address m_linkData; // for links to RouterLSA, - + /** + * Enumeration of the possible types of Static Router Link Records. These + * are defined in the OSPF spec. We currently only use PointToPoint and + * StubNetwork types. + */ enum LinkType { - PointToPoint = 1, - TransitNetwork, - StubNetwork, - VirtualLink + PointToPoint = 1, /**< Record representing a point to point channel */ + TransitNetwork, /**< Unused -- for future OSPF compatibility */ + StubNetwork, /**< Record represents a leaf node network */ + VirtualLink /**< Unused -- for future OSPF compatibility */ } m_linkType; - + /** + * An abstract cost associated with forwarding a packet across a link. + * A sum of metrics must have a well-defined meaning. That is, you shouldn't + * use bandwidth as a metric (how does the sum of the bandwidth of two hops + * relate to the cost of sending a packet); rather you should use something + * like delay. + */ uint32_t m_metric; }; @@ -70,19 +84,77 @@ public: class StaticRouterLSA { public: + /** + * Create a blank Static Router Link State Advertisement. On completion, + * any Ipv4Address variables initialized to 0.0.0.0 and the list of Link + * State Records is empty. + */ StaticRouterLSA(); + /** + * Copy constructor for a Static Router Link State Advertisement. + * Takes a piece of memory and constructs a semantically identical copy of + * the given LSA. + * + * @param lsa The existing LSA to be used as the source. + */ StaticRouterLSA (StaticRouterLSA& lsa); + /** + * Destroy an existing Static Router Link State Advertisement. Any Static + * router Link Records present in the list are freed. + */ ~StaticRouterLSA(); - - StaticRouterLSA& operator= (StaticRouterLSA lsa); - + /** + * Assignment operator for a Static Router Link State Advertisement. + * Takes an existing Static Router Link State Advertisement and overwrites + * it to make a semantically identical copy of a given prototype LSA. + * + * If there are any Static Router Link Records present in the existing + * LSA, they are freed before the assignment happens. + * + * @param lsa The existing LSA to be used as the source. + * @returns Reference to the overwritten LSA. + */ + StaticRouterLSA& operator= (StaticRouterLSA& lsa); + /** + * Add a given Static Router Link Record to a given Static Router Link + * State Advertisement. + * + * @param lr The Static Router Link Record to be added. + * @returns The number of link records in the list. + */ uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); + /** + * Release all of the Static Router Link Records present in the Static + * Router Link State Advertisement and make the list of link records empty. + */ void ClearLinkRecords(void); + /** + * Check to see of the list of Static Router Link Records present in the + * Static Router Link State Advertisement is empty. + * + * @returns True if the list is empty, false otherwise. + */ bool IsEmpty(void); - + /** + * Print the contents of the Static Router Link State Advertisement and + * any Static Router Link Records present in the list. Quite verbose. + */ void Print (std::ostream &os); - + /** + * The Link State ID is defined by the OSPF spec. We always set it to the + * router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + */ Ipv4Address m_linkStateId; + /** + * The Advertising Router is defined by the OSPF spec. We always set it to + * the router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + */ Ipv4Address m_advertisingRtr; typedef std::list ListOfLinkRecords_t; @@ -103,11 +175,65 @@ std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); class StaticRouter : public Object { public: + /** + * The Interface ID of the Static Router interface. + * + * @see Object::QueryInterface () + */ static const InterfaceId iid; + /** + * Create a Static Router class and aggregate its interface onto the Node + * provided. + * + * @param lsa The existing Node onto which this router will be aggregated. + */ StaticRouter (Ptr node); - + /** + * Get the Router ID associated with this Static Router. The Router IDs + * are allocated in the RoutingEnvironment -- one per Router, starting at + * 0.0.0.1 and incrementing with each instantiation of a router. + * + * @see RoutingEnvironment::AllocateRouterId () + * @returns The Router ID associated with the Static Router. + */ Ipv4Address GetRouterId(void); + /** + * Get the Number of Static Router Link State Advertisements that this + * router can export. + * + * This is a fairly expensive operation in that every time it is called + * the current list of LSAs is built by walking connected point-to-point + * channels and peeking into adjacent IPV4 stacks to get address information. + * This is done to allow for limited dymanics of the Static Routing + * environment. By that we mean that you can discover new link state + * advertisements after a network topology change by calling GetNumLSAs and + * then by reading those advertisements. + * + * @see StaticRouterLSA + * @see StaticRouter::GetLSA () + * @returns The number of Static Router Link State Advertisements. + */ uint32_t GetNumLSAs (void); + /** + * Get a Static Router Link State Advertisements that this router has said + * that it can export. + * + * This is a fairly inexpensive expensive operation in that the hard work + * was done in GetNumLSAs. We just copy the indicated Static Router Link + * State Advertisement into the requested StaticRouterLSA object. + * + * You must call StaticRouter::GetNumLSAs before calling this method in + * order to discover the adjacent routers and build the advertisements. + * GetNumLSAs will return the number of LSAs this router advertises. + * The parameter n (requested LSA number) must be in the range 0 to + * GetNumLSAs() - 1. + * + * @see StaticRouterLSA + * @see StaticRouter::GetNumLSAs () + * @param n The index number of the LSA you want to read. + * @param lsa The StaticRouterLSA class to receive the LSA information. + * @returns The number of Static Router Link State Advertisements. + */ bool GetLSA (uint32_t n, StaticRouterLSA &lsa); protected: From b10355c846476624088a60ed4329f9635d4eec44 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 13:01:43 -0700 Subject: [PATCH 035/278] made GetNumLSAs cheap, added DiscoverLSAs as expensive call. --- src/routing/static-route-manager.cc | 8 ++++++-- src/routing/static-router.cc | 20 ++++++++++++++------ src/routing/static-router.h | 24 +++++++++++++++++++----- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 867baeadd..cecd0d9cf 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -102,8 +102,12 @@ StaticRouteManager::BuildStaticRoutingDatabase () Ptr rtr = node->QueryInterface (StaticRouter::iid); NS_ASSERT_MSG(rtr, "QI for interface failed"); - - uint32_t numLSAs = rtr->GetNumLSAs(); +// +// Should call DiscoverLSAs () before trying to use any routing info or to +// update LSAs. Subsequently you may use GetNumLSAs(). If you call +// GetNumLSAs () before calling DiscoverLSAs () will get zero as the number. +// + uint32_t numLSAs = rtr->DiscoverLSAs(); NS_DEBUG_UNCOND ("Found " << numLSAs << " LSAs"); for (uint32_t j = 0; j < numLSAs; ++j) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 6f1fd245b..f8ff27657 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -184,12 +184,13 @@ StaticRouter::ClearLSAs () } // -// Return the number of Link State Advertisements this node has to advertise. +// Go out and discover any adjacent routers and build the Link State +// Advertisements that reflect them and their associated networks. // uint32_t -StaticRouter::GetNumLSAs (void) +StaticRouter::DiscoverLSAs (void) { - NS_DEBUG("StaticRouter::GetNumLSAs ()"); + NS_DEBUG("StaticRouter::DiscoverLSAs ()"); NS_ASSERT_MSG(m_node, " interface not set"); ClearLSAs (); // @@ -208,7 +209,7 @@ StaticRouter::GetNumLSAs (void) // a point-to-point channel. // uint32_t numDevices = m_node->GetNDevices(); - NS_DEBUG("StaticRouter::GetNumLSAs (): numDevices = " << numDevices); + NS_DEBUG("StaticRouter::DiscoverLSAs (): numDevices = " << numDevices); // // Loop through the devices looking for those connected to a point-to-point // channel. @@ -219,11 +220,11 @@ StaticRouter::GetNumLSAs (void) if (!ndLocal->IsPointToPoint ()) { - NS_DEBUG("StaticRouter::GetNumLSAs (): non-point-to-point device"); + NS_DEBUG("StaticRouter::DiscoverLSAs (): non-point-to-point device"); continue; } - NS_DEBUG("StaticRouter::GetNumLSAs (): Point-to-point device"); + NS_DEBUG("StaticRouter::DiscoverLSAs (): Point-to-point device"); // // Now, we have to find the Ipv4 interface whose netdevice is the one we // just found. This is still the IP on the local side of the channel. There @@ -304,6 +305,13 @@ StaticRouter::GetNumLSAs (void) return m_LSAs.size (); } + uint32_t +StaticRouter::GetNumLSAs (void) +{ + NS_DEBUG("StaticRouter::GetNumLSAs ()"); + return m_LSAs.size (); +} + // // Get the nth link state advertisement from this router. // diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 0d0cd09ac..f3273c311 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -185,7 +185,7 @@ public: * Create a Static Router class and aggregate its interface onto the Node * provided. * - * @param lsa The existing Node onto which this router will be aggregated. + * @param node The existing Node onto which this router will be aggregated. */ StaticRouter (Ptr node); /** @@ -198,21 +198,35 @@ public: */ Ipv4Address GetRouterId(void); /** - * Get the Number of Static Router Link State Advertisements that this - * router can export. + * Walk the connected channels, discover the adjacent routers and build + * the associated number of Static Router Link State Advertisements that + * this router can export. * * This is a fairly expensive operation in that every time it is called * the current list of LSAs is built by walking connected point-to-point * channels and peeking into adjacent IPV4 stacks to get address information. * This is done to allow for limited dymanics of the Static Routing * environment. By that we mean that you can discover new link state - * advertisements after a network topology change by calling GetNumLSAs and - * then by reading those advertisements. + * advertisements after a network topology change by calling DiscoverLSAs + * and then by reading those advertisements. * * @see StaticRouterLSA * @see StaticRouter::GetLSA () * @returns The number of Static Router Link State Advertisements. */ + uint32_t DiscoverLSAs (void); + /** + * Get the Number of Static Router Link State Advertisements that this + * router can export. To get meaningful information you must have + * previously called DiscoverLSAs. After you know how many LSAs are + * present in the router, you may call GetLSA () to retrieve the actual + * advertisement. + * + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @see StaticRouter::GetLSA () + * @returns The number of Static Router Link State Advertisements. + */ uint32_t GetNumLSAs (void); /** * Get a Static Router Link State Advertisements that this router has said From 0fc2f3d86d64e4b34d08c7c7b83801549d6fe76a Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 13:28:07 -0700 Subject: [PATCH 036/278] SPFVertex constructor --- src/routing/static-route-manager.cc | 13 +++++++++++++ src/routing/static-route-manager.h | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 867baeadd..b7bb13f3f 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -15,6 +15,7 @@ */ #include #include +#include #include "ns3/assert.h" #include "ns3/fatal-error.h" #include "ns3/debug.h" @@ -26,6 +27,15 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); namespace ns3 { +SPFVertex::SPFVertex () : + m_vertexType(VertexUnknown), + m_vertexId("255.255.255.255"), + m_lsa(0), + m_distanceFromRoot(SPF_INFINITY), + m_stat(false) +{ +} + SPFVertex::~SPFVertex () { delete m_lsa; @@ -191,6 +201,9 @@ void StaticRouteManager::SPFCalculate(Ipv4Address root) { NS_DEBUG("StaticRouteManager::SPFCalculate ()"); + // Make a priority queue of int using a vector container + // priority_queue, less > pq; + //priority_queue, less > candidate; /* * struct pqueue* candidate; * struct vertex* v; diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 6e0ac608f..861da5c13 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -26,6 +26,8 @@ namespace ns3 { +const uint32_t SPF_INFINITY = 0xffffffff; + /** * \brief Vertex used in shortest path first (SPF) computations * @@ -34,10 +36,12 @@ namespace ns3 { class SPFVertex { public: + SPFVertex(); ~SPFVertex(); enum VertexType { - VertexRouter = 1, + VertexUnknown = 0, + VertexRouter, VertexNetwork } m_vertexType; @@ -51,6 +55,8 @@ public: type_listOfSPFVertex::iterator m_iter; uint32_t m_distanceFromRoot; + + bool m_stat; // true if LSA is in SPF tree already }; /** From 42019fca7cd22d6e662865b92f82d0ee25d62fc3 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 13:34:23 -0700 Subject: [PATCH 037/278] Initialize LSDB for SPF runs --- src/routing/static-route-manager.cc | 31 ++++++++++++++++++++++++----- src/routing/static-route-manager.h | 5 +++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index b7bb13f3f..ed8c68c3d 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -41,6 +41,14 @@ SPFVertex::~SPFVertex () delete m_lsa; } +void +SPFVertex::Initialize () +{ + m_distanceFromRoot = SPF_INFINITY; + m_stat = false; + // XXX previous = 0 +} + StaticRouteManagerLSDB::~StaticRouteManagerLSDB() { @@ -48,7 +56,7 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB() LSDBMap_t::iterator i; for (i= m_database.begin(); i!= m_database.end(); i++) - { + { NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB():free vertex"); SPFVertex* temp = i->second; delete temp; @@ -57,6 +65,19 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB() m_database.clear(); } +void +StaticRouteManagerLSDB::Initialize() +{ + NS_DEBUG("StaticRouteManagerLSDB::Initialize ()"); + + LSDBMap_t::iterator i; + for (i= m_database.begin(); i!= m_database.end(); i++) + { + SPFVertex* temp = i->second; + temp->Initialize(); + } +} + void StaticRouteManagerLSDB::Insert(Ipv4Address addr, SPFVertex* vertex) { @@ -201,6 +222,10 @@ void StaticRouteManager::SPFCalculate(Ipv4Address root) { NS_DEBUG("StaticRouteManager::SPFCalculate ()"); + + // The SPFVertex objects may have state from a previous computation + m_lsdb->Initialize(); + // Make a priority queue of int using a vector container // priority_queue, less > pq; //priority_queue, less > candidate; @@ -420,19 +445,15 @@ StaticRouteManagerTest::RunTests (void) SPFVertex* v0 = new SPFVertex (); v0->m_lsa = lsa0; v0->m_vertexType = SPFVertex::VertexRouter; - v0->m_distanceFromRoot = 0xffffffff; SPFVertex* v1 = new SPFVertex (); v1->m_lsa = lsa1; v0->m_vertexType = SPFVertex::VertexRouter; - v0->m_distanceFromRoot = 0xffffffff; SPFVertex* v2 = new SPFVertex (); v2->m_lsa = lsa2; v0->m_vertexType = SPFVertex::VertexRouter; - v0->m_distanceFromRoot = 0xffffffff; SPFVertex* v3 = new SPFVertex (); v3->m_lsa = lsa3; v0->m_vertexType = SPFVertex::VertexRouter; - v0->m_distanceFromRoot = 0xffffffff; // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 861da5c13..84b1a2e29 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -38,6 +38,7 @@ class SPFVertex public: SPFVertex(); ~SPFVertex(); + void Initialize (); enum VertexType { VertexUnknown = 0, @@ -68,6 +69,10 @@ public: ~StaticRouteManagerLSDB (); void Insert(Ipv4Address addr, SPFVertex* vertex); SPFVertex* GetVertex (Ipv4Address addr); + /** + * \brief Set all SPFVertex to an initialized state, for SPF computation + */ + void Initialize (); typedef std::map LSDBMap_t; typedef std::pair LSDBPair_t; From 3adfd850c723b812ae1a2aba55ebcf7e4efde345 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 13:39:54 -0700 Subject: [PATCH 038/278] Initialize SPFCalculate --- src/routing/static-route-manager.cc | 35 +++++++++-------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index ed8c68c3d..888892b1c 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -225,36 +225,23 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // The SPFVertex objects may have state from a previous computation m_lsdb->Initialize(); + SPFVertex* v; - // Make a priority queue of int using a vector container - // priority_queue, less > pq; - //priority_queue, less > candidate; - /* - * struct pqueue* candidate; - * struct vertex* v; - */ + // Make a priority queue of int using a vector container + // priority_queue, less > pq; + // + //priority_queue candidate; + // // Initialize the shortest-path tree to only the router doing the // calculation. // + v= m_lsdb->GetVertex(root); + // Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the + // spanning tree. + v->m_distanceFromRoot = 0; + v->m_stat = true; #if 0 - ospf_spf_init (area); - v = area->spf; - - - /* Create a new heap for the candidates. */ - candidate = pqueue_create(); - candidate->cmp = cmp; - candidate->update = update_stat; - - /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the - * * spanning tree. */ - *(v->stat) = LSA_SPF_IN_SPFTREE; - - /* Set Area A's TransitCapability to FALSE. */ - area->transit = OSPF_TRANSIT_FALSE; - area->shortcut_capability = 1; - for (;;) { /* RFC2328 16.1. (2). */ From 40e70fc6e9d3cc16408cb13bfe5fb89f02f003b5 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 13:58:13 -0700 Subject: [PATCH 039/278] Dummy test node for unit testing --- src/routing/static-route-manager.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 8deb95337..61c5af8c0 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -305,6 +305,28 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) namespace ns3 { +class StaticRouterTestNode : public Node +{ +public: + StaticRouterTestNode(); + +private: + virtual void DoAddDevice (Ptr device) const {}; + virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); +}; + +StaticRouterTestNode::StaticRouterTestNode () +{ +// Ptr ipv4 = Create (this); +} + +TraceResolver* +StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) +{ + return 0; +} + + class StaticRouteManagerTest : public Test { public: StaticRouteManagerTest (); @@ -454,6 +476,9 @@ StaticRouteManagerTest::RunTests (void) srmlsdb->Insert(lsa3->m_linkStateId, v3); NS_ASSERT(v2 == srmlsdb->GetVertex(lsa2->m_linkStateId)); + // We need a dummy node to populate the routing tables + Ptr n2 = Create (); + // XXX next, calculate routes based on the manually created LSDB StaticRouteManager* srm = new StaticRouteManager(); srm->DebugUseLsdb (srmlsdb); From a2acacebe03ebfe9aeba75ac0eb25644df71db5d Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 15:03:39 -0700 Subject: [PATCH 040/278] Iterate link records (16.1(2)) --- src/routing/static-route-manager.cc | 84 ++++++++++++++++++++++++----- src/routing/static-route-manager.h | 4 +- src/routing/static-router.cc | 2 + 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 61c5af8c0..aab5bd88f 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -78,6 +78,16 @@ StaticRouteManagerLSDB::Initialize() } } +void +StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) +{ + SPFVertex* temp = new SPFVertex (); + temp->m_lsa = lsa; + temp->m_vertexType = SPFVertex::VertexRouter; + temp->m_vertexId = lsa->m_linkStateId; + m_database.insert(LSDBPair_t(addr, temp)); +} + void StaticRouteManagerLSDB::Insert(Ipv4Address addr, SPFVertex* vertex) { @@ -143,11 +153,12 @@ StaticRouteManager::BuildStaticRoutingDatabase () for (uint32_t j = 0; j < numLSAs; ++j) { - StaticRouterLSA lsa; - rtr->GetLSA(j, lsa); + StaticRouterLSA* lsa = new StaticRouterLSA (); + rtr->GetLSA(j, *lsa); NS_DEBUG_UNCOND ("LSA " << j); NS_DEBUG_UNCOND ("----------------------------"); - NS_DEBUG_UNCOND(lsa); + NS_DEBUG_UNCOND (*lsa); + m_lsdb->Insert (lsa->m_linkStateId, lsa); } } } @@ -192,7 +203,6 @@ StaticRouteManager::InitializeRoutes () for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) { Ptr node = *i; - NS_DEBUG_UNCOND ("node="<< node->GetId () ); Ptr rtr = node->QueryInterface (StaticRouter::iid); @@ -206,12 +216,49 @@ StaticRouteManager::InitializeRoutes () // quagga ospf_spf_next +// RFC2328 Section 16.1 (2). +// v is on the SPF tree. Examine the links in v's LSA. Update the list +// of candidates with any vertices not already on the list. If a lower-cost +// path is found to a vertex already on the candidate list, store the new cost. +// +// +// void -StaticRouteManager::SPFNext() +StaticRouteManager::SPFNext(SPFVertex* v /*,candidate */) { - // if LSA == Router_LSA, examine links - // a) if link to stub, skip - // b) W is transit + if (v->m_vertexType == SPFVertex::VertexRouter) + { + // Always true for now, since all our LSAs are RouterLSAs + if (true) + { + NS_DEBUG_UNCOND("Examining " << v->m_vertexId << "'s link records"); + for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = + v->m_lsa->m_linkRecords.begin(); + i != v->m_lsa->m_linkRecords.end(); + i++ ) + { + // (a) If this is a link to a stub network, examine the next + // link in V's LSA. Links to stub networks will be + // considered in the second stage of the shortest path + // calculation. + StaticRouterLinkRecord* temp = *i; + if (temp->m_linkType == StaticRouterLinkRecord::StubNetwork) + { + NS_DEBUG_UNCOND("Found a Stub record to " << temp->m_linkId); + continue; + } + if (temp->m_linkType == StaticRouterLinkRecord::PointToPoint) + { + // Lookup the LSA (vertex) for the neighbor + SPFVertex* w = m_lsdb->GetVertex(temp->m_linkId); + NS_DEBUG_UNCOND("Found a P2P record from " << + v->m_vertexId << " to " << w->m_vertexId); + continue; + } + } + } + } + NS_DEBUG_UNCOND(""); } // quagga ospf_spf_calculate @@ -225,7 +272,7 @@ StaticRouteManager::DebugSPFCalculate(Ipv4Address root) void StaticRouteManager::SPFCalculate(Ipv4Address root) { - NS_DEBUG("StaticRouteManager::SPFCalculate ()"); + NS_DEBUG_UNCOND("StaticRouteManager::SPFCalculate ()"); // The SPFVertex objects may have state from a previous computation m_lsdb->Initialize(); @@ -242,11 +289,18 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) v= m_lsdb->GetVertex(root); // Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the // spanning tree. + NS_ASSERT(v); v->m_distanceFromRoot = 0; v->m_stat = true; + + // Add all other vertices to the candidate list -#if 0 for (;;) + { + SPFNext(v /*,candidate */); + break; + } +#if 0 { /* RFC2328 16.1. (2). */ ospf_spf_next (v, area, candidate); @@ -458,15 +512,19 @@ StaticRouteManagerTest::RunTests (void) SPFVertex* v0 = new SPFVertex (); v0->m_lsa = lsa0; v0->m_vertexType = SPFVertex::VertexRouter; + v0->m_vertexId = lsa0->m_linkStateId; SPFVertex* v1 = new SPFVertex (); v1->m_lsa = lsa1; - v0->m_vertexType = SPFVertex::VertexRouter; + v1->m_vertexType = SPFVertex::VertexRouter; + v1->m_vertexId = lsa1->m_linkStateId; SPFVertex* v2 = new SPFVertex (); v2->m_lsa = lsa2; - v0->m_vertexType = SPFVertex::VertexRouter; + v2->m_vertexType = SPFVertex::VertexRouter; + v2->m_vertexId = lsa2->m_linkStateId; SPFVertex* v3 = new SPFVertex (); v3->m_lsa = lsa3; - v0->m_vertexType = SPFVertex::VertexRouter; + v3->m_vertexType = SPFVertex::VertexRouter; + v3->m_vertexId = lsa3->m_linkStateId; // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 84b1a2e29..0ab536350 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -68,6 +68,7 @@ class StaticRouteManagerLSDB public: ~StaticRouteManagerLSDB (); void Insert(Ipv4Address addr, SPFVertex* vertex); + void Insert(Ipv4Address addr, StaticRouterLSA* lsa); SPFVertex* GetVertex (Ipv4Address addr); /** * \brief Set all SPFVertex to an initialized state, for SPF computation @@ -116,12 +117,13 @@ public: void DebugSPFCalculate (Ipv4Address root); virtual ~StaticRouteManager (); + protected: private: StaticRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); - void SPFNext (); + void SPFNext (SPFVertex*/*,candidate */); }; } // namespace ns3 diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index f8ff27657..4bacbda64 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -49,6 +49,7 @@ StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; pDst->m_linkId = pSrc->m_linkId; pDst->m_linkData = pSrc->m_linkData; + pDst->m_linkType = pSrc->m_linkType; m_linkRecords.push_back(pDst); pDst = 0; } @@ -71,6 +72,7 @@ StaticRouterLSA::operator= (StaticRouterLSA& lsa) StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; pDst->m_linkId = pSrc->m_linkId; pDst->m_linkData = pSrc->m_linkData; + pDst->m_linkType = pSrc->m_linkType; m_linkRecords.push_back(pDst); pDst = 0; } From 711276e62b09ea173b7fa87a41508802b4dc4508 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 17:35:44 -0700 Subject: [PATCH 041/278] SPFVertex Priority Queue --- src/routing/static-route-manager.cc | 23 ++++++++++++++++++++++- src/routing/static-route-manager.h | 13 +++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index aab5bd88f..4a4739c4d 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -49,7 +49,6 @@ SPFVertex::Initialize () // XXX previous = 0 } - StaticRouteManagerLSDB::~StaticRouteManagerLSDB() { NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); @@ -401,6 +400,28 @@ StaticRouteManagerTest::RunTests (void) { bool ok = true; + SPFVertexPriorityQueue candidate; // <---------------- + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = new SPFVertex; + v->m_distanceFromRoot = rand () % 100; + candidate.push (v); // <---------------- + } + + uint32_t lastDistance = 0; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = candidate.top (); // <---------------- + candidate.pop (); // <---------------- + if (v->m_distanceFromRoot < lastDistance) + { + ok = false; + } + lastDistance = v->m_distanceFromRoot; + } + // Build fake link state database; four routers (0-3), 3 point-to-point // links // diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 0ab536350..81669804f 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -18,6 +18,7 @@ #include #include +#include #include #include "ns3/object.h" #include "ns3/ptr.h" @@ -58,8 +59,20 @@ public: uint32_t m_distanceFromRoot; bool m_stat; // true if LSA is in SPF tree already + + struct Greater : public std::binary_function< SPFVertex*, SPFVertex*, bool> + { + bool operator()(const SPFVertex *v1, const SPFVertex *v2) const + { + return v1->m_distanceFromRoot > v2->m_distanceFromRoot; + } + }; }; +typedef std::vector SPFVector_t; +typedef std::priority_queue + SPFVertexPriorityQueue; + /** * \brief The Link State DataBase (LSDB) of a static router */ From 4e86f62a6445c99cc70f34e22aa1cce765cc4d2b Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 17:56:46 -0700 Subject: [PATCH 042/278] end of day checkin --- src/routing/static-route-manager.cc | 52 +++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 4a4739c4d..2449b6979 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -246,12 +246,50 @@ StaticRouteManager::SPFNext(SPFVertex* v /*,candidate */) NS_DEBUG_UNCOND("Found a Stub record to " << temp->m_linkId); continue; } + // (b) Otherwise, W is a transit vertex (router or transit + // network). Look up the vertex W's LSA (router-LSA or + // network-LSA) in Area A's link state database. if (temp->m_linkType == StaticRouterLinkRecord::PointToPoint) { // Lookup the LSA (vertex) for the neighbor SPFVertex* w = m_lsdb->GetVertex(temp->m_linkId); + NS_ASSERT(w); NS_DEBUG_UNCOND("Found a P2P record from " << v->m_vertexId << " to " << w->m_vertexId); + // (c) If vertex W is already on the shortest-path tree, + // examine the next link in the LSA. + if (w->m_stat == true) + { + continue; + } + // (d) Calculate the link state cost D of the resulting path + // from the root to vertex W. D is equal to the sum of + // the link state cost of the (already calculated) + // shortest path to vertex V and the advertised cost of + // the link between vertices V and W. + +// uint32_t distance = v->m_distanceFromRoot + temp->m_metric; + + // Here, W is either already in candidate list or not + + // if (not in candidate list) + // ospf_nexthop_calculation() + // priority_queue.enqueu() + // else + // get vertex from candidates list + // if (w->distance < distance) + // continue; // not a shorter path + // else if (w->distance > distance) + // Found a lower-cost path to W. + // * nexthop_calculation is conditional, if it finds + // * valid nexthop it will call spf_add_parents, which + // * will flush the old parents + // */ + // if (ospf_nexthop_calculation (area, v, w, l, distance)) + // /* Decrease the key of the node in the heap, + // * re-sort the heap. */ + // trickle_down (w_lsa->stat, candidate); + // continue; } } @@ -293,17 +331,14 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) v->m_stat = true; // Add all other vertices to the candidate list + // XXX todo for (;;) { - SPFNext(v /*,candidate */); - break; - } + // RFC2328 16.1. (2). + SPFNext(v /*,candidate */); + #if 0 - { - /* RFC2328 16.1. (2). */ - ospf_spf_next (v, area, candidate); - /* RFC2328 16.1. (3). */ /* If at this step the candidate list is empty, the shortest- * path tree (of transit vertices) has been completely built and @@ -345,6 +380,9 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) pqueue_delete (candidate); #endif + break; + } + } From e47dd4f054e8fc0e6c33f651cfc7f24c56311efc Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 17:59:11 -0700 Subject: [PATCH 043/278] One RouterLSA per node --- src/routing/static-router.cc | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 4bacbda64..48a697a5e 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -203,6 +203,15 @@ StaticRouter::DiscoverLSAs (void) Ptr ipv4Local = m_node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4Local, "QI for interface failed"); // +// We are, for now at least, only going to report RouterLSAs in this method. +// What this means is that there is going to be one advertisement with some +// number of link records. This means that GetNumLSAs will actually always +// return exactly one. +// + StaticRouterLSA *pLSA = new StaticRouterLSA; + pLSA->m_linkStateId = m_routerId; + pLSA->m_advertisingRtr = m_routerId; +// // We need to ask the node for the number of net devices attached. This isn't // necessarily equal to the number of links to adjacent nodes (other routers) // as the number of devices may include those for stub networks (e.g., @@ -277,15 +286,10 @@ StaticRouter::DiscoverLSAs (void) Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); NS_DEBUG("Working with remote address " << addrRemote); // -// Now we can fill out the link state advertisement for this link. There -// are always two link records; the first is a point-to-point record -// describing the link and the second is a stub network record with the -// network number. +// Now we can fill out the link records for this link. There are always two +// link records; the first is a point-to-point record describing the link and +// the second is a stub network record with the network number. // - StaticRouterLSA *pLSA = new StaticRouterLSA; - pLSA->m_linkStateId = m_routerId; - pLSA->m_advertisingRtr = m_routerId; - StaticRouterLinkRecord *plr = new StaticRouterLinkRecord; plr->m_linkType = StaticRouterLinkRecord::PointToPoint; plr->m_linkId = rtrIdRemote; @@ -299,11 +303,12 @@ StaticRouter::DiscoverLSAs (void) plr->m_linkData.Set(maskRemote.GetHostOrder()); // Frown pLSA->AddLinkRecord(plr); plr = 0; - - m_LSAs.push_back (pLSA); - NS_DEBUG(*pLSA); } - +// +// The LSA goes on a list of LSAs in case we want to begin exporting other +// kinds of advertisements (than Router LSAs). + m_LSAs.push_back (pLSA); + NS_DEBUG(*pLSA); return m_LSAs.size (); } From d57291777f7c9d6f67f03f0ee54b0582181bd88e Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 10 Jul 2007 22:17:25 -0700 Subject: [PATCH 044/278] minor tweaks --- src/routing/static-router.cc | 30 ++++++++++-------------------- src/routing/static-router.h | 9 +++++++++ 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 48a697a5e..b1a470feb 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -38,32 +38,24 @@ StaticRouterLSA::StaticRouterLSA() StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr) { - NS_DEBUG("StaticRouterLSA Copy Constructor"); - NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty before copy"); - - for ( ListOfLinkRecords_t::iterator i = lsa.m_linkRecords.begin (); - i != lsa.m_linkRecords.end (); - i++) - { - StaticRouterLinkRecord *pSrc = *i; - StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; - pDst->m_linkId = pSrc->m_linkId; - pDst->m_linkData = pSrc->m_linkData; - pDst->m_linkType = pSrc->m_linkType; - m_linkRecords.push_back(pDst); - pDst = 0; - } + NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty in its constructor!"); + CopyLinkRecords (lsa); } StaticRouterLSA& StaticRouterLSA::operator= (StaticRouterLSA& lsa) { - NS_DEBUG("StaticRouterLSA Operator ="); - NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty before assignment"); - m_linkStateId = lsa.m_linkStateId; m_advertisingRtr = lsa.m_advertisingRtr; + ClearLinkRecords (); + CopyLinkRecords (lsa); + return *this; +} + + void +StaticRouterLSA::CopyLinkRecords (StaticRouterLSA& lsa) +{ for ( ListOfLinkRecords_t::iterator i = lsa.m_linkRecords.begin (); i != lsa.m_linkRecords.end (); i++) @@ -76,8 +68,6 @@ StaticRouterLSA::operator= (StaticRouterLSA& lsa) m_linkRecords.push_back(pDst); pDst = 0; } - - return *this; } StaticRouterLSA::~StaticRouterLSA() diff --git a/src/routing/static-router.h b/src/routing/static-router.h index f3273c311..d65e4e165 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -115,6 +115,15 @@ public: * @returns Reference to the overwritten LSA. */ StaticRouterLSA& operator= (StaticRouterLSA& lsa); + /** + * Copy any Static Router Link Records in a given Static Router Link + * State Advertisement to the current LSA. Existing Link Records are not + * deleted -- this is a concatenation of Link Records. + * + * @see ClearLinkRecords () + * @param lsa The LSA to copy the Link Records from. + */ + void CopyLinkRecords (StaticRouterLSA& lsa); /** * Add a given Static Router Link Record to a given Static Router Link * State Advertisement. From 8168ddcb400a1cbd0ecdd31fa98865aa3d55e0a0 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 10 Jul 2007 23:10:18 -0700 Subject: [PATCH 045/278] Add candidate list (priority queue) --- src/routing/static-route-manager.cc | 26 ++++++++++++-------------- src/routing/static-route-manager.h | 9 +++++++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 2449b6979..a0161656c 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -32,7 +32,7 @@ SPFVertex::SPFVertex () : m_vertexId("255.255.255.255"), m_lsa(0), m_distanceFromRoot(SPF_INFINITY), - m_stat(false) + m_stat(LSA_SPF_NOT_EXPLORED) { } @@ -45,7 +45,7 @@ void SPFVertex::Initialize () { m_distanceFromRoot = SPF_INFINITY; - m_stat = false; + m_stat = LSA_SPF_NOT_EXPLORED; // XXX previous = 0 } @@ -223,7 +223,7 @@ StaticRouteManager::InitializeRoutes () // // void -StaticRouteManager::SPFNext(SPFVertex* v /*,candidate */) +StaticRouteManager::SPFNext(SPFVertex* v, SPFVertexPriorityQueue& candidate) { if (v->m_vertexType == SPFVertex::VertexRouter) { @@ -258,7 +258,7 @@ StaticRouteManager::SPFNext(SPFVertex* v /*,candidate */) v->m_vertexId << " to " << w->m_vertexId); // (c) If vertex W is already on the shortest-path tree, // examine the next link in the LSA. - if (w->m_stat == true) + if (w->m_stat == LSA_SPF_IN_SPFTREE) { continue; } @@ -268,7 +268,7 @@ StaticRouteManager::SPFNext(SPFVertex* v /*,candidate */) // shortest path to vertex V and the advertised cost of // the link between vertices V and W. -// uint32_t distance = v->m_distanceFromRoot + temp->m_metric; + //uint32_t distance = v->m_distanceFromRoot + temp->m_metric; // Here, W is either already in candidate list or not @@ -315,10 +315,12 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) m_lsdb->Initialize(); SPFVertex* v; - // Make a priority queue of int using a vector container - // priority_queue, less > pq; + // The candidate queue is a priority queue of SPFVertex objects, with + // the top of the queue being the closest vertex in terms of + // distanceFromRoot. Initially, this queue is empty. // - //priority_queue candidate; + SPFVertexPriorityQueue candidate; + NS_ASSERT(candidate.size() == 0); // // Initialize the shortest-path tree to only the router doing the // calculation. @@ -328,16 +330,12 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // spanning tree. NS_ASSERT(v); v->m_distanceFromRoot = 0; - v->m_stat = true; + v->m_stat = LSA_SPF_IN_SPFTREE; - // Add all other vertices to the candidate list - // XXX todo - for (;;) { // RFC2328 16.1. (2). - SPFNext(v /*,candidate */); - + SPFNext(v , candidate); #if 0 /* RFC2328 16.1. (3). */ /* If at this step the candidate list is empty, the shortest- diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 81669804f..6e63aa5f0 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -29,6 +29,8 @@ namespace ns3 { const uint32_t SPF_INFINITY = 0xffffffff; +const int LSA_SPF_NOT_EXPLORED = -1; +const int LSA_SPF_IN_SPFTREE = -2; /** * \brief Vertex used in shortest path first (SPF) computations * @@ -51,6 +53,8 @@ public: StaticRouterLSA* m_lsa; // This pointer owns LSA for mem. mgmt purposes + // XXX not sure exactly what data structure is needed here + // need to keep track of previous vertex typedef std::list type_listOfSPFVertex; type_listOfSPFVertex m_parents; type_listOfSPFVertex m_children; @@ -58,7 +62,8 @@ public: uint32_t m_distanceFromRoot; - bool m_stat; // true if LSA is in SPF tree already + // If stat >= 0, stat is LSA position in candidates heap + int m_stat; struct Greater : public std::binary_function< SPFVertex*, SPFVertex*, bool> { @@ -136,7 +141,7 @@ protected: private: StaticRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); - void SPFNext (SPFVertex*/*,candidate */); + void SPFNext (SPFVertex*, SPFVertexPriorityQueue&); }; } // namespace ns3 From 9dc9be484f7484ffe1627c120550f57da0db2f90 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Wed, 11 Jul 2007 13:18:01 -0700 Subject: [PATCH 046/278] candidate queue --- SConstruct | 10 ++- samples/main-candidate-queue.cc | 91 +++++++++++++++++++ src/routing/candidate-queue.cc | 151 ++++++++++++++++++++++++++++++++ src/routing/candidate-queue.h | 50 +++++++++++ src/routing/static-router.cc | 2 +- src/routing/static-router.h | 24 ++--- 6 files changed, 314 insertions(+), 14 deletions(-) create mode 100644 samples/main-candidate-queue.cc create mode 100644 src/routing/candidate-queue.cc create mode 100644 src/routing/candidate-queue.h diff --git a/SConstruct b/SConstruct index 00a799f90..111358020 100644 --- a/SConstruct +++ b/SConstruct @@ -374,6 +374,7 @@ routing.add_sources([ 'routing-environment.cc', 'static-router.cc', 'static-route-manager.cc', + 'candidate-queue.cc', ]) routing.add_headers ([ ]) @@ -381,6 +382,7 @@ routing.add_inst_headers([ 'routing-environment.h', 'static-router.h', 'static-route-manager.h', + 'candidate-queue.h', ]) # utils @@ -429,7 +431,6 @@ ns3.add(sample_packet_printer) sample_packet_printer.add_deps (['common', 'internet-node']) sample_packet_printer.add_source('main-packet-printer.cc') - sample_callback = build.Ns3Module('sample-callback', 'samples') sample_callback.set_executable() ns3.add(sample_callback) @@ -502,6 +503,13 @@ ns3.add(sample_component_manager) sample_component_manager.add_deps(['core']) sample_component_manager.add_source('main-component-manager.cc') +sample_candidate_queue = build.Ns3Module('sample-candidate-queue', 'samples') +sample_candidate_queue.set_executable() +ns3.add(sample_candidate_queue) +sample_candidate_queue.add_deps(['core']) +sample_candidate_queue.add_deps(['routing']) +sample_candidate_queue.add_source('main-candidate-queue.cc') + # examples example_simple_p2p = build.Ns3Module('simple-p2p', 'examples') example_simple_p2p.set_executable() diff --git a/samples/main-candidate-queue.cc b/samples/main-candidate-queue.cc new file mode 100644 index 000000000..7708b8c0f --- /dev/null +++ b/samples/main-candidate-queue.cc @@ -0,0 +1,91 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/debug.h" +#include "ns3/assert.h" +#include "ns3/candidate-queue.h" + +using namespace ns3; + + int +main (int argc, char *argv[]) +{ + NS_DEBUG_UNCOND("Candidate Queue Test"); + +#if 0 + DebugComponentEnable("CandidateQueue"); +#endif + + CandidateQueue candidate; + NS_ASSERT(candidate.Size () == 0); + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = new SPFVertex; + v->m_distanceFromRoot = rand () % 100; + candidate.Push (v); + } + + uint32_t lastDistance = 0; + bool ok = true; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = candidate.Top (); + candidate.Pop (); + if (v->m_distanceFromRoot < lastDistance) + { + ok = false; + NS_ASSERT(0); + } + lastDistance = v->m_distanceFromRoot; + } + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = new SPFVertex; + v->m_distanceFromRoot = rand () % 100; + candidate.Push (v); + } + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = candidate.Fetch (i); + if (v) { + v->m_distanceFromRoot = rand () % 100; + } + } + + candidate.Reorder (); + + lastDistance = 0; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = candidate.Top (); + candidate.Pop (); + if (v->m_distanceFromRoot < lastDistance) + { + ok = false; + NS_ASSERT(0); + } + lastDistance = v->m_distanceFromRoot; + } + + NS_ASSERT(candidate.Size () == 0); + + return 0; +} diff --git a/src/routing/candidate-queue.cc b/src/routing/candidate-queue.cc new file mode 100644 index 000000000..a4b29802c --- /dev/null +++ b/src/routing/candidate-queue.cc @@ -0,0 +1,151 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ns3/debug.h" +#include "ns3/assert.h" +#include "candidate-queue.h" + +NS_DEBUG_COMPONENT_DEFINE ("CandidateQueue"); + +namespace ns3 { + +CandidateQueue::CandidateQueue() + : m_candidates () +{ + NS_DEBUG("CandidateQueue::CandidateQueue ()"); +} + +CandidateQueue::~CandidateQueue() +{ + NS_DEBUG("CandidateQueue::~CandidateQueue ()"); + Clear (); +} + + void +CandidateQueue::Clear (void) +{ + NS_DEBUG("CandidateQueue::Clear ()"); + + while (!m_candidates.empty ()) + { + Pop (); + } +} + + + void +CandidateQueue::Push (SPFVertex *vNew) +{ + NS_DEBUG("CandidateQueue::Push (" << vNew << ")"); + + CandidateList_t::iterator i = m_candidates.begin (); + + for (; i != m_candidates.end (); i++) + { + SPFVertex *v = *i; + if (vNew->m_distanceFromRoot < v->m_distanceFromRoot) + { + break; + } + } + m_candidates.insert(i, vNew); +} + + void +CandidateQueue::Pop (void) +{ + NS_DEBUG("CandidateQueue::Pop ()"); + + if (m_candidates.empty ()) + { + return; + } + + SPFVertex *v = m_candidates.front (); + m_candidates.pop_front (); + delete v; + v = 0; +} + + SPFVertex * +CandidateQueue::Top (void) +{ + NS_DEBUG("CandidateQueue::Top ()"); + + if (m_candidates.empty ()) + { + return 0; + } + + return m_candidates.front (); +} + + bool +CandidateQueue::Empty (void) +{ + NS_DEBUG("CandidateQueue::Empty ()"); + + return m_candidates.empty (); +} + + uint32_t +CandidateQueue::Size (void) +{ + NS_DEBUG("CandidateQueue::Size ()"); + + return m_candidates.size (); +} + + + SPFVertex * +CandidateQueue::Fetch (uint32_t m_distanceFromRoot) +{ + NS_DEBUG("CandidateQueue::Fetch ()"); + + CandidateList_t::iterator i = m_candidates.begin (); + + for (; i != m_candidates.end (); i++) + { + SPFVertex *v = *i; + if (v->m_distanceFromRoot == m_distanceFromRoot) + { + return v; + } + } + + return 0; +} + + void +CandidateQueue::Reorder (void) +{ + NS_DEBUG("CandidateQueue::Reorder ()"); + + std::list temp; + + while (!m_candidates.empty ()) { + SPFVertex *v = m_candidates.front (); + m_candidates.pop_front (); + temp.push_back(v); + } + + while (!temp.empty ()) { + Push (temp.front ()); + temp.pop_front (); + } +} + +} // namespace ns3 diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h new file mode 100644 index 000000000..e04bd4651 --- /dev/null +++ b/src/routing/candidate-queue.h @@ -0,0 +1,50 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CANDIDATE_QUEUE_H +#define CANDIDATE_QUEUE_H + +#include +#include +#include "static-route-manager.h" + +namespace ns3 { + +class CandidateQueue +{ +public: + CandidateQueue (); + virtual ~CandidateQueue (); + + void Clear (void); + void Push (SPFVertex *v); + void Pop (void); + SPFVertex* Top (void); + bool Empty (void); + uint32_t Size (void); + SPFVertex* Fetch (uint32_t key); + void Reorder (void); + +protected: + typedef std::list CandidateList_t; + CandidateList_t m_candidates; + +private: +}; + +} // namespace ns3 + +#endif /* CANDIDATE_QUEUE_H */ diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index b1a470feb..528a1500f 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -170,7 +170,7 @@ StaticRouter::ClearLSAs () } Ipv4Address - StaticRouter::GetRouterId (void) +StaticRouter::GetRouterId (void) { return m_routerId; } diff --git a/src/routing/static-router.h b/src/routing/static-router.h index d65e4e165..bda6cc04a 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -13,6 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef STATIC_ROUTER_H #define STATIC_ROUTER_H @@ -39,19 +40,18 @@ namespace ns3 { class StaticRouterLinkRecord { public: - // - // For Type 1 link (PointToPoint), set m_linkId to Router ID of - // neighboring router. - // - // For Type 3 link (Stub), set m_linkId to neighbor's IP address - // +// +// For Type 1 link (PointToPoint), set m_linkId to Router ID of +// neighboring router. +// +// For Type 3 link (Stub), set m_linkId to neighbor's IP address +// Ipv4Address m_linkId; - - // - // For Type 1 link (PointToPoint), set m_linkData to local IP address - // - // For Type 3 link (Stub), set m_linkData to mask 0xffffffff - // +// +// For Type 1 link (PointToPoint), set m_linkData to local IP address +// +// For Type 3 link (Stub), set m_linkData to mask 0xffffffff +// Ipv4Address m_linkData; // for links to RouterLSA, /** * Enumeration of the possible types of Static Router Link Records. These From 248122670f13282034382d6323b8c9698c866853 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 11 Jul 2007 16:45:19 -0700 Subject: [PATCH 047/278] Adjust candidate queue implementation: rename Fetch to Find, and make Find based on m_vertexId --- samples/main-candidate-queue.cc | 4 +++- src/routing/candidate-queue.cc | 6 +++--- src/routing/candidate-queue.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/samples/main-candidate-queue.cc b/samples/main-candidate-queue.cc index 7708b8c0f..ca111f0dc 100644 --- a/samples/main-candidate-queue.cc +++ b/samples/main-candidate-queue.cc @@ -61,13 +61,15 @@ main (int argc, char *argv[]) candidate.Push (v); } +#if 0 for (int i = 0; i < 100; ++i) { - SPFVertex *v = candidate.Fetch (i); + SPFVertex *v = candidate.Find (i); if (v) { v->m_distanceFromRoot = rand () % 100; } } +#endif candidate.Reorder (); diff --git a/src/routing/candidate-queue.cc b/src/routing/candidate-queue.cc index a4b29802c..7b5f9ba96 100644 --- a/src/routing/candidate-queue.cc +++ b/src/routing/candidate-queue.cc @@ -111,16 +111,16 @@ CandidateQueue::Size (void) SPFVertex * -CandidateQueue::Fetch (uint32_t m_distanceFromRoot) +CandidateQueue::Find (const Ipv4Address addr) { - NS_DEBUG("CandidateQueue::Fetch ()"); + NS_DEBUG("CandidateQueue::Find ()"); CandidateList_t::iterator i = m_candidates.begin (); for (; i != m_candidates.end (); i++) { SPFVertex *v = *i; - if (v->m_distanceFromRoot == m_distanceFromRoot) + if (v->m_vertexId == addr) { return v; } diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index e04bd4651..5d266e7c5 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -35,7 +35,7 @@ public: SPFVertex* Top (void); bool Empty (void); uint32_t Size (void); - SPFVertex* Fetch (uint32_t key); + SPFVertex* Find (const Ipv4Address addr); void Reorder (void); protected: From 9424ed96695195c11db1a55daaa3cd8c199be0cf Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 11 Jul 2007 17:13:11 -0700 Subject: [PATCH 048/278] Make LSDB back into a storage for LSAs --- src/routing/static-route-manager.cc | 71 ++++++++++------------------- src/routing/static-route-manager.h | 9 ++-- 2 files changed, 28 insertions(+), 52 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index a0161656c..7bc6b2f5e 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -56,14 +56,15 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB() LSDBMap_t::iterator i; for (i= m_database.begin(); i!= m_database.end(); i++) { - NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB():free vertex"); - SPFVertex* temp = i->second; + NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB():free LSA"); + StaticRouterLSA* temp = i->second; delete temp; } NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); m_database.clear(); } +#if 0 void StaticRouteManagerLSDB::Initialize() { @@ -72,29 +73,20 @@ StaticRouteManagerLSDB::Initialize() LSDBMap_t::iterator i; for (i= m_database.begin(); i!= m_database.end(); i++) { - SPFVertex* temp = i->second; + StaticRouterLSA* temp = i->second; temp->Initialize(); } } +#endif void StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) { - SPFVertex* temp = new SPFVertex (); - temp->m_lsa = lsa; - temp->m_vertexType = SPFVertex::VertexRouter; - temp->m_vertexId = lsa->m_linkStateId; - m_database.insert(LSDBPair_t(addr, temp)); + m_database.insert(LSDBPair_t(addr, lsa)); } -void -StaticRouteManagerLSDB::Insert(Ipv4Address addr, SPFVertex* vertex) -{ - m_database.insert(LSDBPair_t(addr, vertex)); -} - -SPFVertex* -StaticRouteManagerLSDB::GetVertex (Ipv4Address addr) +StaticRouterLSA* +StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) { // Look up an LSA by its address LSDBMap_t::iterator i; @@ -252,16 +244,18 @@ StaticRouteManager::SPFNext(SPFVertex* v, SPFVertexPriorityQueue& candidate) if (temp->m_linkType == StaticRouterLinkRecord::PointToPoint) { // Lookup the LSA (vertex) for the neighbor - SPFVertex* w = m_lsdb->GetVertex(temp->m_linkId); - NS_ASSERT(w); + StaticRouterLSA* w_lsa = m_lsdb->GetLSA(temp->m_linkId); + NS_ASSERT(w_lsa); NS_DEBUG_UNCOND("Found a P2P record from " << - v->m_vertexId << " to " << w->m_vertexId); + v->m_vertexId << " to " << w_lsa->m_linkStateId); +#if 0 // (c) If vertex W is already on the shortest-path tree, // examine the next link in the LSA. if (w->m_stat == LSA_SPF_IN_SPFTREE) { continue; } +#endif // (d) Calculate the link state cost D of the resulting path // from the root to vertex W. D is equal to the sum of // the link state cost of the (already calculated) @@ -311,8 +305,6 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) { NS_DEBUG_UNCOND("StaticRouteManager::SPFCalculate ()"); - // The SPFVertex objects may have state from a previous computation - m_lsdb->Initialize(); SPFVertex* v; // The candidate queue is a priority queue of SPFVertex objects, with @@ -325,10 +317,12 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // Initialize the shortest-path tree to only the router doing the // calculation. // - v= m_lsdb->GetVertex(root); + v= new SPFVertex(); + v->m_vertexType = SPFVertex::VertexRouter; + v->m_vertexId = root; + v-> m_lsa = m_lsdb->GetLSA(root); // Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the // spanning tree. - NS_ASSERT(v); v->m_distanceFromRoot = 0; v->m_stat = LSA_SPF_IN_SPFTREE; @@ -565,31 +559,13 @@ StaticRouteManagerTest::RunTests (void) lsa3->AddLinkRecord(lr2); lsa3->AddLinkRecord(lr3); - // Create four vertices to store these four LSAs - SPFVertex* v0 = new SPFVertex (); - v0->m_lsa = lsa0; - v0->m_vertexType = SPFVertex::VertexRouter; - v0->m_vertexId = lsa0->m_linkStateId; - SPFVertex* v1 = new SPFVertex (); - v1->m_lsa = lsa1; - v1->m_vertexType = SPFVertex::VertexRouter; - v1->m_vertexId = lsa1->m_linkStateId; - SPFVertex* v2 = new SPFVertex (); - v2->m_lsa = lsa2; - v2->m_vertexType = SPFVertex::VertexRouter; - v2->m_vertexId = lsa2->m_linkStateId; - SPFVertex* v3 = new SPFVertex (); - v3->m_lsa = lsa3; - v3->m_vertexType = SPFVertex::VertexRouter; - v3->m_vertexId = lsa3->m_linkStateId; - // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); - srmlsdb->Insert(lsa0->m_linkStateId, v0); - srmlsdb->Insert(lsa1->m_linkStateId, v1); - srmlsdb->Insert(lsa2->m_linkStateId, v2); - srmlsdb->Insert(lsa3->m_linkStateId, v3); - NS_ASSERT(v2 == srmlsdb->GetVertex(lsa2->m_linkStateId)); + srmlsdb->Insert(lsa0->m_linkStateId, lsa0); + srmlsdb->Insert(lsa1->m_linkStateId, lsa1); + srmlsdb->Insert(lsa2->m_linkStateId, lsa2); + srmlsdb->Insert(lsa3->m_linkStateId, lsa3); + NS_ASSERT(lsa2 == srmlsdb->GetLSA(lsa2->m_linkStateId)); // We need a dummy node to populate the routing tables Ptr n2 = Create (); @@ -600,8 +576,7 @@ StaticRouteManagerTest::RunTests (void) srm->DebugSPFCalculate(lsa0->m_linkStateId); // node n0 // This delete clears the srm, which deletes the LSDB, which clears - // all of the vertices, which each destroy the matching LSAs, which each - // destroys the attached LinkRecords. + // all of the LSAs, which each destroys the attached LinkRecords. delete srm; return ok; diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 6e63aa5f0..42fa7ee16 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -85,16 +85,17 @@ class StaticRouteManagerLSDB { public: ~StaticRouteManagerLSDB (); - void Insert(Ipv4Address addr, SPFVertex* vertex); void Insert(Ipv4Address addr, StaticRouterLSA* lsa); - SPFVertex* GetVertex (Ipv4Address addr); + StaticRouterLSA* GetLSA (Ipv4Address addr); /** * \brief Set all SPFVertex to an initialized state, for SPF computation */ +#if 0 void Initialize (); +#endif - typedef std::map LSDBMap_t; - typedef std::pair LSDBPair_t; + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; LSDBMap_t m_database; }; From 9ff955496e4bea66691961e123256cf70c8dad87 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 11 Jul 2007 17:31:43 -0700 Subject: [PATCH 049/278] Replace SPFVertexPriorityQueue with CandidateQueue --- src/routing/static-route-manager.cc | 15 ++++++++------- src/routing/static-route-manager.h | 17 ++++------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 7bc6b2f5e..b68432ca0 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -22,6 +22,7 @@ #include "ns3/node-list.h" #include "static-router.h" #include "static-route-manager.h" +#include "candidate-queue.h" NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); @@ -215,7 +216,7 @@ StaticRouteManager::InitializeRoutes () // // void -StaticRouteManager::SPFNext(SPFVertex* v, SPFVertexPriorityQueue& candidate) +StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) { if (v->m_vertexType == SPFVertex::VertexRouter) { @@ -311,8 +312,8 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // the top of the queue being the closest vertex in terms of // distanceFromRoot. Initially, this queue is empty. // - SPFVertexPriorityQueue candidate; - NS_ASSERT(candidate.size() == 0); + CandidateQueue candidate; + NS_ASSERT(candidate.Size() == 0); // // Initialize the shortest-path tree to only the router doing the // calculation. @@ -430,21 +431,21 @@ StaticRouteManagerTest::RunTests (void) { bool ok = true; - SPFVertexPriorityQueue candidate; // <---------------- + CandidateQueue candidate; // <---------------- for (int i = 0; i < 100; ++i) { SPFVertex *v = new SPFVertex; v->m_distanceFromRoot = rand () % 100; - candidate.push (v); // <---------------- + candidate.Push (v); // <---------------- } uint32_t lastDistance = 0; for (int i = 0; i < 100; ++i) { - SPFVertex *v = candidate.top (); // <---------------- - candidate.pop (); // <---------------- + SPFVertex *v = candidate.Top (); // <---------------- + candidate.Pop (); // <---------------- if (v->m_distanceFromRoot < lastDistance) { ok = false; diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 42fa7ee16..e9e94997b 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -31,6 +31,9 @@ const uint32_t SPF_INFINITY = 0xffffffff; const int LSA_SPF_NOT_EXPLORED = -1; const int LSA_SPF_IN_SPFTREE = -2; + +class CandidateQueue; + /** * \brief Vertex used in shortest path first (SPF) computations * @@ -64,20 +67,8 @@ public: // If stat >= 0, stat is LSA position in candidates heap int m_stat; - - struct Greater : public std::binary_function< SPFVertex*, SPFVertex*, bool> - { - bool operator()(const SPFVertex *v1, const SPFVertex *v2) const - { - return v1->m_distanceFromRoot > v2->m_distanceFromRoot; - } - }; }; -typedef std::vector SPFVector_t; -typedef std::priority_queue - SPFVertexPriorityQueue; - /** * \brief The Link State DataBase (LSDB) of a static router */ @@ -142,7 +133,7 @@ protected: private: StaticRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); - void SPFNext (SPFVertex*, SPFVertexPriorityQueue&); + void SPFNext (SPFVertex*, CandidateQueue&); }; } // namespace ns3 From 33a0cc37598a58628b8352428f858727a4f9014b Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 11 Jul 2007 22:37:48 -0700 Subject: [PATCH 050/278] move m_stat flag to LSA --- src/routing/static-route-manager.cc | 19 ++++++++++--------- src/routing/static-route-manager.h | 5 ----- src/routing/static-router.cc | 8 ++++++-- src/routing/static-router.h | 8 ++++++++ 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index b68432ca0..1a681764e 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -32,8 +32,7 @@ SPFVertex::SPFVertex () : m_vertexType(VertexUnknown), m_vertexId("255.255.255.255"), m_lsa(0), - m_distanceFromRoot(SPF_INFINITY), - m_stat(LSA_SPF_NOT_EXPLORED) + m_distanceFromRoot(SPF_INFINITY) { } @@ -46,7 +45,6 @@ void SPFVertex::Initialize () { m_distanceFromRoot = SPF_INFINITY; - m_stat = LSA_SPF_NOT_EXPLORED; // XXX previous = 0 } @@ -244,19 +242,18 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // network-LSA) in Area A's link state database. if (temp->m_linkType == StaticRouterLinkRecord::PointToPoint) { - // Lookup the LSA (vertex) for the neighbor + // Lookup the vertex W's LSA StaticRouterLSA* w_lsa = m_lsdb->GetLSA(temp->m_linkId); NS_ASSERT(w_lsa); NS_DEBUG_UNCOND("Found a P2P record from " << v->m_vertexId << " to " << w_lsa->m_linkStateId); -#if 0 // (c) If vertex W is already on the shortest-path tree, // examine the next link in the LSA. - if (w->m_stat == LSA_SPF_IN_SPFTREE) + if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_IN_SPFTREE) { + NS_DEBUG("LSA "<< w_lsa->m_linkStateId << " in SPF"); continue; } -#endif // (d) Calculate the link state cost D of the resulting path // from the root to vertex W. D is equal to the sum of // the link state cost of the (already calculated) @@ -267,7 +264,12 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // Here, W is either already in candidate list or not - // if (not in candidate list) +#if 0 + if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + { + SPFVertex* w = new SPFVertex(w_lsa); +#endif + // ospf_nexthop_calculation() // priority_queue.enqueu() // else @@ -325,7 +327,6 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the // spanning tree. v->m_distanceFromRoot = 0; - v->m_stat = LSA_SPF_IN_SPFTREE; for (;;) { diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index e9e94997b..0b0cc4c5d 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -29,9 +29,6 @@ namespace ns3 { const uint32_t SPF_INFINITY = 0xffffffff; -const int LSA_SPF_NOT_EXPLORED = -1; -const int LSA_SPF_IN_SPFTREE = -2; - class CandidateQueue; /** @@ -65,8 +62,6 @@ public: uint32_t m_distanceFromRoot; - // If stat >= 0, stat is LSA position in candidates heap - int m_stat; }; /** diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 528a1500f..e0bceb40a 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -30,13 +30,15 @@ StaticRouterLSA::StaticRouterLSA() : m_linkStateId("0.0.0.0"), m_advertisingRtr("0.0.0.0"), - m_linkRecords() + m_linkRecords(), + m_stat(StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); } StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) - : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr) + : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr), + m_stat(lsa.m_stat) { NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty in its constructor!"); CopyLinkRecords (lsa); @@ -47,6 +49,7 @@ StaticRouterLSA::operator= (StaticRouterLSA& lsa) { m_linkStateId = lsa.m_linkStateId; m_advertisingRtr = lsa.m_advertisingRtr; + m_stat = lsa.m_stat; ClearLinkRecords (); CopyLinkRecords (lsa); @@ -201,6 +204,7 @@ StaticRouter::DiscoverLSAs (void) StaticRouterLSA *pLSA = new StaticRouterLSA; pLSA->m_linkStateId = m_routerId; pLSA->m_advertisingRtr = m_routerId; + pLSA->m_stat = StaticRouterLSA::LSA_SPF_NOT_EXPLORED; // // We need to ask the node for the number of net devices attached. This isn't // necessarily equal to the number of links to adjacent nodes (other routers) diff --git a/src/routing/static-router.h b/src/routing/static-router.h index bda6cc04a..3c1c50514 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -168,6 +168,14 @@ public: typedef std::list ListOfLinkRecords_t; ListOfLinkRecords_t m_linkRecords; + + // this is a tristate flag used internally in the SPF computation + enum SPFStatus { + LSA_SPF_NOT_EXPLORED = 0, + LSA_SPF_IN_SPFTREE, + LSA_SPF_IN_CANDIDATE_QUEUE + } m_stat; + }; std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); From e0399adca9e5aaafea706fe8d7a09d66e696c6b6 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 11 Jul 2007 22:54:47 -0700 Subject: [PATCH 051/278] Non-default constructor for SPFVertex --- src/routing/static-route-manager.cc | 18 +++++++++++------- src/routing/static-route-manager.h | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 1a681764e..8bada0079 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -36,9 +36,17 @@ SPFVertex::SPFVertex () : { } +SPFVertex::SPFVertex (StaticRouterLSA* lsa) : + m_vertexType(VertexRouter), + m_vertexId(lsa->m_linkStateId), + m_lsa(lsa), + m_distanceFromRoot(SPF_INFINITY) +{ +} + + SPFVertex::~SPFVertex () { - delete m_lsa; } void @@ -320,12 +328,8 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // Initialize the shortest-path tree to only the router doing the // calculation. // - v= new SPFVertex(); - v->m_vertexType = SPFVertex::VertexRouter; - v->m_vertexId = root; - v-> m_lsa = m_lsdb->GetLSA(root); - // Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the - // spanning tree. + v= new SPFVertex(m_lsdb->GetLSA(root)); + // This vertex is the root of the SPF tree v->m_distanceFromRoot = 0; for (;;) diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 0b0cc4c5d..4734619ce 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -40,6 +40,7 @@ class SPFVertex { public: SPFVertex(); + SPFVertex(StaticRouterLSA*); ~SPFVertex(); void Initialize (); From 534ab7a0305c059ffba2d2ccab694314741e5026 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 11 Jul 2007 23:43:09 -0700 Subject: [PATCH 052/278] finish SPFNext logic; add declaration for NexthopCalculation --- src/routing/static-route-manager.cc | 87 ++++++++++++++++++++--------- src/routing/static-route-manager.h | 2 + src/routing/static-router.h | 2 +- 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 8bada0079..f91f9bc9c 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -224,6 +224,10 @@ StaticRouteManager::InitializeRoutes () void StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) { + SPFVertex* w = 0; + StaticRouterLSA* w_lsa = 0; + uint32_t distance = 0; + if (v->m_vertexType == SPFVertex::VertexRouter) { // Always true for now, since all our LSAs are RouterLSAs @@ -239,19 +243,19 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // link in V's LSA. Links to stub networks will be // considered in the second stage of the shortest path // calculation. - StaticRouterLinkRecord* temp = *i; - if (temp->m_linkType == StaticRouterLinkRecord::StubNetwork) + StaticRouterLinkRecord* l = *i; + if (l->m_linkType == StaticRouterLinkRecord::StubNetwork) { - NS_DEBUG_UNCOND("Found a Stub record to " << temp->m_linkId); + NS_DEBUG_UNCOND("Found a Stub record to " << l->m_linkId); continue; } // (b) Otherwise, W is a transit vertex (router or transit // network). Look up the vertex W's LSA (router-LSA or // network-LSA) in Area A's link state database. - if (temp->m_linkType == StaticRouterLinkRecord::PointToPoint) + if (l->m_linkType == StaticRouterLinkRecord::PointToPoint) { // Lookup the vertex W's LSA - StaticRouterLSA* w_lsa = m_lsdb->GetLSA(temp->m_linkId); + w_lsa = m_lsdb->GetLSA(l->m_linkId); NS_ASSERT(w_lsa); NS_DEBUG_UNCOND("Found a P2P record from " << v->m_vertexId << " to " << w_lsa->m_linkStateId); @@ -267,42 +271,75 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // the link state cost of the (already calculated) // shortest path to vertex V and the advertised cost of // the link between vertices V and W. - - //uint32_t distance = v->m_distanceFromRoot + temp->m_metric; + distance = v->m_distanceFromRoot + l->m_metric; // Here, W is either already in candidate list or not - -#if 0 if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { - SPFVertex* w = new SPFVertex(w_lsa); -#endif - - // ospf_nexthop_calculation() - // priority_queue.enqueu() - // else - // get vertex from candidates list - // if (w->distance < distance) - // continue; // not a shorter path - // else if (w->distance > distance) + w = new SPFVertex(w_lsa); + // Calculate nexthop to W + if (SPFNexthopCalculation(v, w, l, distance)) + { + w_lsa->m_stat = StaticRouterLSA::LSA_SPF_CANDIDATE; + candidate.Push(w); + } + } + } else if (w_lsa->m_stat == + StaticRouterLSA::LSA_SPF_CANDIDATE) + { + //Get the vertex from candidates + w = candidate.Find(w_lsa->m_linkStateId); + if (w->m_distanceFromRoot < distance) + { + continue; // not a shorter path + } + // equal to + else if (w->m_distanceFromRoot == distance) + { + // Do nothing-- not doing equal-cost multipath + } + else + { // Found a lower-cost path to W. // * nexthop_calculation is conditional, if it finds // * valid nexthop it will call spf_add_parents, which // * will flush the old parents // */ - // if (ospf_nexthop_calculation (area, v, w, l, distance)) + if (SPFNexthopCalculation(v, w, l, distance)) + { // /* Decrease the key of the node in the heap, // * re-sort the heap. */ - // trickle_down (w_lsa->stat, candidate); - // - continue; - } - } + candidate.Reorder(); + } + } + } // point-to-point + } // for loop } } NS_DEBUG_UNCOND(""); } +/* 16.1.1. Calculate nexthop from root through V (parent) to + * vertex W (destination), with given distance from root->W. + * + * The link must be supplied if V is the root vertex. In all other cases + * it may be NULL. + * + * Note that this function may fail, hence the state of the destination + * vertex, W, should /not/ be modified in a dependent manner until + * this function returns. This function will update the W vertex with the + * provided distance as appropriate. + */ +int +StaticRouteManager::SPFNexthopCalculation ( + SPFVertex* v, + SPFVertex* w, + StaticRouterLinkRecord* l, + uint32_t distance) +{ + return 1; +} + // quagga ospf_spf_calculate void StaticRouteManager::DebugSPFCalculate(Ipv4Address root) diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 4734619ce..6edf37e17 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -130,6 +130,8 @@ private: StaticRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); void SPFNext (SPFVertex*, CandidateQueue&); + int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* l, uint32_t distance); }; } // namespace ns3 diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 3c1c50514..c863ddc90 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -173,7 +173,7 @@ public: enum SPFStatus { LSA_SPF_NOT_EXPLORED = 0, LSA_SPF_IN_SPFTREE, - LSA_SPF_IN_CANDIDATE_QUEUE + LSA_SPF_CANDIDATE } m_stat; }; From 9f44a9d6a4a76469f9bfb6cc87f3e7041f0f24cf Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 12 Jul 2007 10:47:12 -0700 Subject: [PATCH 053/278] dox for candidate queue --- src/routing/candidate-queue.cc | 2 - src/routing/candidate-queue.h | 109 ++++++++++++++++++++++++++++++++- src/routing/static-router.h | 8 +++ 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/routing/candidate-queue.cc b/src/routing/candidate-queue.cc index 7b5f9ba96..bec333936 100644 --- a/src/routing/candidate-queue.cc +++ b/src/routing/candidate-queue.cc @@ -45,7 +45,6 @@ CandidateQueue::Clear (void) } } - void CandidateQueue::Push (SPFVertex *vNew) { @@ -109,7 +108,6 @@ CandidateQueue::Size (void) return m_candidates.size (); } - SPFVertex * CandidateQueue::Find (const Ipv4Address addr) { diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index 5d266e7c5..c5bfb3c39 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -23,19 +23,112 @@ namespace ns3 { +/** + * \brief a Candidate Queue used in static routing. + * + * The CandidateQueue is used in the OSPF shortest path computations. It + * is a priority queue used to store candidates for the shortest path to a + * given network. + * + * The queue holds Shortest Path First Vertex pointers and orders them + * according to the lowest value of the field m_distanceFromRoot. Remaining + * vertices are ordered according to increasing distance. This implements a + * priority queue. + * + * Although a STL priority_queue almost does what we want, the requirement + * for a Find () operation, the dynamic nature of the data and the derived + * requirement for a Reorder () operation led us to implement this simple + * enhanced priority queue. + */ class CandidateQueue { public: + /** + * Create an empty SPF Candidate Queue. + * + * @see SPFVertex + */ CandidateQueue (); + /** + * Destroy an SPF Candidate Queue and release any resources held by the + * contents. + * + * @see SPFVertex + */ virtual ~CandidateQueue (); - + /** + * Empty the Candidate Queue and release all of the resources associated + * with the Shortest Path First Vertex pointers in the queue. + * + * @see SPFVertex + */ void Clear (void); - void Push (SPFVertex *v); + /** + * Push a Shortest Path First Vertex pointer onto the queue according to the + * priority scheme. + * + * On completion, the top of the queue will hold the Shortest Path First + * Vertex pointer that points to a vertex having lowest value of the field + * m_distanceFromRoot. Remaining vertices are ordered according to + * increasing distance. + * + * @see SPFVertex + * @param vNew The Shortest Path First Vertex to add to the queue. + */ + void Push (SPFVertex *vNew); + /** + * Pop the Shortest Path First Vertex pointer at the top of the queue and + * release the resources associated with the vertex. + * + * @see SPFVertex + * @see Top () + */ void Pop (void); + /** + * Return the Shortest Path First Vertex pointer at the top of the queue. + * This method does not pop the SPFVertex* off of the queue, it simply + * returns the pointer. + * + * @see SPFVertex + * @see Pop () + * @returns The Shortest Path First Vertex pointer at the top of the queue. + */ SPFVertex* Top (void); + /** + * Test the Candidate Queue to determine if it is empty. + * + * @returns True if the queue is empty, false otherwise. + */ bool Empty (void); + /** + * Return the number of Shortest Path First Vertex pointers presently + * stored in the Candidate Queue. + * + * @see SPFVertex + * @returns The number of SPFVertex* pointers in the Candidate Queue. + */ uint32_t Size (void); + /** + * Searches the Candidate Queue for a Shortest Path First Vertex pointer + * that points to a vertex having the given IP address. + * + * @see SPFVertex + * @param addr The IP address to search for. + * @returns The SPFVertex* pointer corresponding to the given IP address. + */ SPFVertex* Find (const Ipv4Address addr); + /** + * Reorders the Candidate Queue according to the priority scheme. On + * completion, the top of the queue will hold the Shortest Path First + * Vertex pointer that points to a vertex having lowest value of the field + * m_distanceFromRoot. Remaining vertices are ordered according to + * increasing distance. + * + * This method is provided in case the values of m_distanceFromRoot change + * during the routing calculations. + * + * @see SPFVertex + */ void Reorder (void); protected: @@ -43,6 +136,18 @@ protected: CandidateList_t m_candidates; private: + /** + * Candidate Queue copy construction is disallowed (not implemented) to + * prevent the compiler from slipping in incorrect versions that don't + * properly deal with deep copies. + */ + CandidateQueue (CandidateQueue& sr); + /** + * Candidate Queue assignment operator is disallowed (not implemented) to + * prevent the compiler from slipping in incorrect versions that don't + * properly deal with deep copies. + */ + CandidateQueue& operator= (CandidateQueue& sr); }; } // namespace ns3 diff --git a/src/routing/static-router.h b/src/routing/static-router.h index c863ddc90..1d7bf2ab3 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -282,6 +282,14 @@ protected: Ipv4Address m_routerId; private: + /** + * Static Router copy construction is disallowed. + */ + StaticRouter (StaticRouter& sr); + /** + * Static Router copy assignment operator is disallowed. + */ + StaticRouter& operator= (StaticRouter& sr); }; } // namespace ns3 From 6361dd3f6e89b56d9520c64f813243d2c77350b9 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Thu, 12 Jul 2007 11:05:23 -0700 Subject: [PATCH 054/278] Initial logic for SPFNexthopCalculation --- src/routing/static-route-manager.cc | 86 +++++++++++++++++++---------- src/routing/static-route-manager.h | 17 +++--- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index f91f9bc9c..5fb613790 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -32,7 +32,10 @@ SPFVertex::SPFVertex () : m_vertexType(VertexUnknown), m_vertexId("255.255.255.255"), m_lsa(0), - m_distanceFromRoot(SPF_INFINITY) + m_parent(0), + m_children(), + m_distanceFromRoot(SPF_INFINITY), + m_root_oif(SPF_INFINITY) { } @@ -40,7 +43,10 @@ SPFVertex::SPFVertex (StaticRouterLSA* lsa) : m_vertexType(VertexRouter), m_vertexId(lsa->m_linkStateId), m_lsa(lsa), - m_distanceFromRoot(SPF_INFINITY) + m_parent(0), + m_children(), + m_distanceFromRoot(SPF_INFINITY), + m_root_oif(SPF_INFINITY) { } @@ -49,13 +55,6 @@ SPFVertex::~SPFVertex () { } -void -SPFVertex::Initialize () -{ - m_distanceFromRoot = SPF_INFINITY; - // XXX previous = 0 -} - StaticRouteManagerLSDB::~StaticRouteManagerLSDB() { NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); @@ -107,7 +106,7 @@ StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) return 0; } -StaticRouteManager::StaticRouteManager () +StaticRouteManager::StaticRouteManager () : m_spfroot(0) { m_lsdb = new StaticRouteManagerLSDB (); } @@ -321,14 +320,8 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) /* 16.1.1. Calculate nexthop from root through V (parent) to * vertex W (destination), with given distance from root->W. - * - * The link must be supplied if V is the root vertex. In all other cases - * it may be NULL. - * - * Note that this function may fail, hence the state of the destination - * vertex, W, should /not/ be modified in a dependent manner until - * this function returns. This function will update the W vertex with the - * provided distance as appropriate. + * + * This greatly simplified from quagga */ int StaticRouteManager::SPFNexthopCalculation ( @@ -337,6 +330,21 @@ StaticRouteManager::SPFNexthopCalculation ( StaticRouterLinkRecord* l, uint32_t distance) { + if (v == m_spfroot) + { + // parent of w is the root itself + // calculate the interfaceid of the router that corresponds + // to link l between v and w and store it in w->m_root_oif + // This root_oif is then used when installing host routes for the + // destinations covered by this vertex + } + else + { + // Inherit the root_oif from the current parent + w->m_root_oif = v->m_root_oif; + } + w->m_distanceFromRoot = distance; + w->m_parent = v; return 1; } @@ -353,7 +361,9 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) { NS_DEBUG_UNCOND("StaticRouteManager::SPFCalculate ()"); - SPFVertex* v; + SPFVertex *v; + + // Query Interface for the IPv4-route interface // The candidate queue is a priority queue of SPFVertex objects, with // the top of the queue being the closest vertex in terms of @@ -368,17 +378,17 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) v= new SPFVertex(m_lsdb->GetLSA(root)); // This vertex is the root of the SPF tree v->m_distanceFromRoot = 0; + m_spfroot= v; for (;;) { // RFC2328 16.1. (2). SPFNext(v , candidate); -#if 0 /* RFC2328 16.1. (3). */ /* If at this step the candidate list is empty, the shortest- * path tree (of transit vertices) has been completely built and * this stage of the procedure terminates. */ - if (candidate->size == 0) + if (candidate.Size() == 0) break; /* Otherwise, choose the vertex belonging to the candidate list @@ -386,17 +396,21 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) * tree (removing it from the candidate list in the * process). */ /* Extract from the candidates the node with the lower key. */ - v = (struct vertex *) pqueue_dequeue (candidate); + v = candidate.Top(); + candidate.Pop(); /* Update stat field in vertex. */ - *(v->stat) = LSA_SPF_IN_SPFTREE; - - ospf_vertex_add_parent (v); + v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; + SPFVertexAddParent(v); +#if 0 /* Note that when there is a choice of vertices closest to the * root, network vertices must be chosen before router vertices * in order to necessarily find all equal-cost paths. */ /* We don't do this at this moment, we should add the treatment * above codes. -- kunihiro. */ + +INSTALL HOST ROUTES HERE + /* RFC2328 16.1. (4). */ if (v->type == OSPF_VERTEX_ROUTER) ospf_intra_add_router (new_rtrs, v, area); @@ -413,15 +427,29 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) /* Free candidate queue. */ pqueue_delete (candidate); - + #endif + break; } - - - + DeleteSPFVertexChain(m_spfroot); + m_spfroot = 0; } +// Add a vertex to the list of children in each of its parents. +void +StaticRouteManager::SPFVertexAddParent(SPFVertex* v) +{ +} + +void +StaticRouteManager::DeleteSPFVertexChain(SPFVertex* spfroot) +{ + // spfroot is the root of all SPFVertex created during the SPF process + // each vertex has a number of children + // Recursively, delete all of the SPFVertex children of each SPFVertex + // then delete root itself +} } // namespace ns3 diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 6edf37e17..fbde872e9 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -42,7 +42,6 @@ public: SPFVertex(); SPFVertex(StaticRouterLSA*); ~SPFVertex(); - void Initialize (); enum VertexType { VertexUnknown = 0, @@ -54,14 +53,15 @@ public: StaticRouterLSA* m_lsa; // This pointer owns LSA for mem. mgmt purposes - // XXX not sure exactly what data structure is needed here - // need to keep track of previous vertex - typedef std::list type_listOfSPFVertex; - type_listOfSPFVertex m_parents; - type_listOfSPFVertex m_children; - type_listOfSPFVertex::iterator m_iter; + // need to keep track of current parent vertex + SPFVertex* m_parent; + // m_children lists the leaves from your SPF tree + typedef std::list t_listOfSPFVertex; + t_listOfSPFVertex m_children; + t_listOfSPFVertex::iterator m_SPFVertexIter; uint32_t m_distanceFromRoot; + uint32_t m_root_oif; }; @@ -127,11 +127,14 @@ public: protected: private: + SPFVertex* m_spfroot; StaticRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); void SPFNext (SPFVertex*, CandidateQueue&); int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, StaticRouterLinkRecord* l, uint32_t distance); + void SPFVertexAddParent(SPFVertex* v); + void DeleteSPFVertexChain(SPFVertex* spfroot); }; } // namespace ns3 From ba94df76e1cf4872abb28357170f6312cd26a431 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Thu, 12 Jul 2007 11:41:59 -0700 Subject: [PATCH 055/278] Finish function prototypes --- src/routing/static-route-manager.cc | 60 +++++++++++++++++++++-------- src/routing/static-route-manager.h | 4 ++ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 5fb613790..d33b8c15b 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -337,6 +337,10 @@ StaticRouteManager::SPFNexthopCalculation ( // to link l between v and w and store it in w->m_root_oif // This root_oif is then used when installing host routes for the // destinations covered by this vertex + // + // Find the outgoing interface on v corresponding to the link l + // between v and w + w->m_root_oif = FindOutgoingInterface(v,w,l); } else { @@ -348,6 +352,20 @@ StaticRouteManager::SPFNexthopCalculation ( return 1; } +uint32_t +StaticRouteManager::FindOutgoingInterface ( + SPFVertex* v, + SPFVertex* w, + StaticRouterLinkRecord* l + ) +{ + // Using the Ipv4 public APIs of a node, find the outgoing + // interface ID corresponding to the link l between vertex v and w + // where v is the root of the tree + return 0; +} + + // quagga ospf_spf_calculate void StaticRouteManager::DebugSPFCalculate(Ipv4Address root) @@ -363,7 +381,6 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) SPFVertex *v; - // Query Interface for the IPv4-route interface // The candidate queue is a priority queue of SPFVertex objects, with // the top of the queue being the closest vertex in terms of @@ -401,52 +418,63 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) /* Update stat field in vertex. */ v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; SPFVertexAddParent(v); -#if 0 /* Note that when there is a choice of vertices closest to the * root, network vertices must be chosen before router vertices * in order to necessarily find all equal-cost paths. */ /* We don't do this at this moment, we should add the treatment * above codes. -- kunihiro. */ - -INSTALL HOST ROUTES HERE - /* RFC2328 16.1. (4). */ - if (v->type == OSPF_VERTEX_ROUTER) - ospf_intra_add_router (new_rtrs, v, area); - else - ospf_intra_add_transit (new_table, v, area); + SPFIntraAddRouter (v); /* RFC2328 16.1. (5). */ /* Iterate the algorithm by returning to Step 2. */ } /* end loop until no more candidate vertices */ +#ifdef NOTYET /* Second stage of SPF calculation procedure's */ ospf_spf_process_stubs (area, area->spf, new_table); - - /* Free candidate queue. */ - pqueue_delete (candidate); - #endif - break; - } DeleteSPFVertexChain(m_spfroot); m_spfroot = 0; } +void +StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) +{ + + // This vertex has just been added to the SPF tree + // - the vertex should have a valid m_root_oid corresponding + // to the outgoing interface on the root router of the tree + // that corresponds to the path to it + // - the vertex has an m_lsa field that has a number of link + // records. For each point to point record, the m_linkData + // is a destination IP address to which we add a host route + // + + // Therefore, this routine's logic should be: + // i) obtain the ipv4-route interface of the node corresponding + // to m_spfroot (vertex) + // i.e. Query Interface for the IPv4-route interface + // ii) for each point-to-point link in v->m_lsa + // ipv4-route::AddHostRouteTo(m_linkData, m_root_oid); +} + // Add a vertex to the list of children in each of its parents. void StaticRouteManager::SPFVertexAddParent(SPFVertex* v) { + // For now, only one parent (not doing equal-cost multipath) + v->m_parent->m_children.push_back(v); } void StaticRouteManager::DeleteSPFVertexChain(SPFVertex* spfroot) { // spfroot is the root of all SPFVertex created during the SPF process - // each vertex has a number of children + // each vertex has a list of children // Recursively, delete all of the SPFVertex children of each SPFVertex // then delete root itself } diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index fbde872e9..ac7eb9f07 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -135,6 +135,10 @@ private: StaticRouterLinkRecord* l, uint32_t distance); void SPFVertexAddParent(SPFVertex* v); void DeleteSPFVertexChain(SPFVertex* spfroot); + uint32_t FindOutgoingInterface(SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* l); + void SPFIntraAddRouter(SPFVertex* v); + }; } // namespace ns3 From be74b3dca89a4033c7c4ad49e97f470a4f8e0740 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 12 Jul 2007 22:15:59 -0700 Subject: [PATCH 056/278] implement SPFIntraAddRouter --- src/routing/static-route-manager.cc | 89 +++++++++++++++++++++++++++-- src/routing/static-route-manager.h | 2 +- src/routing/static-router.cc | 48 +++++++++++++--- src/routing/static-router.h | 16 +++++- 4 files changed, 138 insertions(+), 17 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index d33b8c15b..e68a85719 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -20,6 +20,7 @@ #include "ns3/fatal-error.h" #include "ns3/debug.h" #include "ns3/node-list.h" +#include "ns3/ipv4.h" #include "static-router.h" #include "static-route-manager.h" #include "candidate-queue.h" @@ -352,6 +353,10 @@ StaticRouteManager::SPFNexthopCalculation ( return 1; } +// +// Figure out which interface that the node represented by v will want to use +// to send packets to the node represented by w over the link represented by l +// uint32_t StaticRouteManager::FindOutgoingInterface ( SPFVertex* v, @@ -359,6 +364,12 @@ StaticRouteManager::FindOutgoingInterface ( StaticRouterLinkRecord* l ) { + NS_ASSERT_MSG(v == m_spfroot, + "StaticRouterManager""FindOutgoingInterface (): " + "The node of interest must be the root node"); + + // want interface that v uses to send packets + // Using the Ipv4 public APIs of a node, find the outgoing // interface ID corresponding to the link l between vertex v and w // where v is the root of the tree @@ -444,7 +455,6 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) void StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) { - // This vertex has just been added to the SPF tree // - the vertex should have a valid m_root_oid corresponding // to the outgoing interface on the root router of the tree @@ -460,6 +470,75 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) // i.e. Query Interface for the IPv4-route interface // ii) for each point-to-point link in v->m_lsa // ipv4-route::AddHostRouteTo(m_linkData, m_root_oid); + + NS_ASSERT_MSG(m_spfroot, + "StaticRouteManager::SPFIntraAddRouter (): Root pointer not set"); + + Ipv4Address routerId = m_spfroot->m_vertexId; + + std::vector >::iterator i = NodeList::Begin(); + for (; i != NodeList::End(); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); + NS_ASSERT_MSG(rtr, + "StaticRouteManager::SPFIntraAddRouter (): " + "QI for interface failed"); + + if (rtr->GetRouterId () == routerId) + { + NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + "setting routes for node " << node->GetId ()); + + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4, + "StaticRouteManager::SPFIntraAddRouter (): " + "QI for interface failed"); + + StaticRouterLSA *lsa = v->m_lsa; + NS_ASSERT_MSG(lsa, + "StaticRouteManager::SPFIntraAddRouter (): " + "Expected valid LSA in SPFVertex* v"); + + uint32_t nLinkRecords = lsa->GetNLinkRecords (); + + NS_ASSERT_MSG((nLinkRecords & 1) == 0, + "StaticRouteManager::SPFIntraAddRouter (): " + "Expected exen number of Link Records"); + + for (uint32_t j = 0; j < nLinkRecords; j += 2) + { + StaticRouterLinkRecord *lrp2p = lsa->GetLinkRecord (j); + NS_ASSERT_MSG( + lrp2p->m_linkType == StaticRouterLinkRecord::PointToPoint, + "StaticRouteManager::SPFIntraAddRouter (): " + "Expected PointToPoint Link Record"); + + StaticRouterLinkRecord *lrstub = lsa->GetLinkRecord (j + 1); + NS_ASSERT_MSG( + lrstub->m_linkType == StaticRouterLinkRecord::StubNetwork, + "StaticRouteManager::SPFIntraAddRouter (): " + "Expected StubNetwork Link Record"); +// +// BUGBUG +// +// Where does the next hop address come from? +// + NS_ASSERT_MSG(false, "BUGBUG"); + + NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + "Add route to " << lrp2p->m_linkData << + " using next hop " << lrp2p->m_linkData << + " via interface " << v->m_root_oif); + + ipv4->AddHostRouteTo(lrp2p->m_linkData, lrp2p->m_linkData, + v->m_root_oif); + } + break; + } + } } // Add a vertex to the list of children in each of its parents. @@ -529,21 +608,21 @@ StaticRouteManagerTest::RunTests (void) { bool ok = true; - CandidateQueue candidate; // <---------------- + CandidateQueue candidate; for (int i = 0; i < 100; ++i) { SPFVertex *v = new SPFVertex; v->m_distanceFromRoot = rand () % 100; - candidate.Push (v); // <---------------- + candidate.Push (v); } uint32_t lastDistance = 0; for (int i = 0; i < 100; ++i) { - SPFVertex *v = candidate.Top (); // <---------------- - candidate.Pop (); // <---------------- + SPFVertex *v = candidate.Top (); + candidate.Pop (); if (v->m_distanceFromRoot < lastDistance) { ok = false; diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index ac7eb9f07..85a96a71a 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -49,7 +49,7 @@ public: VertexNetwork } m_vertexType; - Ipv4Address m_vertexId; + Ipv4Address m_vertexId; // router id StaticRouterLSA* m_lsa; // This pointer owns LSA for mem. mgmt purposes diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index e0bceb40a..81bbee2a6 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -40,7 +40,8 @@ StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr), m_stat(lsa.m_stat) { - NS_ASSERT_MSG(IsEmpty(), "The LSA must be empty in its constructor!"); + NS_ASSERT_MSG(IsEmpty(), + "StaticRouterLSA::StaticRouterLSA (): Non-empty LSA in constructor"); CopyLinkRecords (lsa); } @@ -105,6 +106,30 @@ StaticRouterLSA::AddLinkRecord (StaticRouterLinkRecord* lr) return m_linkRecords.size (); } + uint32_t +StaticRouterLSA::GetNLinkRecords (void) +{ + return m_linkRecords.size (); +} + + StaticRouterLinkRecord * +StaticRouterLSA::GetLinkRecord (uint32_t n) +{ + uint32_t j = 0; + for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); + i != m_linkRecords.end (); + i++, j++) + { + if (j == n) + { + return *i; + } + } + NS_ASSERT_MSG(false, "StaticRouterLSA::GetLinkRecord (): invalid index"); + return 0; +} + + bool StaticRouterLSA::IsEmpty (void) { @@ -186,7 +211,9 @@ StaticRouter::GetRouterId (void) StaticRouter::DiscoverLSAs (void) { NS_DEBUG("StaticRouter::DiscoverLSAs ()"); - NS_ASSERT_MSG(m_node, " interface not set"); + NS_ASSERT_MSG(m_node, + "StaticRouter::DiscoverLSAs (): interface not set"); + ClearLSAs (); // // We're aggregated to a node. We need to ask the node for a pointer to its @@ -194,7 +221,8 @@ StaticRouter::DiscoverLSAs (void) // interfaces lives. // Ptr ipv4Local = m_node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4Local, "QI for interface failed"); + NS_ASSERT_MSG(ipv4Local, + "StaticRouter::DiscoverLSAs (): QI for interface failed"); // // We are, for now at least, only going to report RouterLSAs in this method. // What this means is that there is going to be one advertisement with some @@ -257,14 +285,16 @@ StaticRouter::DiscoverLSAs (void) // Ptr nodeRemote = ndRemote->GetNode(); Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4Remote, "QI for remote interface failed"); + NS_ASSERT_MSG(ipv4Remote, + "StaticRouter::DiscoverLSAs (): QI for remote failed"); // // Per the OSPF spec, we're going to need the remote router ID, so we might as // well get it now. // Ptr srRemote = nodeRemote->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG(srRemote, "QI for remote failed"); + NS_ASSERT_MSG(srRemote, + "StaticRouter::DiscoverLSAs (): QI for remote failed"); Ipv4Address rtrIdRemote = srRemote->GetRouterId(); NS_DEBUG("Working with remote router " << rtrIdRemote); // @@ -319,7 +349,7 @@ StaticRouter::GetNumLSAs (void) bool StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) { - NS_ASSERT_MSG(lsa.IsEmpty(), "Must pass empty LSA"); + NS_ASSERT_MSG(lsa.IsEmpty(), "StaticRouter::GetLSA (): Must pass empty LSA"); // // All of the work was done in GetNumLSAs. All we have to do here is to // walk the list of link state advertisements created there and return the @@ -355,7 +385,7 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) uint32_t nDevices = ch->GetNDevices(); NS_ASSERT_MSG(nDevices == 2, - "Point to point channel with other than two devices is not expected"); + "StaticRouter::GetAdjacent (): Channel with other than two devices"); // // This is a point to point channel with two endpoints. Get both of them. // @@ -376,8 +406,8 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) } else { - NS_ASSERT_MSG(0, - "Neither channel endpoint thinks it is connected to this net device"); + NS_ASSERT_MSG(false, + "StaticRouter::GetAdjacent (): Wrong or confused channel?"); return 0; } } diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 1d7bf2ab3..b6331021a 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -125,13 +125,25 @@ public: */ void CopyLinkRecords (StaticRouterLSA& lsa); /** - * Add a given Static Router Link Record to a given Static Router Link - * State Advertisement. + * Add a given Static Router Link Record to the LSA. * * @param lr The Static Router Link Record to be added. * @returns The number of link records in the list. */ uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); + /** + * Return the number of Static Router Link Records in the LSA. + * + * @returns The number of link records in the list. + */ + uint32_t GetNLinkRecords (void); + /** + * Return a pointer to the specified Static Router Link Record. + * + * @param n The LSA number desired. + * @returns The number of link records in the list. + */ + StaticRouterLinkRecord* GetLinkRecord (uint32_t n); /** * Release all of the Static Router Link Records present in the Static * Router Link State Advertisement and make the list of link records empty. From 3e0167a9e9752afa0d555198ee21dcc745e1ef88 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 13 Jul 2007 12:21:48 -0700 Subject: [PATCH 057/278] delete vertices, fix candidate queue pop/top semantics --- src/routing/candidate-queue.cc | 11 ++--- src/routing/candidate-queue.h | 8 ++-- src/routing/static-route-manager.cc | 68 +++++++++++++---------------- src/routing/static-route-manager.h | 1 - 4 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/routing/candidate-queue.cc b/src/routing/candidate-queue.cc index bec333936..b45af7ac2 100644 --- a/src/routing/candidate-queue.cc +++ b/src/routing/candidate-queue.cc @@ -41,7 +41,9 @@ CandidateQueue::Clear (void) while (!m_candidates.empty ()) { - Pop (); + SPFVertex *p = Pop (); + delete p; + p = 0; } } @@ -63,20 +65,19 @@ CandidateQueue::Push (SPFVertex *vNew) m_candidates.insert(i, vNew); } - void + SPFVertex * CandidateQueue::Pop (void) { NS_DEBUG("CandidateQueue::Pop ()"); if (m_candidates.empty ()) { - return; + return 0; } SPFVertex *v = m_candidates.front (); m_candidates.pop_front (); - delete v; - v = 0; + return v; } SPFVertex * diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index c5bfb3c39..146de707c 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -77,13 +77,15 @@ public: */ void Push (SPFVertex *vNew); /** - * Pop the Shortest Path First Vertex pointer at the top of the queue and - * release the resources associated with the vertex. + * Pop the Shortest Path First Vertex pointer at the top of the queue. + * The caller is given the responsiblity for releasing the resources + * associated with the vertex. * * @see SPFVertex * @see Top () + * @returns The Shortest Path First Vertex pointer at the top of the queue. */ - void Pop (void); + SPFVertex* Pop (void); /** * Return the Shortest Path First Vertex pointer at the top of the queue. * This method does not pop the SPFVertex* off of the queue, it simply diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index e68a85719..2aa2a857e 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -51,9 +51,18 @@ SPFVertex::SPFVertex (StaticRouterLSA* lsa) : { } - SPFVertex::~SPFVertex () { + for ( t_listOfSPFVertex::iterator i = m_children.begin (); + i != m_children.end (); + i++) + { + SPFVertex *p = *i; + delete p; + p = 0; + *i = 0; + } + m_children.clear(); } StaticRouteManagerLSDB::~StaticRouteManagerLSDB() @@ -89,7 +98,7 @@ StaticRouteManagerLSDB::Initialize() void StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) { - m_database.insert(LSDBPair_t(addr, lsa)); + m_database.insert(LSDBPair_t(addr, lsa)); } StaticRouterLSA* @@ -153,8 +162,7 @@ StaticRouteManager::BuildStaticRoutingDatabase () { StaticRouterLSA* lsa = new StaticRouterLSA (); rtr->GetLSA(j, *lsa); - NS_DEBUG_UNCOND ("LSA " << j); - NS_DEBUG_UNCOND ("----------------------------"); + NS_DEBUG_UNCOND ("*** LSA " << j); NS_DEBUG_UNCOND (*lsa); m_lsdb->Insert (lsa->m_linkStateId, lsa); } @@ -424,8 +432,7 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) * tree (removing it from the candidate list in the * process). */ /* Extract from the candidates the node with the lower key. */ - v = candidate.Top(); - candidate.Pop(); + v = candidate.Pop(); /* Update stat field in vertex. */ v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; SPFVertexAddParent(v); @@ -448,7 +455,7 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) ospf_spf_process_stubs (area, area->spf, new_table); #endif - DeleteSPFVertexChain(m_spfroot); + delete m_spfroot; m_spfroot = 0; } @@ -508,33 +515,26 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) "StaticRouteManager::SPFIntraAddRouter (): " "Expected exen number of Link Records"); - for (uint32_t j = 0; j < nLinkRecords; j += 2) + for (uint32_t j = 0; j < nLinkRecords; ++j) { - StaticRouterLinkRecord *lrp2p = lsa->GetLinkRecord (j); - NS_ASSERT_MSG( - lrp2p->m_linkType == StaticRouterLinkRecord::PointToPoint, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected PointToPoint Link Record"); - - StaticRouterLinkRecord *lrstub = lsa->GetLinkRecord (j + 1); - NS_ASSERT_MSG( - lrstub->m_linkType == StaticRouterLinkRecord::StubNetwork, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected StubNetwork Link Record"); + StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); + if (lr->m_linkType != StaticRouterLinkRecord::PointToPoint) + { + continue; + } // -// BUGBUG +// BUGBUG This is not right. Need to find the next hop interface correctly // -// Where does the next hop address come from? -// - NS_ASSERT_MSG(false, "BUGBUG"); + NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + "BUGBUG incorrect next hope calculation"); NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " - "Add route to " << lrp2p->m_linkData << - " using next hop " << lrp2p->m_linkData << + "Add route to " << lr->m_linkData << + " using next hop " << lr->m_linkData << " via interface " << v->m_root_oif); - ipv4->AddHostRouteTo(lrp2p->m_linkData, lrp2p->m_linkData, - v->m_root_oif); + ipv4->AddHostRouteTo(lr->m_linkData, + lr->m_linkData, v->m_root_oif); } break; } @@ -549,15 +549,6 @@ StaticRouteManager::SPFVertexAddParent(SPFVertex* v) v->m_parent->m_children.push_back(v); } -void -StaticRouteManager::DeleteSPFVertexChain(SPFVertex* spfroot) -{ - // spfroot is the root of all SPFVertex created during the SPF process - // each vertex has a list of children - // Recursively, delete all of the SPFVertex children of each SPFVertex - // then delete root itself -} - } // namespace ns3 #ifdef RUN_SELF_TESTS @@ -621,12 +612,13 @@ StaticRouteManagerTest::RunTests (void) for (int i = 0; i < 100; ++i) { - SPFVertex *v = candidate.Top (); - candidate.Pop (); + SPFVertex *v = candidate.Pop (); if (v->m_distanceFromRoot < lastDistance) { ok = false; } + delete v; + v = 0; lastDistance = v->m_distanceFromRoot; } diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 85a96a71a..d0cb28aa7 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -62,7 +62,6 @@ public: uint32_t m_distanceFromRoot; uint32_t m_root_oif; - }; /** From c4ee764dd83399e5c1cde4b47aa5096917514f43 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 13 Jul 2007 13:33:56 -0700 Subject: [PATCH 058/278] Debugged; works --- examples/simple-static-routing.cc | 10 +- src/routing/routing-environment.cc | 2 +- src/routing/static-route-manager.cc | 400 +++++++++++++++++----------- src/routing/static-route-manager.h | 13 +- src/routing/static-router.h | 4 +- 5 files changed, 253 insertions(+), 176 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 7a366f736..71fc00044 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -82,6 +82,7 @@ int main (int argc, char *argv[]) DebugComponentEnable("PointToPointChannel"); DebugComponentEnable("PointToPointNetDevice"); DebugComponentEnable("StaticRouter"); + DebugComponentEnable("StaticRouteManager"); #endif // Set up some default values for the simulation. Use the Bind() @@ -146,15 +147,6 @@ int main (int argc, char *argv[]) routeManager->BuildStaticRoutingDatabase (); routeManager->InitializeRoutes (); - // XXX this goes away once static routing is in place - // Finally, we add static routes. These three steps (Channel and - // NetDevice creation, IP Address assignment, and routing) are - // separated because there may be a need to postpone IP Address - // assignment (emulation) or modify to use dynamic routing - PointToPointTopology::AddIpv4Routes(n0, n2, channel0); - PointToPointTopology::AddIpv4Routes(n1, n2, channel1); - PointToPointTopology::AddIpv4Routes(n2, n3, channel2); - // Create the OnOff application to send UDP datagrams of size // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( diff --git a/src/routing/routing-environment.cc b/src/routing/routing-environment.cc index 73e936ca8..33eeafbe5 100644 --- a/src/routing/routing-environment.cc +++ b/src/routing/routing-environment.cc @@ -39,7 +39,7 @@ StaticRoutingEnabled(void) AllocateRouterId(void) { static uint32_t routerId = 0; - return ++routerId; + return routerId++; } } // namespace RoutingEnvironment diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 2aa2a857e..8b72927d8 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -36,7 +36,8 @@ SPFVertex::SPFVertex () : m_parent(0), m_children(), m_distanceFromRoot(SPF_INFINITY), - m_root_oif(SPF_INFINITY) + m_rootOif(SPF_INFINITY), + m_nextHop("0.0.0.0") { } @@ -47,22 +48,14 @@ SPFVertex::SPFVertex (StaticRouterLSA* lsa) : m_parent(0), m_children(), m_distanceFromRoot(SPF_INFINITY), - m_root_oif(SPF_INFINITY) + m_rootOif(SPF_INFINITY), + m_nextHop("0.0.0.0") { } + SPFVertex::~SPFVertex () { - for ( t_listOfSPFVertex::iterator i = m_children.begin (); - i != m_children.end (); - i++) - { - SPFVertex *p = *i; - delete p; - p = 0; - *i = 0; - } - m_children.clear(); } StaticRouteManagerLSDB::~StaticRouteManagerLSDB() @@ -80,7 +73,6 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB() m_database.clear(); } -#if 0 void StaticRouteManagerLSDB::Initialize() { @@ -90,20 +82,21 @@ StaticRouteManagerLSDB::Initialize() for (i= m_database.begin(); i!= m_database.end(); i++) { StaticRouterLSA* temp = i->second; - temp->Initialize(); + temp->m_stat = StaticRouterLSA::LSA_SPF_NOT_EXPLORED; } } -#endif void StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) { + NS_DEBUG("StaticRouteManagerLSDB::Insert ()"); m_database.insert(LSDBPair_t(addr, lsa)); } StaticRouterLSA* StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) { + NS_DEBUG("StaticRouteManagerLSDB::GetLSA ()"); // Look up an LSA by its address LSDBMap_t::iterator i; for (i= m_database.begin(); i!= m_database.end(); i++) @@ -123,6 +116,8 @@ StaticRouteManager::StaticRouteManager () : m_spfroot(0) StaticRouteManager::~StaticRouteManager () { + NS_DEBUG("StaticRouteManager::~StaticRouteManager ()"); + if (m_lsdb) delete m_lsdb; } @@ -138,73 +133,74 @@ StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) void StaticRouteManager::BuildStaticRoutingDatabase () { - // walk list of nodes. QI for StaticRouter interface. + NS_DEBUG("StaticRouteManager::BuildStaticRoutingDatabase()"); + + // Walk the list of nodes. QI for StaticRouter interface. // if node has a StaticRouter interface, grab the LSAs // from it and stick them in the LSDB typedef std::vector < Ptr >::iterator Iterator; for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) { Ptr node = *i; - NS_DEBUG_UNCOND ("node="<< node->GetId () ); Ptr rtr = node->QueryInterface (StaticRouter::iid); NS_ASSERT_MSG(rtr, "QI for interface failed"); -// -// Should call DiscoverLSAs () before trying to use any routing info or to -// update LSAs. Subsequently you may use GetNumLSAs(). If you call -// GetNumLSAs () before calling DiscoverLSAs () will get zero as the number. -// + + // You must call DiscoverLSAs () before trying to use any + // routing info or to update LSAs. Subsequently you may use + // GetNumLSAs(). If you call GetNumLSAs () before calling + // DiscoverLSAs () will get zero as the number. uint32_t numLSAs = rtr->DiscoverLSAs(); - NS_DEBUG_UNCOND ("Found " << numLSAs << " LSAs"); + NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); for (uint32_t j = 0; j < numLSAs; ++j) { StaticRouterLSA* lsa = new StaticRouterLSA (); rtr->GetLSA(j, *lsa); - NS_DEBUG_UNCOND ("*** LSA " << j); - NS_DEBUG_UNCOND (*lsa); + NS_DEBUG ("LSA " << j); + NS_DEBUG ("----------------------------"); + NS_DEBUG (*lsa); m_lsdb->Insert (lsa->m_linkStateId, lsa); } } } - // For each node that is a static router (which can be determined by - // the presence of StaticRouter interface), run Dijkstra SPF calculation - // on the database rooted at that router, and populate the node - // forwarding tables - // +// For each node that is a static router (which can be determined by +// the presence of StaticRouter interface), run Dijkstra SPF calculation +// on the database rooted at that router, and populate the node +// forwarding tables void StaticRouteManager::InitializeRoutes () { - NS_DEBUG_UNCOND("StaticRouteManager::InitializeRoutes ()"); -// This function parallels RFC2328, Section 16.1.1, and quagga ospfd -// -// This calculation yields the set of intra-area routes associated -// with an area (called hereafter Area A). A router calculates the -// shortest-path tree using itself as the root. The formation -// of the shortest path tree is done here in two stages. In the -// first stage, only links between routers and transit networks are -// considered. Using the Dijkstra algorithm, a tree is formed from -// this subset of the link state database. In the second stage, -// leaves are added to the tree by considering the links to stub -// networks. + NS_DEBUG("StaticRouteManager::InitializeRoutes ()"); + // This function parallels RFC2328, Section 16.1.1, and quagga ospfd + // + // This calculation yields the set of intra-area routes associated + // with an area (called hereafter Area A). A router calculates the + // shortest-path tree using itself as the root. The formation + // of the shortest path tree is done here in two stages. In the + // first stage, only links between routers and transit networks are + // considered. Using the Dijkstra algorithm, a tree is formed from + // this subset of the link state database. In the second stage, + // leaves are added to the tree by considering the links to stub + // networks. -// The area's link state database is represented as a directed graph. -// The graph's vertices are routers, transit networks and stub networks. -// The first stage of the procedure (i.e., the Dijkstra algorithm) -// can now be summarized as follows. At each iteration of the -// algorithm, there is a list of candidate vertices. Paths from -// the root to these vertices have been found, but not necessarily -// the shortest ones. However, the paths to the candidate vertex -// that is closest to the root are guaranteed to be shortest; this -// vertex is added to the shortest-path tree, removed from the -// candidate list, and its adjacent vertices are examined for -// possible addition to/modification of the candidate list. The -// algorithm then iterates again. It terminates when the candidate -// list becomes empty. + // The area's link state database is represented as a directed graph. + // The graph's vertices are routers, transit networks and stub networks. + // The first stage of the procedure (i.e., the Dijkstra algorithm) + // can now be summarized as follows. At each iteration of the + // algorithm, there is a list of candidate vertices. Paths from + // the root to these vertices have been found, but not necessarily + // the shortest ones. However, the paths to the candidate vertex + // that is closest to the root are guaranteed to be shortest; this + // vertex is added to the shortest-path tree, removed from the + // candidate list, and its adjacent vertices are examined for + // possible addition to/modification of the candidate list. The + // algorithm then iterates again. It terminates when the candidate + // list becomes empty. - // For each node that is a router in the topology + // Iterate for each node that is a router in the topology typedef std::vector < Ptr >::iterator Iterator; for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) { @@ -221,14 +217,11 @@ StaticRouteManager::InitializeRoutes () } -// quagga ospf_spf_next +// Derived from quagga ospf_spf_next() // RFC2328 Section 16.1 (2). // v is on the SPF tree. Examine the links in v's LSA. Update the list // of candidates with any vertices not already on the list. If a lower-cost // path is found to a vertex already on the candidate list, store the new cost. -// -// -// void StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) { @@ -236,12 +229,14 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) StaticRouterLSA* w_lsa = 0; uint32_t distance = 0; + NS_DEBUG("StaticRouteManager::SPFNext ()"); if (v->m_vertexType == SPFVertex::VertexRouter) { // Always true for now, since all our LSAs are RouterLSAs if (true) { - NS_DEBUG_UNCOND("Examining " << v->m_vertexId << "'s link records"); + NS_DEBUG ("SPFNext: Examining " << v->m_vertexId << "'s " << + v->m_lsa->m_linkRecords.size() << " link records"); for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = v->m_lsa->m_linkRecords.begin(); i != v->m_lsa->m_linkRecords.end(); @@ -254,7 +249,8 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) StaticRouterLinkRecord* l = *i; if (l->m_linkType == StaticRouterLinkRecord::StubNetwork) { - NS_DEBUG_UNCOND("Found a Stub record to " << l->m_linkId); + NS_DEBUG("SPFNext: Found a Stub record to " + << l->m_linkId); continue; } // (b) Otherwise, W is a transit vertex (router or transit @@ -265,13 +261,14 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // Lookup the vertex W's LSA w_lsa = m_lsdb->GetLSA(l->m_linkId); NS_ASSERT(w_lsa); - NS_DEBUG_UNCOND("Found a P2P record from " << + NS_DEBUG("SPFNext: Found a P2P record from " << v->m_vertexId << " to " << w_lsa->m_linkStateId); // (c) If vertex W is already on the shortest-path tree, // examine the next link in the LSA. if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_IN_SPFTREE) { - NS_DEBUG("LSA "<< w_lsa->m_linkStateId << " in SPF"); + NS_DEBUG("SPFNext: Skipping-> LSA "<< + w_lsa->m_linkStateId << " already in SPF tree"); continue; } // (d) Calculate the link state cost D of the resulting path @@ -281,15 +278,19 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // the link between vertices V and W. distance = v->m_distanceFromRoot + l->m_metric; + NS_DEBUG("SPFNext: Considering w_lsa " << + w_lsa->m_linkStateId); // Here, W is either already in candidate list or not if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { - w = new SPFVertex(w_lsa); + w = new SPFVertex(w_lsa); // Calculate nexthop to W if (SPFNexthopCalculation(v, w, l, distance)) { w_lsa->m_stat = StaticRouterLSA::LSA_SPF_CANDIDATE; candidate.Push(w); + NS_DEBUG("SPFNext: Pushing " << w->m_vertexId + << ", parent vertexId: " << v->m_vertexId); } } } else if (w_lsa->m_stat == @@ -308,30 +309,29 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) } else { - // Found a lower-cost path to W. - // * nexthop_calculation is conditional, if it finds - // * valid nexthop it will call spf_add_parents, which - // * will flush the old parents - // */ + // Found a lower-cost path to W. + // nexthop_calculation is conditional, if it finds + // valid nexthop it will call spf_add_parents, which + // will flush the old parents if (SPFNexthopCalculation(v, w, l, distance)) { - // /* Decrease the key of the node in the heap, - // * re-sort the heap. */ - candidate.Reorder(); - } + // Decrease the key of the node in the heap, + // re-sort the heap. + candidate.Reorder(); + } } } // point-to-point } // for loop } } - NS_DEBUG_UNCOND(""); } -/* 16.1.1. Calculate nexthop from root through V (parent) to - * vertex W (destination), with given distance from root->W. - * - * This greatly simplified from quagga - */ +// Derived from quagga ospf_next_hop_calculation() +// 16.1.1. Calculate nexthop from root through V (parent) to +// vertex W (destination), with given distance from root->W. +// +// For now, this is greatly simplified from the quagga code +// int StaticRouteManager::SPFNexthopCalculation ( SPFVertex* v, @@ -339,48 +339,91 @@ StaticRouteManager::SPFNexthopCalculation ( StaticRouterLinkRecord* l, uint32_t distance) { + NS_DEBUG("StaticRouteManager::SPFNexthopCalculation ()"); if (v == m_spfroot) { // parent of w is the root itself // calculate the interfaceid of the router that corresponds - // to link l between v and w and store it in w->m_root_oif - // This root_oif is then used when installing host routes for the - // destinations covered by this vertex + // to link l between v and w and store it in w->m_rootOif + // This rootOif is then used when installing host routes for the + // destinations covered by this vertex. Store also the next hop + // IP address. // // Find the outgoing interface on v corresponding to the link l // between v and w - w->m_root_oif = FindOutgoingInterface(v,w,l); + if (w->m_vertexType == SPFVertex::VertexRouter) + { + // l is a link from v to w + // l2 will be a link from w to v + StaticRouterLinkRecord *l2 = 0; + l2 = SPFGetNextLink(w,v,l2); + w->m_nextHop = l2->m_linkData; + // Find interface corresponding to link's IP address + w->m_rootOif = FindOutgoingInterfaceId(l->m_linkData); + + NS_DEBUG("SPFNexthopCalculation: Next hop from " << + v->m_vertexId << " to " << w->m_vertexId << + " goes through next hop " << w->m_nextHop << + " via outgoing interface " << w->m_rootOif); + } } else { - // Inherit the root_oif from the current parent - w->m_root_oif = v->m_root_oif; + // Inherit the rootOif and nextHop from the current parent + w->m_rootOif = v->m_rootOif; + w->m_nextHop = v->m_nextHop; } w->m_distanceFromRoot = distance; w->m_parent = v; return 1; } +// Derived from quagga ospf_get_next_link +// Find the next link after prev_link from v to w. If prev_link is +// NULL, return the first link from v to w. Ignore stub and virtual links; +// these link types will never be returned. // -// Figure out which interface that the node represented by v will want to use -// to send packets to the node represented by w over the link represented by l -// -uint32_t -StaticRouteManager::FindOutgoingInterface ( +StaticRouterLinkRecord* +StaticRouteManager::SPFGetNextLink( SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* l + StaticRouterLinkRecord* prev_link ) { - NS_ASSERT_MSG(v == m_spfroot, - "StaticRouterManager""FindOutgoingInterface (): " - "The node of interest must be the root node"); - - // want interface that v uses to send packets - - // Using the Ipv4 public APIs of a node, find the outgoing - // interface ID corresponding to the link l between vertex v and w - // where v is the root of the tree + NS_DEBUG("StaticRouteManager::SPFGetNextLink ()"); + bool skip = true; + StaticRouterLinkRecord* l; + if (prev_link == 0) + { + skip = false; + } + + for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = + v->m_lsa->m_linkRecords.begin(); + i != v->m_lsa->m_linkRecords.end(); + i++ ) + { + l = *i; + if (l->m_linkType != StaticRouterLinkRecord::PointToPoint) + { + continue; + } + if (l->m_linkId == w->m_vertexId) { + NS_DEBUG("SPFGetNextLink: Found matching link l: linkId=" << + l->m_linkId << " linkData=" << l->m_linkData); + if (skip == false) + { + NS_DEBUG("SPFGetNextLink: Returning the found link"); + return l; + } + else + { + NS_DEBUG("SPFGetNextLink: Skipping the found link"); + skip = false; + continue; + } + } + } return 0; } @@ -396,10 +439,11 @@ StaticRouteManager::DebugSPFCalculate(Ipv4Address root) void StaticRouteManager::SPFCalculate(Ipv4Address root) { - NS_DEBUG_UNCOND("StaticRouteManager::SPFCalculate ()"); + NS_DEBUG("StaticRouteManager::SPFCalculate ()"); SPFVertex *v; + m_lsdb->Initialize (); // The candidate queue is a priority queue of SPFVertex objects, with // the top of the queue being the closest vertex in terms of @@ -415,50 +459,88 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // This vertex is the root of the SPF tree v->m_distanceFromRoot = 0; m_spfroot= v; + v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; for (;;) { // RFC2328 16.1. (2). SPFNext(v , candidate); - /* RFC2328 16.1. (3). */ - /* If at this step the candidate list is empty, the shortest- - * path tree (of transit vertices) has been completely built and - * this stage of the procedure terminates. */ + + // RFC2328 16.1. (3). + // If at this step the candidate list is empty, the shortest- + // path tree (of transit vertices) has been completely built and + // this stage of the procedure terminates. if (candidate.Size() == 0) break; - - /* Otherwise, choose the vertex belonging to the candidate list - * that is closest to the root, and add it to the shortest-path - * tree (removing it from the candidate list in the - * process). */ - /* Extract from the candidates the node with the lower key. */ - v = candidate.Pop(); - /* Update stat field in vertex. */ + // Otherwise, choose the vertex belonging to the candidate list + // that is closest to the root, and add it to the shortest-path + // tree (removing it from the candidate list in the + // process). + // Extract from the candidates the node with the lower key. + v = candidate.Top(); + candidate.Pop(); + // Update stat field in vertex. + NS_DEBUG("SPFCalculate: Popping vertex" << v->m_vertexId); v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; SPFVertexAddParent(v); - /* Note that when there is a choice of vertices closest to the - * root, network vertices must be chosen before router vertices - * in order to necessarily find all equal-cost paths. */ - /* We don't do this at this moment, we should add the treatment - * above codes. -- kunihiro. */ + // Note that when there is a choice of vertices closest to the + // root, network vertices must be chosen before router vertices + // in order to necessarily find all equal-cost paths. + // We don't do this at this moment, we should add the treatment + // above codes. -- kunihiro. - /* RFC2328 16.1. (4). */ + // RFC2328 16.1. (4). SPFIntraAddRouter (v); - /* RFC2328 16.1. (5). */ - /* Iterate the algorithm by returning to Step 2. */ + // RFC2328 16.1. (5). + // Iterate the algorithm by returning to Step 2. + } // end loop until no more candidate vertices - } /* end loop until no more candidate vertices */ + // Second stage of SPF calculation procedure's + // NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); -#ifdef NOTYET - /* Second stage of SPF calculation procedure's */ - ospf_spf_process_stubs (area, area->spf, new_table); -#endif - - delete m_spfroot; + DeleteSPFVertexChain(m_spfroot); m_spfroot = 0; } +// XXX this should probably be a method on Ipv4 +uint32_t +StaticRouteManager::FindOutgoingInterfaceId(Ipv4Address a) +{ + + Ipv4Address routerId = m_spfroot->m_vertexId; + + std::vector >::iterator i = NodeList::Begin(); + for (; i != NodeList::End(); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); + NS_ASSERT_MSG(rtr, + "StaticRouteManager::SPFIntraAddRouter (): " + "QI for interface failed"); + if (rtr->GetRouterId () == routerId) + { + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4, + "StaticRouteManager::SPFIntraAddRouter (): " + "QI for interface failed"); + for (uint32_t i = 0; i < ipv4->GetNInterfaces(); i++) + { + if (ipv4->GetAddress (i) == a) { + NS_DEBUG("FindOutgoingInterfaceId: Interface match for " << a); + return i; + } + } + } + } + return 0; +} + +// derived from quagga ospf_intra_add_router() +// +// This is where we add host routes to the routing tables void StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) { @@ -470,13 +552,6 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) // records. For each point to point record, the m_linkData // is a destination IP address to which we add a host route // - - // Therefore, this routine's logic should be: - // i) obtain the ipv4-route interface of the node corresponding - // to m_spfroot (vertex) - // i.e. Query Interface for the IPv4-route interface - // ii) for each point-to-point link in v->m_lsa - // ipv4-route::AddHostRouteTo(m_linkData, m_root_oid); NS_ASSERT_MSG(m_spfroot, "StaticRouteManager::SPFIntraAddRouter (): Root pointer not set"); @@ -496,7 +571,7 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) if (rtr->GetRouterId () == routerId) { - NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + NS_DEBUG("StaticRouteManager::SPFIntraAddRouter (): " "setting routes for node " << node->GetId ()); Ptr ipv4 = node->QueryInterface (Ipv4::iid); @@ -515,32 +590,33 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) "StaticRouteManager::SPFIntraAddRouter (): " "Expected exen number of Link Records"); - for (uint32_t j = 0; j < nLinkRecords; ++j) + for (uint32_t j = 0; j < nLinkRecords; j += 2) { - StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); - if (lr->m_linkType != StaticRouterLinkRecord::PointToPoint) - { - continue; - } -// -// BUGBUG This is not right. Need to find the next hop interface correctly -// - NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " - "BUGBUG incorrect next hope calculation"); + StaticRouterLinkRecord *lrp2p = lsa->GetLinkRecord (j); + NS_ASSERT_MSG( + lrp2p->m_linkType == StaticRouterLinkRecord::PointToPoint, + "StaticRouteManager::SPFIntraAddRouter (): " + "Expected PointToPoint Link Record"); - NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " - "Add route to " << lr->m_linkData << - " using next hop " << lr->m_linkData << - " via interface " << v->m_root_oif); + StaticRouterLinkRecord *lrstub = lsa->GetLinkRecord (j + 1); + NS_ASSERT_MSG( + lrstub->m_linkType == StaticRouterLinkRecord::StubNetwork, + "StaticRouteManager::SPFIntraAddRouter (): " + "Expected StubNetwork Link Record"); + + NS_DEBUG("StaticRouteManager::SPFIntraAddRouter (): " + "Add route to " << lrp2p->m_linkData << + " using next hop " << v->m_nextHop << + " via interface " << v->m_rootOif); - ipv4->AddHostRouteTo(lr->m_linkData, - lr->m_linkData, v->m_root_oif); + ipv4->AddHostRouteTo(lrp2p->m_linkData, v->m_nextHop, + v->m_rootOif); } - break; } } } +// Derived from quagga ospf_vertex_add_parents() // Add a vertex to the list of children in each of its parents. void StaticRouteManager::SPFVertexAddParent(SPFVertex* v) @@ -549,6 +625,15 @@ StaticRouteManager::SPFVertexAddParent(SPFVertex* v) v->m_parent->m_children.push_back(v); } +void +StaticRouteManager::DeleteSPFVertexChain(SPFVertex* spfroot) +{ + // spfroot is the root of all SPFVertex created during the SPF process + // each vertex has a list of children + // Recursively, delete all of the SPFVertex children of each SPFVertex + // then delete root itself +} + } // namespace ns3 #ifdef RUN_SELF_TESTS @@ -612,13 +697,12 @@ StaticRouteManagerTest::RunTests (void) for (int i = 0; i < 100; ++i) { - SPFVertex *v = candidate.Pop (); + SPFVertex *v = candidate.Top (); + candidate.Pop (); if (v->m_distanceFromRoot < lastDistance) { ok = false; } - delete v; - v = 0; lastDistance = v->m_distanceFromRoot; } diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index d0cb28aa7..40105d464 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -61,7 +61,9 @@ public: t_listOfSPFVertex::iterator m_SPFVertexIter; uint32_t m_distanceFromRoot; - uint32_t m_root_oif; + uint32_t m_rootOif; + Ipv4Address m_nextHop; + }; /** @@ -74,11 +76,9 @@ public: void Insert(Ipv4Address addr, StaticRouterLSA* lsa); StaticRouterLSA* GetLSA (Ipv4Address addr); /** - * \brief Set all SPFVertex to an initialized state, for SPF computation + * \brief Set all LSA flags to an initialized state, for SPF computation */ -#if 0 void Initialize (); -#endif typedef std::map LSDBMap_t; typedef std::pair LSDBPair_t; @@ -134,9 +134,10 @@ private: StaticRouterLinkRecord* l, uint32_t distance); void SPFVertexAddParent(SPFVertex* v); void DeleteSPFVertexChain(SPFVertex* spfroot); - uint32_t FindOutgoingInterface(SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* l); + StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* prev_link); void SPFIntraAddRouter(SPFVertex* v); + uint32_t FindOutgoingInterfaceId(Ipv4Address a); }; diff --git a/src/routing/static-router.h b/src/routing/static-router.h index b6331021a..4f777e484 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -184,8 +184,8 @@ public: // this is a tristate flag used internally in the SPF computation enum SPFStatus { LSA_SPF_NOT_EXPLORED = 0, - LSA_SPF_IN_SPFTREE, - LSA_SPF_CANDIDATE + LSA_SPF_CANDIDATE, + LSA_SPF_IN_SPFTREE } m_stat; }; From 420fb5f6ccfb94084b11e3c84a770de03273b54f Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 13 Jul 2007 13:46:01 -0700 Subject: [PATCH 059/278] merge probs --- src/routing/static-route-manager.cc | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 8b72927d8..e06cceeec 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -518,13 +518,13 @@ StaticRouteManager::FindOutgoingInterfaceId(Ipv4Address a) Ptr rtr = node->QueryInterface (StaticRouter::iid); NS_ASSERT_MSG(rtr, - "StaticRouteManager::SPFIntraAddRouter (): " + "StaticRouteManager::FindOutgoingInterfaceId (): " "QI for interface failed"); if (rtr->GetRouterId () == routerId) { Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4, - "StaticRouteManager::SPFIntraAddRouter (): " + "StaticRouteManager::FindOutgoingInterfaceId (): " "QI for interface failed"); for (uint32_t i = 0; i < ipv4->GetNInterfaces(); i++) { @@ -592,24 +592,21 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) for (uint32_t j = 0; j < nLinkRecords; j += 2) { - StaticRouterLinkRecord *lrp2p = lsa->GetLinkRecord (j); - NS_ASSERT_MSG( - lrp2p->m_linkType == StaticRouterLinkRecord::PointToPoint, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected PointToPoint Link Record"); + StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); + if (lr->m_linkType != StaticRouterLinkRecord::PointToPoint) + { + continue; + } - StaticRouterLinkRecord *lrstub = lsa->GetLinkRecord (j + 1); - NS_ASSERT_MSG( - lrstub->m_linkType == StaticRouterLinkRecord::StubNetwork, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected StubNetwork Link Record"); - - NS_DEBUG("StaticRouteManager::SPFIntraAddRouter (): " - "Add route to " << lrp2p->m_linkData << + NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + "BUGBUG incorrect next hope calculation"); + + NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + "Add route to " << lr->m_linkData << " using next hop " << v->m_nextHop << " via interface " << v->m_rootOif); - ipv4->AddHostRouteTo(lrp2p->m_linkData, v->m_nextHop, + ipv4->AddHostRouteTo(lr->m_linkData, v->m_nextHop, v->m_rootOif); } } From e1c4bbed1d6ba78cf58295b556e2c7f054858bbc Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 13 Jul 2007 13:49:10 -0700 Subject: [PATCH 060/278] remove debug prints --- src/routing/static-route-manager.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index e06cceeec..4eb432a09 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -598,10 +598,7 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) continue; } - NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " - "BUGBUG incorrect next hope calculation"); - - NS_DEBUG_UNCOND("StaticRouteManager::SPFIntraAddRouter (): " + NS_DEBUG("StaticRouteManager::SPFIntraAddRouter (): " "Add route to " << lr->m_linkData << " using next hop " << v->m_nextHop << " via interface " << v->m_rootOif); From 65faee4e7be298ae29d6cc8aae4b8900f7d1d16f Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 13 Jul 2007 14:05:12 -0700 Subject: [PATCH 061/278] fix merge problem that lost candidate queue changes --- src/routing/static-route-manager.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 4eb432a09..3e8e43fd7 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -477,8 +477,7 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // tree (removing it from the candidate list in the // process). // Extract from the candidates the node with the lower key. - v = candidate.Top(); - candidate.Pop(); + v = candidate.Pop(); // Update stat field in vertex. NS_DEBUG("SPFCalculate: Popping vertex" << v->m_vertexId); v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; @@ -691,13 +690,14 @@ StaticRouteManagerTest::RunTests (void) for (int i = 0; i < 100; ++i) { - SPFVertex *v = candidate.Top (); - candidate.Pop (); + SPFVertex *v = candidate.Pop (); if (v->m_distanceFromRoot < lastDistance) { ok = false; } lastDistance = v->m_distanceFromRoot; + delete v; + v = 0; } // Build fake link state database; four routers (0-3), 3 point-to-point From 57b34480191abedb4b8e7a7ba998d8c30c4abc6c Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 13 Jul 2007 14:21:44 -0700 Subject: [PATCH 062/278] Check for static routing flag before instantiating a StaticRouteManager --- examples/simple-static-routing.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 71fc00044..55200e7af 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -140,12 +140,12 @@ int main (int argc, char *argv[]) channel2, n2, Ipv4Address("10.1.3.1"), n3, Ipv4Address("10.1.3.2")); - // Here, we will use the StaticRoutingManager to build routes - Ptr routeManager = Create (); - // The below functions might better be placed in some kind of - // Simulator::Initialization function (for further study) - routeManager->BuildStaticRoutingDatabase (); - routeManager->InitializeRoutes (); + if (RoutingEnvironment::StaticRoutingEnabled()) + { + Ptr routeManager = Create (); + routeManager->BuildStaticRoutingDatabase (); + routeManager->InitializeRoutes (); + } // Create the OnOff application to send UDP datagrams of size // 210 bytes at a rate of 448 Kb/s From 2065013a0434ceca85b66dda9181199d5dd4af77 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 13 Jul 2007 14:22:40 -0700 Subject: [PATCH 063/278] Small readme for the routing --- README.routing | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 README.routing diff --git a/README.routing b/README.routing new file mode 100644 index 000000000..7b5166f5c --- /dev/null +++ b/README.routing @@ -0,0 +1,93 @@ +Routing overview, mid-July + +This is a proposal to add global static routing to ns-3 + +The previously announced roadmap: +* July 15: Support IPv4 static routing with PointToPoint numbered links +* August 15: Extend IPv4 static routing to Ethernet (shared links), add static multicast forwarding over Ethernet and PointToPoint +* Sept 15: Add static multicast forwarding over wireless interface + +This would provide the first bullet above. + +Note: This is orthogonal to Gustavo's OLSR code, but could also exist +as a static routing protocol in the framework that he proposes; right now, +this just writes directly into the existing Ipv4 routing API + +1. Code: + +- source code is in a routing module src/routing/ +- an example script is in examples/simple-static-routing.cc +- StaticRouteManager is added in the run-tests unit tests + +2. Approach + +Static routing is used to automatically populate the forwarding tables +in a topology without running a dynamic routing protocol or asking +the user to manually enter routes themselves. + +A single object (StaticRouteManager) is responsible for populating +the static routes on each node, using the public Ipv4 API of that node. +It queries each node in the topology for a "staticRouter" interface. +If found, it uses the API of that interface to obtain a "link state +advertisement (LSA)" for the router. Link State Advertisements +are used in OSPF routing, and we follow their formatting. + +The StaticRouteManager populates a link state database with LSAs +gathered from the entire topology. Then, for each router in the topology, +the StaticRouteManager executes the OSPF shortest path first (SPF) +computation on the database, and populates the routing tables on each +node. + +This computation is initiated during the pre-simulation phase (after +topology and IP addressing has been done) with the following lines of code, +presently: + Ptr routeManager = Create (); + routeManager->BuildStaticRoutingDatabase (); + routeManager->InitializeRoutes (); + +The quagga (http://www.quagga.net) OSPF implementation was used as the +basis for the routing computation logic. +One benefit of following an existing OSPF SPF implementation is that +OSPF already has defined link state advertisements for all common +types of network links: +- point-to-point (serial links) +- point-to-multipoint (Frame Relay, ad hoc wireless) +- non-broadcast multiple access (ATM) +- broadcast (Ethernet) +Therefore, we think that enabling these other link types will be more +straightforward now that the underlying OSPF SPF framework is in place. + +Presently, we can handle IPv4 point-to-point, numbered links, and we do +not do equal-cost multipath. + +3. Bootstrapping + +Static routing can be enabled using a DoStaticRouting flag in the +default value system: + Bind ("DoStaticRouting", "true"); +This bind tells the system to use global static routing. It results in +a StaticRouter interface being aggregated to the internet nodes and the +creation of a Route Manager component to oversee the route generation. + +If this flag is true, when an InternetNode is created, it will aggregate +a routing interface to it. + if (RoutingEnvironment::StaticRoutingEnabled()) + { + Ptr staticRouter = Create (this); + Object::AddInterface (staticRouter); + } +this flag is also tested before creating a StaticRouteManager object. + +4. Some open issues + +- how transparent vs. explicit the enabling of static routing should be +(e.g., if we have a higher layer Inversion-of-Control framework, do these +static routing functions exist in some kind of Init() or Presimulate() +method?) +- whether to add some kind of flag in an InternetNode that is equivalent +to /proc/sys/net/ipv4/ip_forward , so that every InternetNode is not +necessarily a router. +- whether to continue to write to the existing IPv4 API or load a static +router component into the node like Gustavo's OLSR +- whether to make a single global forwarding table instead of distributing +it among all the routers From 2f2b10d22b1413ea69bccd55f3f3039d4cc914f4 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 13 Jul 2007 14:35:24 -0700 Subject: [PATCH 064/278] remove inappropriate assertions that popped when routing disabled --- src/routing/static-route-manager.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 3e8e43fd7..3c37389cf 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -145,7 +145,11 @@ StaticRouteManager::BuildStaticRoutingDatabase () Ptr rtr = node->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG(rtr, "QI for interface failed"); + + if (!rtr) + { + continue; + } // You must call DiscoverLSAs () before trying to use any // routing info or to update LSAs. Subsequently you may use @@ -208,7 +212,7 @@ StaticRouteManager::InitializeRoutes () Ptr rtr = node->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG(rtr, "QI for interface failed"); + if (rtr && rtr->GetNumLSAs () ) { SPFCalculate(rtr->GetRouterId ()); From 2684031ff2824a6dc4cb57c4762141a07eccb774 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 15 Jul 2007 22:47:58 -0700 Subject: [PATCH 065/278] Fix SPFVertex destructor; make unit tests succeed again --- src/routing/static-route-manager.cc | 28 ++++++++++++++-------------- src/routing/static-route-manager.h | 1 - 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 3c37389cf..62dfc5136 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -56,6 +56,16 @@ SPFVertex::SPFVertex (StaticRouterLSA* lsa) : SPFVertex::~SPFVertex () { + for ( t_listOfSPFVertex::iterator i = m_children.begin (); + i != m_children.end (); + i++) + { + SPFVertex *p = *i; + delete p; + p = 0; + *i = 0; + } + m_children.clear(); } StaticRouteManagerLSDB::~StaticRouteManagerLSDB() @@ -502,7 +512,7 @@ StaticRouteManager::SPFCalculate(Ipv4Address root) // Second stage of SPF calculation procedure's // NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); - DeleteSPFVertexChain(m_spfroot); + delete m_spfroot; m_spfroot = 0; } @@ -622,15 +632,6 @@ StaticRouteManager::SPFVertexAddParent(SPFVertex* v) v->m_parent->m_children.push_back(v); } -void -StaticRouteManager::DeleteSPFVertexChain(SPFVertex* spfroot) -{ - // spfroot is the root of all SPFVertex created during the SPF process - // each vertex has a list of children - // Recursively, delete all of the SPFVertex children of each SPFVertex - // then delete root itself -} - } // namespace ns3 #ifdef RUN_SELF_TESTS @@ -819,12 +820,11 @@ StaticRouteManagerTest::RunTests (void) srmlsdb->Insert(lsa3->m_linkStateId, lsa3); NS_ASSERT(lsa2 == srmlsdb->GetLSA(lsa2->m_linkStateId)); - // We need a dummy node to populate the routing tables - Ptr n2 = Create (); - // XXX next, calculate routes based on the manually created LSDB StaticRouteManager* srm = new StaticRouteManager(); - srm->DebugUseLsdb (srmlsdb); + srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB + // Note-- this will succeed without any nodes in the topology + // because the NodeList is empty srm->DebugSPFCalculate(lsa0->m_linkStateId); // node n0 // This delete clears the srm, which deletes the LSDB, which clears diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 40105d464..2f47d0b40 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -133,7 +133,6 @@ private: int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, StaticRouterLinkRecord* l, uint32_t distance); void SPFVertexAddParent(SPFVertex* v); - void DeleteSPFVertexChain(SPFVertex* spfroot); StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, StaticRouterLinkRecord* prev_link); void SPFIntraAddRouter(SPFVertex* v); From 510d2346118f24d6d98089ccee7b00a528389204 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 16 Jul 2007 16:59:23 -0700 Subject: [PATCH 066/278] checkpoint --- src/routing/static-route-manager.cc | 307 +++++++++++++++++++--------- 1 file changed, 210 insertions(+), 97 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 62dfc5136..322548faf 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -53,7 +53,6 @@ SPFVertex::SPFVertex (StaticRouterLSA* lsa) : { } - SPFVertex::~SPFVertex () { for ( t_listOfSPFVertex::iterator i = m_children.begin (); @@ -129,7 +128,9 @@ StaticRouteManager::~StaticRouteManager () NS_DEBUG("StaticRouteManager::~StaticRouteManager ()"); if (m_lsdb) - delete m_lsdb; + { + delete m_lsdb; + } } void @@ -140,14 +141,22 @@ StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) m_lsdb = lsdb; } +// +// In order to build the routing database, we need to walk the list of nodes +// in the system and look for those that support the StaticRouter interface. +// These routers will export a number of Link State Advertisements (LSAs) +// that describe the links and networks that are "adjacent" (i.e., that are +// on the other side of a point-to-point link). We take these LSAs and put +// add them to the Link State DataBase (LSDB) from which the routes will +// ultimately be computed. +// void StaticRouteManager::BuildStaticRoutingDatabase () { NS_DEBUG("StaticRouteManager::BuildStaticRoutingDatabase()"); - - // Walk the list of nodes. QI for StaticRouter interface. - // if node has a StaticRouter interface, grab the LSAs - // from it and stick them in the LSDB +// +// Walk the list of nodes looking for the StaticRouter Interface. +// typedef std::vector < Ptr >::iterator Iterator; for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) { @@ -155,74 +164,96 @@ StaticRouteManager::BuildStaticRoutingDatabase () Ptr rtr = node->QueryInterface (StaticRouter::iid); - +// +// Ignore nodes that aren't participating in routing. +// if (!rtr) { continue; } - - // You must call DiscoverLSAs () before trying to use any - // routing info or to update LSAs. Subsequently you may use - // GetNumLSAs(). If you call GetNumLSAs () before calling - // DiscoverLSAs () will get zero as the number. +// +// You must call DiscoverLSAs () before trying to use any routing info or to +// update LSAs. DiscoverLSAs () drives the process of discovering routes in +// the StaticRouter. Afterward, you may use GetNumLSAs (), which is a very +// computationally inexpensive call. If you call GetNumLSAs () before calling +// DiscoverLSAs () will get zero as the number since no routes have been +// found. +// uint32_t numLSAs = rtr->DiscoverLSAs(); NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); for (uint32_t j = 0; j < numLSAs; ++j) { StaticRouterLSA* lsa = new StaticRouterLSA (); +// +// This is the call to actually fetch a Link State Advertisement from the +// router. +// rtr->GetLSA(j, *lsa); NS_DEBUG ("LSA " << j); - NS_DEBUG ("----------------------------"); NS_DEBUG (*lsa); +// +// Write the newly discovered link state advertisement to the database. +// m_lsdb->Insert (lsa->m_linkStateId, lsa); } } } -// For each node that is a static router (which can be determined by -// the presence of StaticRouter interface), run Dijkstra SPF calculation -// on the database rooted at that router, and populate the node -// forwarding tables +// +// For each node that is a static router (which is determined by the presence +// of an aggregated StaticRouter interface), run the Dijkstra SPF calculation +// on the database rooted at that router, and populate the node forwarding +// tables. +// +// This function parallels RFC2328, Section 16.1.1, and quagga ospfd +// +// This calculation yields the set of intra-area routes associated +// with an area (called hereafter Area A). A router calculates the +// shortest-path tree using itself as the root. The formation +// of the shortest path tree is done here in two stages. In the +// first stage, only links between routers and transit networks are +// considered. Using the Dijkstra algorithm, a tree is formed from +// this subset of the link state database. In the second stage, +// leaves are added to the tree by considering the links to stub +// networks. +// +// The area's link state database is represented as a directed graph. +// The graph's vertices are routers, transit networks and stub networks. +// +// The first stage of the procedure (i.e., the Dijkstra algorithm) +// can now be summarized as follows. At each iteration of the +// algorithm, there is a list of candidate vertices. Paths from +// the root to these vertices have been found, but not necessarily +// the shortest ones. However, the paths to the candidate vertex +// that is closest to the root are guaranteed to be shortest; this +// vertex is added to the shortest-path tree, removed from the +// candidate list, and its adjacent vertices are examined for +// possible addition to/modification of the candidate list. The +// algorithm then iterates again. It terminates when the candidate +// list becomes empty. +// void StaticRouteManager::InitializeRoutes () { NS_DEBUG("StaticRouteManager::InitializeRoutes ()"); - // This function parallels RFC2328, Section 16.1.1, and quagga ospfd - // - // This calculation yields the set of intra-area routes associated - // with an area (called hereafter Area A). A router calculates the - // shortest-path tree using itself as the root. The formation - // of the shortest path tree is done here in two stages. In the - // first stage, only links between routers and transit networks are - // considered. Using the Dijkstra algorithm, a tree is formed from - // this subset of the link state database. In the second stage, - // leaves are added to the tree by considering the links to stub - // networks. - - // The area's link state database is represented as a directed graph. - // The graph's vertices are routers, transit networks and stub networks. - // The first stage of the procedure (i.e., the Dijkstra algorithm) - // can now be summarized as follows. At each iteration of the - // algorithm, there is a list of candidate vertices. Paths from - // the root to these vertices have been found, but not necessarily - // the shortest ones. However, the paths to the candidate vertex - // that is closest to the root are guaranteed to be shortest; this - // vertex is added to the shortest-path tree, removed from the - // candidate list, and its adjacent vertices are examined for - // possible addition to/modification of the candidate list. The - // algorithm then iterates again. It terminates when the candidate - // list becomes empty. - - // Iterate for each node that is a router in the topology +// +// Walk the list of nodes in the system. +// typedef std::vector < Ptr >::iterator Iterator; for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) { Ptr node = *i; - +// +// Look for the StaticRouter interface that indicates that the node is +// participating in routing. +// Ptr rtr = node->QueryInterface (StaticRouter::iid); - +// +// if the node has a static router interface, then run the static routing +// algorithms. +// if (rtr && rtr->GetNumLSAs () ) { SPFCalculate(rtr->GetRouterId ()); @@ -230,12 +261,19 @@ StaticRouteManager::InitializeRoutes () } } - -// Derived from quagga ospf_spf_next() -// RFC2328 Section 16.1 (2). -// v is on the SPF tree. Examine the links in v's LSA. Update the list -// of candidates with any vertices not already on the list. If a lower-cost -// path is found to a vertex already on the candidate list, store the new cost. +// +// This method is derived from quagga ospf_spf_next(). See RFC2328 Section +// 16.1 (2) for further details. +// +// We're passed a parameter that is a vertex which is already in the SPF +// tree. A vertex represents a router node. We also get a reference to the +// SPF candidate queue, which is a priority queue containing the shortest paths +// to the networks we know about. +// +// We examine the links in v's LSA and update the listof candidates with any +// vertices not already on the list. If a lower-cost path is found to a +// vertex already on the candidate list, store the new (lower) cost. +// void StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) { @@ -246,20 +284,27 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) NS_DEBUG("StaticRouteManager::SPFNext ()"); if (v->m_vertexType == SPFVertex::VertexRouter) { - // Always true for now, since all our LSAs are RouterLSAs +// +// Always true for now, since all our LSAs are RouterLSAs. +// if (true) { NS_DEBUG ("SPFNext: Examining " << v->m_vertexId << "'s " << v->m_lsa->m_linkRecords.size() << " link records"); +// +// Walk the list of link records in the link state advertisemnt associated with +// the "current" router (represented by vertex ). +// for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = v->m_lsa->m_linkRecords.begin(); i != v->m_lsa->m_linkRecords.end(); i++ ) { - // (a) If this is a link to a stub network, examine the next - // link in V's LSA. Links to stub networks will be - // considered in the second stage of the shortest path - // calculation. +// +// (a) If this is a link to a stub network, examine the next link in V's LSA. +// Links to stub networks will be considered in the second stage of the +// shortest path calculation. +// StaticRouterLinkRecord* l = *i; if (l->m_linkType == StaticRouterLinkRecord::StubNetwork) { @@ -267,41 +312,67 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) << l->m_linkId); continue; } - // (b) Otherwise, W is a transit vertex (router or transit - // network). Look up the vertex W's LSA (router-LSA or - // network-LSA) in Area A's link state database. +// +// (b) Otherwise, W is a transit vertex (router or transit network). Look up +// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state +// database. +// if (l->m_linkType == StaticRouterLinkRecord::PointToPoint) { - // Lookup the vertex W's LSA +// +// Lookup the link state advertisement of the new link -- we call it in +// the link state database. +// w_lsa = m_lsdb->GetLSA(l->m_linkId); NS_ASSERT(w_lsa); NS_DEBUG("SPFNext: Found a P2P record from " << v->m_vertexId << " to " << w_lsa->m_linkStateId); - // (c) If vertex W is already on the shortest-path tree, - // examine the next link in the LSA. +// +// (c) If vertex W is already on the shortest-path tree, examine the next +// link in the LSA. +// +// If the link is to a router that is already in the shortest path first tree +// then we have it covered -- ignore it. +// if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_IN_SPFTREE) { NS_DEBUG("SPFNext: Skipping-> LSA "<< w_lsa->m_linkStateId << " already in SPF tree"); continue; } - // (d) Calculate the link state cost D of the resulting path - // from the root to vertex W. D is equal to the sum of - // the link state cost of the (already calculated) - // shortest path to vertex V and the advertised cost of - // the link between vertices V and W. +// +// The link is to a router we haven't dealt with yet. +// +// (d) Calculate the link state cost D of the resulting path from the root to +// vertex W. D is equal to the sum of the link state cost of the (already +// calculated) shortest path to vertex V and the advertised cost of the link +// between vertices V and W. +// distance = v->m_distanceFromRoot + l->m_metric; NS_DEBUG("SPFNext: Considering w_lsa " << w_lsa->m_linkStateId); - // Here, W is either already in candidate list or not + if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { +// +// If we havent yet considered the link represented by we have to create +// a new SPFVertex to represent it. +// w = new SPFVertex(w_lsa); - // Calculate nexthop to W +// +// We need to figure out how to actually get to the new router represented +// by . This will (among other things0 find the next hop address to send +// packets destined fo this network to, and also find the outbound interface +// used to forward the packets. +// if (SPFNexthopCalculation(v, w, l, distance)) { w_lsa->m_stat = StaticRouterLSA::LSA_SPF_CANDIDATE; +// +// Push this new vertex onto the priority queue (ordered by distance from the +// root node). +// candidate.Push(w); NS_DEBUG("SPFNext: Pushing " << w->m_vertexId << ", parent vertexId: " << v->m_vertexId); @@ -310,39 +381,58 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) } else if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_CANDIDATE) { - //Get the vertex from candidates +// +// We have already considered the link represented by . What wse have to +// do now is to decide if this new router represents a route with a shorter +// distance metric. +// +// So, locate the vertex in the candidate queue and take a look at the +// distance. w = candidate.Find(w_lsa->m_linkStateId); if (w->m_distanceFromRoot < distance) { - continue; // not a shorter path +// +// This is not a shorter path, so don't do anything. +// + continue; } - // equal to else if (w->m_distanceFromRoot == distance) { - // Do nothing-- not doing equal-cost multipath +// +// This path is one with an equal cost. Do nothing for now -- we're not doing +// equal-cost multipath cases yet. +// } else { - // Found a lower-cost path to W. - // nexthop_calculation is conditional, if it finds - // valid nexthop it will call spf_add_parents, which - // will flush the old parents +// +// this path represents a new, lower-cost path to (the vertex we found in +// the current link record of the link state advertisement of the current root +// (vertex ) +// +// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop +// it will call spf_add_parents, which will flush the old parents +// if (SPFNexthopCalculation(v, w, l, distance)) { - // Decrease the key of the node in the heap, - // re-sort the heap. +// +// If we've changed the cost to get to the vertex represented by , we +// must reorder the priority queue keyed to that cost. +// candidate.Reorder(); } - } + } } // point-to-point } // for loop } } } -// Derived from quagga ospf_next_hop_calculation() -// 16.1.1. Calculate nexthop from root through V (parent) to -// vertex W (destination), with given distance from root->W. +// +// This method is derived from quagga ospf_next_hop_calculation() 16.1.1. +// +// Calculate the nexthop from the root through V (parent) to vertex W +// (destination), with given distance from root->W. // // For now, this is greatly simplified from the quagga code // @@ -354,25 +444,42 @@ StaticRouteManager::SPFNexthopCalculation ( uint32_t distance) { NS_DEBUG("StaticRouteManager::SPFNexthopCalculation ()"); +// +// If we're calculating the next hop information from a node (v) that is the +// root, then we need to store the information needed to forward to the +// given network (w). We need to know the interface ID to use to forward the +// packets, and we need to know the IP address of the router to which we need +// to send the packets (the next hop address). +// if (v == m_spfroot) { - // parent of w is the root itself - // calculate the interfaceid of the router that corresponds - // to link l between v and w and store it in w->m_rootOif - // This rootOif is then used when installing host routes for the - // destinations covered by this vertex. Store also the next hop - // IP address. - // - // Find the outgoing interface on v corresponding to the link l - // between v and w +// +// We're going from the root to a vertex representing a router ... +// if (w->m_vertexType == SPFVertex::VertexRouter) { - // l is a link from v to w - // l2 will be a link from w to v +// +// We need to find both sides of the link we're examining. We are considering +// a link "from" vertex v "to" vertex w over the link represented by the link +// record l. We have the information from the perspective of v, now we need +// to get the information from the perspective of w, specifically the point +// to point link record describing the link from w to v. +// StaticRouterLinkRecord *l2 = 0; l2 = SPFGetNextLink(w,v,l2); +// +// At this point, is the link record from to ; and is the +// link record from to . The next hop address of the destination is +// the link data field of the static router link record (which is the local IP +// address in the case of a point-to-point link). This means that in order to +// get to the network w, you send packets to the other side of the point-to- +// point link -- the router on that network. +// w->m_nextHop = l2->m_linkData; - // Find interface corresponding to link's IP address +// +// Now find the interface corresponding to the point to point link's IP +// address. +// w->m_rootOif = FindOutgoingInterfaceId(l->m_linkData); NS_DEBUG("SPFNexthopCalculation: Next hop from " << @@ -383,10 +490,16 @@ StaticRouteManager::SPFNexthopCalculation ( } else { - // Inherit the rootOif and nextHop from the current parent +// +// If we're calculating the next hop information from a node (v) that is +// *not* the root, then we need to "inherit" the information needed to +// forward from the parent (who will have inherited, ultimately, from the +// root. +// w->m_rootOif = v->m_rootOif; w->m_nextHop = v->m_nextHop; } + w->m_distanceFromRoot = distance; w->m_parent = v; return 1; From 04e59f26b9efb04571da7e670e52acae79d99134 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 17 Jul 2007 12:17:17 -0700 Subject: [PATCH 067/278] checkpoint documentation --- src/routing/static-route-manager.cc | 679 +++++++++++++++++----------- 1 file changed, 405 insertions(+), 274 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 322548faf..508f53831 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -13,6 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include #include #include @@ -30,26 +31,26 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); namespace ns3 { SPFVertex::SPFVertex () : - m_vertexType(VertexUnknown), - m_vertexId("255.255.255.255"), - m_lsa(0), - m_parent(0), - m_children(), - m_distanceFromRoot(SPF_INFINITY), - m_rootOif(SPF_INFINITY), - m_nextHop("0.0.0.0") + m_vertexType (VertexUnknown), + m_vertexId ("255.255.255.255"), + m_lsa (0), + m_parent (0), + m_children (), + m_distanceFromRoot (SPF_INFINITY), + m_rootOif (SPF_INFINITY), + m_nextHop ("0.0.0.0") { } SPFVertex::SPFVertex (StaticRouterLSA* lsa) : - m_vertexType(VertexRouter), - m_vertexId(lsa->m_linkStateId), - m_lsa(lsa), - m_parent(0), - m_children(), - m_distanceFromRoot(SPF_INFINITY), - m_rootOif(SPF_INFINITY), - m_nextHop("0.0.0.0") + m_vertexType (VertexRouter), + m_vertexId (lsa->m_linkStateId), + m_lsa (lsa), + m_parent (0), + m_children (), + m_distanceFromRoot (SPF_INFINITY), + m_rootOif (SPF_INFINITY), + m_nextHop ("0.0.0.0") { } @@ -64,31 +65,31 @@ SPFVertex::~SPFVertex () p = 0; *i = 0; } - m_children.clear(); + m_children.clear (); } -StaticRouteManagerLSDB::~StaticRouteManagerLSDB() +StaticRouteManagerLSDB::~StaticRouteManagerLSDB () { - NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); LSDBMap_t::iterator i; - for (i= m_database.begin(); i!= m_database.end(); i++) + for (i= m_database.begin (); i!= m_database.end (); i++) { - NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB():free LSA"); + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ():free LSA"); StaticRouterLSA* temp = i->second; delete temp; } - NS_DEBUG("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); - m_database.clear(); + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); + m_database.clear (); } void -StaticRouteManagerLSDB::Initialize() +StaticRouteManagerLSDB::Initialize () { - NS_DEBUG("StaticRouteManagerLSDB::Initialize ()"); + NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); LSDBMap_t::iterator i; - for (i= m_database.begin(); i!= m_database.end(); i++) + for (i= m_database.begin (); i!= m_database.end (); i++) { StaticRouterLSA* temp = i->second; temp->m_stat = StaticRouterLSA::LSA_SPF_NOT_EXPLORED; @@ -96,19 +97,19 @@ StaticRouteManagerLSDB::Initialize() } void -StaticRouteManagerLSDB::Insert(Ipv4Address addr, StaticRouterLSA* lsa) +StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) { - NS_DEBUG("StaticRouteManagerLSDB::Insert ()"); - m_database.insert(LSDBPair_t(addr, lsa)); + NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); + m_database.insert (LSDBPair_t (addr, lsa)); } StaticRouterLSA* StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) { - NS_DEBUG("StaticRouteManagerLSDB::GetLSA ()"); + NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); // Look up an LSA by its address LSDBMap_t::iterator i; - for (i= m_database.begin(); i!= m_database.end(); i++) + for (i= m_database.begin (); i!= m_database.end (); i++) { if (i->first == addr) { @@ -118,14 +119,14 @@ StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) return 0; } -StaticRouteManager::StaticRouteManager () : m_spfroot(0) +StaticRouteManager::StaticRouteManager () : m_spfroot (0) { m_lsdb = new StaticRouteManagerLSDB (); } StaticRouteManager::~StaticRouteManager () { - NS_DEBUG("StaticRouteManager::~StaticRouteManager ()"); + NS_DEBUG ("StaticRouteManager::~StaticRouteManager ()"); if (m_lsdb) { @@ -153,12 +154,12 @@ StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) void StaticRouteManager::BuildStaticRoutingDatabase () { - NS_DEBUG("StaticRouteManager::BuildStaticRoutingDatabase()"); + NS_DEBUG ("StaticRouteManager::BuildStaticRoutingDatabase()"); // // Walk the list of nodes looking for the StaticRouter Interface. // typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) { Ptr node = *i; @@ -179,7 +180,7 @@ StaticRouteManager::BuildStaticRoutingDatabase () // DiscoverLSAs () will get zero as the number since no routes have been // found. // - uint32_t numLSAs = rtr->DiscoverLSAs(); + uint32_t numLSAs = rtr->DiscoverLSAs (); NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); for (uint32_t j = 0; j < numLSAs; ++j) @@ -189,7 +190,7 @@ StaticRouteManager::BuildStaticRoutingDatabase () // This is the call to actually fetch a Link State Advertisement from the // router. // - rtr->GetLSA(j, *lsa); + rtr->GetLSA (j, *lsa); NS_DEBUG ("LSA " << j); NS_DEBUG (*lsa); // @@ -236,12 +237,12 @@ StaticRouteManager::BuildStaticRoutingDatabase () void StaticRouteManager::InitializeRoutes () { - NS_DEBUG("StaticRouteManager::InitializeRoutes ()"); + NS_DEBUG ("StaticRouteManager::InitializeRoutes ()"); // // Walk the list of nodes in the system. // typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin(); i != NodeList::End(); i++) + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) { Ptr node = *i; // @@ -256,13 +257,13 @@ StaticRouteManager::InitializeRoutes () // if (rtr && rtr->GetNumLSAs () ) { - SPFCalculate(rtr->GetRouterId ()); + SPFCalculate (rtr->GetRouterId ()); } } } // -// This method is derived from quagga ospf_spf_next(). See RFC2328 Section +// This method is derived from quagga ospf_spf_next (). See RFC2328 Section // 16.1 (2) for further details. // // We're passed a parameter that is a vertex which is already in the SPF @@ -270,35 +271,35 @@ StaticRouteManager::InitializeRoutes () // SPF candidate queue, which is a priority queue containing the shortest paths // to the networks we know about. // -// We examine the links in v's LSA and update the listof candidates with any +// We examine the links in v's LSA and update the list of candidates with any // vertices not already on the list. If a lower-cost path is found to a // vertex already on the candidate list, store the new (lower) cost. // void -StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) +StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) { SPFVertex* w = 0; StaticRouterLSA* w_lsa = 0; uint32_t distance = 0; - NS_DEBUG("StaticRouteManager::SPFNext ()"); - if (v->m_vertexType == SPFVertex::VertexRouter) - { + NS_DEBUG ("StaticRouteManager::SPFNext ()"); // // Always true for now, since all our LSAs are RouterLSAs. // + if (v->m_vertexType == SPFVertex::VertexRouter) + { if (true) { NS_DEBUG ("SPFNext: Examining " << v->m_vertexId << "'s " << - v->m_lsa->m_linkRecords.size() << " link records"); + v->m_lsa->m_linkRecords.size () << " link records"); // -// Walk the list of link records in the link state advertisemnt associated with -// the "current" router (represented by vertex ). +// Walk the list of link records in the link state advertisement associated +// with the "current" router (represented by vertex ). // - for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = - v->m_lsa->m_linkRecords.begin(); - i != v->m_lsa->m_linkRecords.end(); - i++ ) + for (StaticRouterLSA::ListOfLinkRecords_t::iterator i = + v->m_lsa->m_linkRecords.begin (); + i != v->m_lsa->m_linkRecords.end (); + i++) { // // (a) If this is a link to a stub network, examine the next link in V's LSA. @@ -308,7 +309,7 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) StaticRouterLinkRecord* l = *i; if (l->m_linkType == StaticRouterLinkRecord::StubNetwork) { - NS_DEBUG("SPFNext: Found a Stub record to " + NS_DEBUG ("SPFNext: Found a Stub record to " << l->m_linkId); continue; } @@ -323,9 +324,9 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // Lookup the link state advertisement of the new link -- we call it in // the link state database. // - w_lsa = m_lsdb->GetLSA(l->m_linkId); - NS_ASSERT(w_lsa); - NS_DEBUG("SPFNext: Found a P2P record from " << + w_lsa = m_lsdb->GetLSA (l->m_linkId); + NS_ASSERT (w_lsa); + NS_DEBUG ("SPFNext: Found a P2P record from " << v->m_vertexId << " to " << w_lsa->m_linkStateId); // // (c) If vertex W is already on the shortest-path tree, examine the next @@ -336,7 +337,7 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_IN_SPFTREE) { - NS_DEBUG("SPFNext: Skipping-> LSA "<< + NS_DEBUG ("SPFNext: Skipping-> LSA "<< w_lsa->m_linkStateId << " already in SPF tree"); continue; } @@ -350,7 +351,7 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // distance = v->m_distanceFromRoot + l->m_metric; - NS_DEBUG("SPFNext: Considering w_lsa " << + NS_DEBUG ("SPFNext: Considering w_lsa " << w_lsa->m_linkStateId); if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_NOT_EXPLORED) @@ -359,22 +360,22 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // If we havent yet considered the link represented by we have to create // a new SPFVertex to represent it. // - w = new SPFVertex(w_lsa); + w = new SPFVertex (w_lsa); // // We need to figure out how to actually get to the new router represented -// by . This will (among other things0 find the next hop address to send -// packets destined fo this network to, and also find the outbound interface +// by . This will (among other things) find the next hop address to send +// packets destined for this network to, and also find the outbound interface // used to forward the packets. // - if (SPFNexthopCalculation(v, w, l, distance)) + if (SPFNexthopCalculation (v, w, l, distance)) { w_lsa->m_stat = StaticRouterLSA::LSA_SPF_CANDIDATE; // // Push this new vertex onto the priority queue (ordered by distance from the // root node). // - candidate.Push(w); - NS_DEBUG("SPFNext: Pushing " << w->m_vertexId + candidate.Push (w); + NS_DEBUG ("SPFNext: Pushing " << w->m_vertexId << ", parent vertexId: " << v->m_vertexId); } } @@ -388,7 +389,7 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // // So, locate the vertex in the candidate queue and take a look at the // distance. - w = candidate.Find(w_lsa->m_linkStateId); + w = candidate.Find (w_lsa->m_linkStateId); if (w->m_distanceFromRoot < distance) { // @@ -413,26 +414,27 @@ StaticRouteManager::SPFNext(SPFVertex* v, CandidateQueue& candidate) // N.B. the nexthop_calculation is conditional, if it finds a valid nexthop // it will call spf_add_parents, which will flush the old parents // - if (SPFNexthopCalculation(v, w, l, distance)) + if (SPFNexthopCalculation (v, w, l, distance)) { // // If we've changed the cost to get to the vertex represented by , we // must reorder the priority queue keyed to that cost. // - candidate.Reorder(); + candidate.Reorder (); } } - } // point-to-point + } // point-to-point } // for loop } - } + } } // // This method is derived from quagga ospf_next_hop_calculation() 16.1.1. // -// Calculate the nexthop from the root through V (parent) to vertex W -// (destination), with given distance from root->W. +// Calculate the next hop IP address and the outgoing interface required to +// get packets from the root through (parent) to vertex (destination), +// over a given distance. // // For now, this is greatly simplified from the quagga code // @@ -443,46 +445,73 @@ StaticRouteManager::SPFNexthopCalculation ( StaticRouterLinkRecord* l, uint32_t distance) { - NS_DEBUG("StaticRouteManager::SPFNexthopCalculation ()"); + NS_DEBUG ("StaticRouteManager::SPFNexthopCalculation ()"); // -// If we're calculating the next hop information from a node (v) that is the -// root, then we need to store the information needed to forward to the -// given network (w). We need to know the interface ID to use to forward the -// packets, and we need to know the IP address of the router to which we need -// to send the packets (the next hop address). +// The vertex m_spfroot is a distinguished vertex representing the node at +// the root of the calculations. That is, it is the node for which we are +// calculating the routes. +// +// There are two distinct cases for calculating the next hop information. +// First, if we're considering a hop from the root to an "adjacent" network +// (one that is on the other side of a point-to-point link connected to the +// root), then we need to store the information needed to forward down that +// link. The second case is if the network is not directly adjacent. In that +// case we need to use the forwarding information from the vertex on the path +// to the destination that is directly adjacent [node 1] in both cases of the +// diagram below. +// +// (1) [root] -> [point-to-point] -> [node 1] +// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2] +// +// We call the propagation of next hop information down vertices of a path +// "inheriting" the next hop information. +// +// The point-to-point link information is only useful in this calculation when +// we are examining the root node. // if (v == m_spfroot) { // -// We're going from the root to a vertex representing a router ... -// +// In this case is the root node, which means it is the starting point +// for the packets forwarded by that node. This also means that the next hop +// address of packets headed for some arbitrary off-network destination must +// be the destination at the other end of one of the links off of the root +// node if this root node is a router. We then need to see if this node +// is a router. +// if (w->m_vertexType == SPFVertex::VertexRouter) { // -// We need to find both sides of the link we're examining. We are considering -// a link "from" vertex v "to" vertex w over the link represented by the link -// record l. We have the information from the perspective of v, now we need -// to get the information from the perspective of w, specifically the point -// to point link record describing the link from w to v. +// In the case of point-to-point links, the link data field (m_linkData) of a +// Static Router Link Record contains the local IP address. If we look at the +// link record describing the link from the perspecive of (the remote +// node from the viewpoint of ) back to the root node, we can discover the +// IP address of the router to which is adjacent. This is a distinguished +// address -- the next hop address to get from to and all networks +// accessed through that path. // - StaticRouterLinkRecord *l2 = 0; - l2 = SPFGetNextLink(w,v,l2); + StaticRouterLinkRecord *linkRemote = 0; + linkRemote = SPFGetNextLink (w, v, linkRemote); // -// At this point, is the link record from to ; and is the -// link record from to . The next hop address of the destination is -// the link data field of the static router link record (which is the local IP -// address in the case of a point-to-point link). This means that in order to -// get to the network w, you send packets to the other side of the point-to- -// point link -- the router on that network. -// - w->m_nextHop = l2->m_linkData; +// At this point, is the Static Router Link Record describing the point- +// to point link from to from the perspective of ; and +// is the Static Router Link Record describing that same link from the +// perspective of (back to ). Now we can just copy the next hop +// address from the m_linkData member variable. // -// Now find the interface corresponding to the point to point link's IP -// address. +// The next hop member variable we put in has the sense "in order to get +// to the network represented by vertex , you have to send the packet to +// the next hop address specified in w->nextHop. // - w->m_rootOif = FindOutgoingInterfaceId(l->m_linkData); + w->m_nextHop = linkRemote->m_linkData; +// +// Now find the outgoing interface corresponding to the point to point link +// from the perspective of -- remember that is the link "from" +// "to" . +// + w->m_rootOif = FindOutgoingInterfaceId (l->m_linkData); - NS_DEBUG("SPFNexthopCalculation: Next hop from " << + NS_DEBUG ("SPFNexthopCalculation: Next hop from " << v->m_vertexId << " to " << w->m_vertexId << " goes through next hop " << w->m_nextHop << " via outgoing interface " << w->m_rootOif); @@ -493,63 +522,112 @@ StaticRouteManager::SPFNexthopCalculation ( // // If we're calculating the next hop information from a node (v) that is // *not* the root, then we need to "inherit" the information needed to -// forward from the parent (who will have inherited, ultimately, from the -// root. +// forward the packet from the vertex closer to the root. That is, we'll +// still send packets to the next hop address of the router adjacent to the +// root on the path toward . +// +// Above, when we were considering the root node, we calculated the next hop +// address and outgoing interface required to get off of the root network. +// At this point, we are further away from the root network along one of the +// (shortest) paths. So the next hop and outoing interface remain the same +// (are inherited). // - w->m_rootOif = v->m_rootOif; w->m_nextHop = v->m_nextHop; + w->m_rootOif = v->m_rootOif; } - +// +// In all cases, we need valid values for the distance metric and a parent. +// w->m_distanceFromRoot = distance; w->m_parent = v; + return 1; } -// Derived from quagga ospf_get_next_link -// Find the next link after prev_link from v to w. If prev_link is -// NULL, return the first link from v to w. Ignore stub and virtual links; -// these link types will never be returned. +// +// This method is derived from quagga ospf_get_next_link () +// +// First search the Static Router Link Records of vertex for one +// representing a point-to point link to vertex . +// +// What is done depends on prev_link. Contrary to appearances, prev_link just +// acts as a flag here. If prev_link is NULL, we return the first Static +// Router Link Record we find that describes a point-to-point link from +// to . If prev_link is not NULL, we return a Static Router Link Record +// representing a possible *second* link from to . +// +// BUGBUG This seems to be a bug? Shouldn't this function look for any link +// records after pre_link and not just after the first? // StaticRouterLinkRecord* -StaticRouteManager::SPFGetNextLink( +StaticRouteManager::SPFGetNextLink ( SPFVertex* v, SPFVertex* w, StaticRouterLinkRecord* prev_link ) { - NS_DEBUG("StaticRouteManager::SPFGetNextLink ()"); + NS_DEBUG ("StaticRouteManager::SPFGetNextLink ()"); + bool skip = true; StaticRouterLinkRecord* l; +// +// If prev_link is 0, we are really looking for the first link, not the next +// link. +// if (prev_link == 0) { skip = false; } - - for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = - v->m_lsa->m_linkRecords.begin(); - i != v->m_lsa->m_linkRecords.end(); - i++ ) +// +// Iterate through the Static Router Link Records advertised by the vertex +// looking for records representing the point-to-point links off of this +// vertex. +// + for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = + v->m_lsa->m_linkRecords.begin (); + i != v->m_lsa->m_linkRecords.end (); + i++ ) { - l = *i; - if (l->m_linkType != StaticRouterLinkRecord::PointToPoint) + l = *i; + if (l->m_linkType != StaticRouterLinkRecord::PointToPoint) + { + continue; + } +// +// The link ID of a link record representing a point-to-point link is set to +// the router ID of the neighboring router -- the router to which the link +// connects from the perspective of in this case. The vertex ID is also +// set to the router ID (using the link state advertisement of a router node). +// We're just checking to see if the link is actually the link from to +// . +// + if (l->m_linkId == w->m_vertexId) { + NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId=" << + l->m_linkId << " linkData=" << l->m_linkData); +// +// If skip is false, don't (not too surprisingly) skip the link found -- it's +// the one we're interested in. That's either because we didn't pass in a +// previous link, and we're interested in the first one, or because we've +// skipped a previous link and moved forward to the next (which is then the +// one we want). +// + if (skip == false) { + NS_DEBUG ("SPFGetNextLink: Returning the found link"); + return l; + } + else + { +// +// Skip is true and we've found a link from to . We want the next one. +// Setting skip to false gets us the next point-to-point static router link +// record in the LSA from . +// + NS_DEBUG ("SPFGetNextLink: Skipping the found link"); + skip = false; continue; } - if (l->m_linkId == w->m_vertexId) { - NS_DEBUG("SPFGetNextLink: Found matching link l: linkId=" << - l->m_linkId << " linkData=" << l->m_linkData); - if (skip == false) - { - NS_DEBUG("SPFGetNextLink: Returning the found link"); - return l; - } - else - { - NS_DEBUG("SPFGetNextLink: Skipping the found link"); - skip = false; - continue; - } - } + } } return 0; } @@ -557,105 +635,158 @@ StaticRouteManager::SPFGetNextLink( // quagga ospf_spf_calculate void -StaticRouteManager::DebugSPFCalculate(Ipv4Address root) +StaticRouteManager::DebugSPFCalculate (Ipv4Address root) { - SPFCalculate(root); + SPFCalculate (root); } // quagga ospf_spf_calculate void -StaticRouteManager::SPFCalculate(Ipv4Address root) +StaticRouteManager::SPFCalculate (Ipv4Address root) { - NS_DEBUG("StaticRouteManager::SPFCalculate ()"); + NS_DEBUG ("StaticRouteManager::SPFCalculate ()"); SPFVertex *v; - +// +// Initialize the Link State Database. +// m_lsdb->Initialize (); - - // The candidate queue is a priority queue of SPFVertex objects, with - // the top of the queue being the closest vertex in terms of - // distanceFromRoot. Initially, this queue is empty. - // +// +// The candidate queue is a priority queue of SPFVertex objects, with the top +// of the queue being the closest vertex in terms of distance from the root +// of the tree. Initially, this queue is empty. +// CandidateQueue candidate; - NS_ASSERT(candidate.Size() == 0); - // - // Initialize the shortest-path tree to only the router doing the - // calculation. - // - v= new SPFVertex(m_lsdb->GetLSA(root)); - // This vertex is the root of the SPF tree + NS_ASSERT(candidate.Size () == 0); +// +// Initialize the shortest-path tree to only contain the router doing the +// calculation. Each router (and corresponding network) is a vertex in the +// shortest path first (SPF) tree. +// + v = new SPFVertex (m_lsdb->GetLSA (root)); +// +// This vertex is the root of the SPF tree and it is distance 0 from the root. +// We also mark this vertex as being in the SPF tree. +// + m_spfroot= v; v->m_distanceFromRoot = 0; - m_spfroot= v; v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; for (;;) { - // RFC2328 16.1. (2). - SPFNext(v , candidate); - - // RFC2328 16.1. (3). - // If at this step the candidate list is empty, the shortest- - // path tree (of transit vertices) has been completely built and - // this stage of the procedure terminates. - if (candidate.Size() == 0) - break; - // Otherwise, choose the vertex belonging to the candidate list - // that is closest to the root, and add it to the shortest-path - // tree (removing it from the candidate list in the - // process). - // Extract from the candidates the node with the lower key. - v = candidate.Pop(); - // Update stat field in vertex. - NS_DEBUG("SPFCalculate: Popping vertex" << v->m_vertexId); +// +// The operations we need to do are given in the OSPF RFC which we reference +// as we go along. +// +// RFC2328 16.1. (2). +// +// We examine the Static Router Link Records in the Link State +// Advertisements of the current vertex. If there are any point-to-point +// links to unexplored adjacent vertices we add them to the tree and update +// the distance and next hop information on how to get there. We also add +// the new vertices to the candidate queue (the priority queue ordered by +// shortest path). If the new vertices represent shorter paths, we use them +// and update the path cost. +// + SPFNext (v, candidate); +// +// RFC2328 16.1. (3). +// +// If at this step the candidate list is empty, the shortest-path tree (of +// transit vertices) has been completely built and this stage of the +// procedure terminates. +// + if (candidate.Size () == 0) + { + break; + } +// +// Choose the vertex belonging to the candidate list that is closest to the +// root, and add it to the shortest-path tree (removing it from the candidate +// list in the process). +// +// Recall that in the previous step, we created SPFVertex structures for each +// of the routers found in the Static Router Link Records and added tehm to +// the candidate list. +// + v = candidate.Pop (); + NS_DEBUG ("SPFCalculate: Popped vertex" << v->m_vertexId); +// +// Update the status field of the vertex to indicate that it is in the SPF +// tree. +// v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; - SPFVertexAddParent(v); - // Note that when there is a choice of vertices closest to the - // root, network vertices must be chosen before router vertices - // in order to necessarily find all equal-cost paths. - // We don't do this at this moment, we should add the treatment - // above codes. -- kunihiro. - - // RFC2328 16.1. (4). +// +// The current vertex has a parent pointer. By calling this rather oddly +// named method (blame quagga) we add the current vertex to the list of +// children of that parent vertex. In the next hop calculation called during +// SPFNext, the parent pointer was set but the vertex has been orphaned up +// to now. +// + SPFVertexAddParent (v); +// +// Note that when there is a choice of vertices closest to the root, network +// vertices must be chosen before router vertices in order to necessarily +// find all equal-cost paths. We don't do this at this moment, we should add +// the treatment above codes. -- kunihiro. +// +// +// RFC2328 16.1. (4). +// +// This is the method that actually adds the routes. It'll walk the list +// of nodes in the system, looking for the node corresponding to the router +// ID of the root of the tree -- that is the router we're building the routes +// for. It looks for the Ipv4 interface of that node and remembers it. So +// we are always adding routes to that one node at the root of the SPF tree. +// +// We have a pointer to a vertex in the SPF tree. For each of the +// point-to-point Static Router Link Records of that vertex, we add a route +// using the existing next hop and outbound interface information we have +// already calculated. +// SPFIntraAddRouter (v); - - // RFC2328 16.1. (5). - // Iterate the algorithm by returning to Step 2. - } // end loop until no more candidate vertices - - // Second stage of SPF calculation procedure's - // NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); - +// +// RFC2328 16.1. (5). +// +// Iterate the algorithm by returning to Step 2 until there are no more +// candidate vertices. +// + } +// +// Second stage of SPF calculation procedure's +// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); +// delete m_spfroot; m_spfroot = 0; } // XXX this should probably be a method on Ipv4 uint32_t -StaticRouteManager::FindOutgoingInterfaceId(Ipv4Address a) +StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) { Ipv4Address routerId = m_spfroot->m_vertexId; - std::vector >::iterator i = NodeList::Begin(); - for (; i != NodeList::End(); i++) + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) { Ptr node = *i; Ptr rtr = node->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG(rtr, + NS_ASSERT_MSG (rtr, "StaticRouteManager::FindOutgoingInterfaceId (): " "QI for interface failed"); if (rtr->GetRouterId () == routerId) { Ptr ipv4 = node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4, + NS_ASSERT_MSG (ipv4, "StaticRouteManager::FindOutgoingInterfaceId (): " "QI for interface failed"); - for (uint32_t i = 0; i < ipv4->GetNInterfaces(); i++) + for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) { if (ipv4->GetAddress (i) == a) { - NS_DEBUG("FindOutgoingInterfaceId: Interface match for " << a); + NS_DEBUG ("FindOutgoingInterfaceId: Interface match for " << a); return i; } } @@ -664,11 +795,11 @@ StaticRouteManager::FindOutgoingInterfaceId(Ipv4Address a) return 0; } -// derived from quagga ospf_intra_add_router() +// derived from quagga ospf_intra_add_router () // // This is where we add host routes to the routing tables void -StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) +StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) { // This vertex has just been added to the SPF tree // - the vertex should have a valid m_root_oid corresponding @@ -679,42 +810,42 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) // is a destination IP address to which we add a host route // - NS_ASSERT_MSG(m_spfroot, + NS_ASSERT_MSG (m_spfroot, "StaticRouteManager::SPFIntraAddRouter (): Root pointer not set"); Ipv4Address routerId = m_spfroot->m_vertexId; - std::vector >::iterator i = NodeList::Begin(); - for (; i != NodeList::End(); i++) + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) { Ptr node = *i; Ptr rtr = node->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG(rtr, + NS_ASSERT_MSG (rtr, "StaticRouteManager::SPFIntraAddRouter (): " "QI for interface failed"); if (rtr->GetRouterId () == routerId) { - NS_DEBUG("StaticRouteManager::SPFIntraAddRouter (): " + NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " "setting routes for node " << node->GetId ()); Ptr ipv4 = node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4, + NS_ASSERT_MSG (ipv4, "StaticRouteManager::SPFIntraAddRouter (): " "QI for interface failed"); StaticRouterLSA *lsa = v->m_lsa; - NS_ASSERT_MSG(lsa, + NS_ASSERT_MSG (lsa, "StaticRouteManager::SPFIntraAddRouter (): " "Expected valid LSA in SPFVertex* v"); uint32_t nLinkRecords = lsa->GetNLinkRecords (); - NS_ASSERT_MSG((nLinkRecords & 1) == 0, + NS_ASSERT_MSG ((nLinkRecords & 1) == 0, "StaticRouteManager::SPFIntraAddRouter (): " - "Expected exen number of Link Records"); + "Expected even number of Link Records"); for (uint32_t j = 0; j < nLinkRecords; j += 2) { @@ -724,25 +855,25 @@ StaticRouteManager::SPFIntraAddRouter(SPFVertex* v) continue; } - NS_DEBUG("StaticRouteManager::SPFIntraAddRouter (): " + NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " "Add route to " << lr->m_linkData << " using next hop " << v->m_nextHop << " via interface " << v->m_rootOif); - ipv4->AddHostRouteTo(lr->m_linkData, v->m_nextHop, + ipv4->AddHostRouteTo (lr->m_linkData, v->m_nextHop, v->m_rootOif); } } } } -// Derived from quagga ospf_vertex_add_parents() +// Derived from quagga ospf_vertex_add_parents () // Add a vertex to the list of children in each of its parents. void -StaticRouteManager::SPFVertexAddParent(SPFVertex* v) +StaticRouteManager::SPFVertexAddParent (SPFVertex* v) { // For now, only one parent (not doing equal-cost multipath) - v->m_parent->m_children.push_back(v); + v->m_parent->m_children.push_back (v); } } // namespace ns3 @@ -756,7 +887,7 @@ namespace ns3 { class StaticRouterTestNode : public Node { public: - StaticRouterTestNode(); + StaticRouterTestNode (); private: virtual void DoAddDevice (Ptr device) const {}; @@ -834,111 +965,111 @@ StaticRouteManagerTest::RunTests (void) // link2: 10.1.3.1/30, 10.1.3.2/30 // // Router 0 - StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord(); - lr0->m_linkId.Set(2); // router ID 0.0.0.2 - lr0->m_linkData.Set("10.1.1.1"); + StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord (); + lr0->m_linkId.Set (2); // router ID 0.0.0.2 + lr0->m_linkData.Set ("10.1.1.1"); lr0->m_linkType = StaticRouterLinkRecord::PointToPoint; lr0->m_metric = 1; - StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord(); - lr1->m_linkId.Set("10.1.1.1"); - lr1->m_linkData.Set("255.255.255.252"); + StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord (); + lr1->m_linkId.Set ("10.1.1.1"); + lr1->m_linkData.Set ("255.255.255.252"); lr1->m_linkType = StaticRouterLinkRecord::StubNetwork; lr1->m_metric = 1; - StaticRouterLSA* lsa0 = new StaticRouterLSA(); - lsa0->m_linkStateId.Set("0.0.0.0"); - lsa0->m_advertisingRtr.Set("0.0.0.0"); - lsa0->AddLinkRecord(lr0); - lsa0->AddLinkRecord(lr1); + StaticRouterLSA* lsa0 = new StaticRouterLSA (); + lsa0->m_linkStateId.Set ("0.0.0.0"); + lsa0->m_advertisingRtr.Set ("0.0.0.0"); + lsa0->AddLinkRecord (lr0); + lsa0->AddLinkRecord (lr1); // Router 1 - StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord(); - lr2->m_linkId.Set(2); // router ID 0.0.0.2 - lr2->m_linkData.Set("10.1.2.1"); + StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord (); + lr2->m_linkId.Set (2); // router ID 0.0.0.2 + lr2->m_linkData.Set ("10.1.2.1"); lr2->m_linkType = StaticRouterLinkRecord::PointToPoint; lr2->m_metric = 1; - StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord(); - lr3->m_linkId.Set("10.1.2.1"); - lr3->m_linkData.Set("255.255.255.252"); + StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord (); + lr3->m_linkId.Set ("10.1.2.1"); + lr3->m_linkData.Set ("255.255.255.252"); lr3->m_linkType = StaticRouterLinkRecord::StubNetwork; lr3->m_metric = 1; - StaticRouterLSA* lsa1 = new StaticRouterLSA(); - lsa1->m_linkStateId.Set(1); - lsa1->m_advertisingRtr.Set(1); - lsa1->AddLinkRecord(lr2); - lsa1->AddLinkRecord(lr3); + StaticRouterLSA* lsa1 = new StaticRouterLSA (); + lsa1->m_linkStateId.Set (1); + lsa1->m_advertisingRtr.Set (1); + lsa1->AddLinkRecord (lr2); + lsa1->AddLinkRecord (lr3); // Router 2 - StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord(); - lr4->m_linkId.Set("0.0.0.0"); - lr4->m_linkData.Set("10.1.1.2"); + StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord (); + lr4->m_linkId.Set ("0.0.0.0"); + lr4->m_linkData.Set ("10.1.1.2"); lr4->m_linkType = StaticRouterLinkRecord::PointToPoint; lr4->m_metric = 1; - StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord(); - lr5->m_linkId.Set("10.1.1.2"); - lr5->m_linkData.Set("255.255.255.252"); + StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord (); + lr5->m_linkId.Set ("10.1.1.2"); + lr5->m_linkData.Set ("255.255.255.252"); lr5->m_linkType = StaticRouterLinkRecord::StubNetwork; lr5->m_metric = 1; - StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord(); - lr6->m_linkId.Set(1); - lr6->m_linkData.Set("10.1.2.2"); + StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord (); + lr6->m_linkId.Set (1); + lr6->m_linkData.Set ("10.1.2.2"); lr6->m_linkType = StaticRouterLinkRecord::PointToPoint; lr6->m_metric = 1; - StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord(); - lr7->m_linkId.Set("10.1.2.2"); - lr7->m_linkData.Set("255.255.255.252"); + StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord (); + lr7->m_linkId.Set ("10.1.2.2"); + lr7->m_linkData.Set ("255.255.255.252"); lr7->m_linkType = StaticRouterLinkRecord::StubNetwork; lr7->m_metric = 1; - StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord(); - lr8->m_linkId.Set(3); - lr8->m_linkData.Set("10.1.3.2"); + StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord (); + lr8->m_linkId.Set (3); + lr8->m_linkData.Set ("10.1.3.2"); lr8->m_linkType = StaticRouterLinkRecord::PointToPoint; lr8->m_metric = 1; - StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord(); - lr9->m_linkId.Set("10.1.3.2"); - lr9->m_linkData.Set("255.255.255.252"); + StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord (); + lr9->m_linkId.Set ("10.1.3.2"); + lr9->m_linkData.Set ("255.255.255.252"); lr9->m_linkType = StaticRouterLinkRecord::StubNetwork; lr9->m_metric = 1; - StaticRouterLSA* lsa2 = new StaticRouterLSA(); - lsa2->m_linkStateId.Set(2); - lsa2->m_advertisingRtr.Set(2); - lsa2->AddLinkRecord(lr4); - lsa2->AddLinkRecord(lr5); - lsa2->AddLinkRecord(lr6); - lsa2->AddLinkRecord(lr7); - lsa2->AddLinkRecord(lr8); - lsa2->AddLinkRecord(lr9); + StaticRouterLSA* lsa2 = new StaticRouterLSA (); + lsa2->m_linkStateId.Set (2); + lsa2->m_advertisingRtr.Set (2); + lsa2->AddLinkRecord (lr4); + lsa2->AddLinkRecord (lr5); + lsa2->AddLinkRecord (lr6); + lsa2->AddLinkRecord (lr7); + lsa2->AddLinkRecord (lr8); + lsa2->AddLinkRecord (lr9); // Router 3 - StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord(); - lr10->m_linkId.Set(2); // router ID 0.0.0.2 - lr10->m_linkData.Set("10.1.2.1"); + StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord (); + lr10->m_linkId.Set (2); // router ID 0.0.0.2 + lr10->m_linkData.Set ("10.1.2.1"); lr10->m_linkType = StaticRouterLinkRecord::PointToPoint; lr10->m_metric = 1; - StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord(); - lr11->m_linkId.Set("10.1.2.1"); - lr11->m_linkData.Set("255.255.255.252"); + StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord (); + lr11->m_linkId.Set ("10.1.2.1"); + lr11->m_linkData.Set ("255.255.255.252"); lr11->m_linkType = StaticRouterLinkRecord::StubNetwork; lr11->m_metric = 1; - StaticRouterLSA* lsa3 = new StaticRouterLSA(); - lsa3->m_linkStateId.Set(3); - lsa3->m_advertisingRtr.Set(3); - lsa3->AddLinkRecord(lr2); - lsa3->AddLinkRecord(lr3); + StaticRouterLSA* lsa3 = new StaticRouterLSA (); + lsa3->m_linkStateId.Set (3); + lsa3->m_advertisingRtr.Set (3); + lsa3->AddLinkRecord (lr2); + lsa3->AddLinkRecord (lr3); // Test the database - StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB(); - srmlsdb->Insert(lsa0->m_linkStateId, lsa0); - srmlsdb->Insert(lsa1->m_linkStateId, lsa1); - srmlsdb->Insert(lsa2->m_linkStateId, lsa2); - srmlsdb->Insert(lsa3->m_linkStateId, lsa3); - NS_ASSERT(lsa2 == srmlsdb->GetLSA(lsa2->m_linkStateId)); + StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); + srmlsdb->Insert (lsa0->m_linkStateId, lsa0); + srmlsdb->Insert (lsa1->m_linkStateId, lsa1); + srmlsdb->Insert (lsa2->m_linkStateId, lsa2); + srmlsdb->Insert (lsa3->m_linkStateId, lsa3); + NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->m_linkStateId)); // XXX next, calculate routes based on the manually created LSDB - StaticRouteManager* srm = new StaticRouteManager(); + StaticRouteManager* srm = new StaticRouteManager (); srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB // Note-- this will succeed without any nodes in the topology // because the NodeList is empty - srm->DebugSPFCalculate(lsa0->m_linkStateId); // node n0 + srm->DebugSPFCalculate (lsa0->m_linkStateId); // node n0 // This delete clears the srm, which deletes the LSDB, which clears // all of the LSAs, which each destroys the attached LinkRecords. From 76223227ba572b5f2d142259be2e385467776491 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 17 Jul 2007 11:02:14 +0100 Subject: [PATCH 068/278] Allow compiling the 'routing' module and example with WAF --- examples/wscript | 1 + src/internet-node/wscript | 2 +- src/routing/wscript | 25 +++++++++++++++++++++++++ src/wscript | 1 + 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/routing/wscript diff --git a/examples/wscript b/examples/wscript index f535ea93f..6e8fea84d 100644 --- a/examples/wscript +++ b/examples/wscript @@ -10,4 +10,5 @@ def build(bld): return obj obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node']) + obj = create_ns_prog('simple-static-routing', 'simple-static-routing.cc', deps=['p2p', 'internet-node', 'routing']) diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 806861fd3..ef922b3b1 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -9,7 +9,7 @@ def build(bld): obj = bld.create_obj('cpp', 'shlib') obj.name = 'ns3-internet-node' obj.target = obj.name - obj.uselib_local = ['ns3-node', 'ns3-applications'] + obj.uselib_local = ['ns3-node', 'ns3-applications', 'ns3-routing'] obj.source = [ 'internet-node.cc', 'l3-demux.cc', diff --git a/src/routing/wscript b/src/routing/wscript new file mode 100644 index 000000000..79f8c2b21 --- /dev/null +++ b/src/routing/wscript @@ -0,0 +1,25 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-routing') + + +def build(bld): + module = bld.create_obj('cpp', 'shlib') + module.name = 'ns3-routing' + module.target = module.name + module.uselib_local = ['ns3-node'] + module.source = [ + 'routing-environment.cc', + 'static-router.cc', + 'static-route-manager.cc', + 'candidate-queue.cc', + ] + + headers = bld.create_obj('ns3header') + headers.source = [ + 'routing-environment.h', + 'static-router.h', + 'static-route-manager.h', + 'candidate-queue.h', + ] diff --git a/src/wscript b/src/wscript index 2e2349f10..33032283b 100644 --- a/src/wscript +++ b/src/wscript @@ -17,6 +17,7 @@ all_modules = [ 'internet-node', 'devices/p2p', 'applications', + 'routing', ] From f8616ba0b506fe41a0b0bf965f83e958d2e99527 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 17 Jul 2007 22:20:48 -0700 Subject: [PATCH 069/278] routing documentation --- src/routing/static-route-manager.cc | 220 ++++++++++++++++++++++------ 1 file changed, 172 insertions(+), 48 deletions(-) diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 508f53831..e6142fa03 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -489,6 +489,10 @@ StaticRouteManager::SPFNexthopCalculation ( // IP address of the router to which is adjacent. This is a distinguished // address -- the next hop address to get from to and all networks // accessed through that path. +// +// SPFGetNextLink () is a little odd. used in this way it is just going to +// return the link record describing the link from to . Think of it as +// SPFGetLink. // StaticRouterLinkRecord *linkRemote = 0; linkRemote = SPFGetNextLink (w, v, linkRemote); @@ -500,8 +504,8 @@ StaticRouteManager::SPFNexthopCalculation ( // address from the m_linkData member variable. // // The next hop member variable we put in has the sense "in order to get -// to the network represented by vertex , you have to send the packet to -// the next hop address specified in w->nextHop. +// from the root node to the host represented by vertex , you have to send +// the packet to the next hop address specified in w->m_nextHop. // w->m_nextHop = linkRemote->m_linkData; // @@ -632,8 +636,9 @@ StaticRouteManager::SPFGetNextLink ( return 0; } - -// quagga ospf_spf_calculate +// +// Used for unit tests. +// void StaticRouteManager::DebugSPFCalculate (Ipv4Address root) { @@ -644,7 +649,8 @@ StaticRouteManager::DebugSPFCalculate (Ipv4Address root) void StaticRouteManager::SPFCalculate (Ipv4Address root) { - NS_DEBUG ("StaticRouteManager::SPFCalculate ()"); + NS_DEBUG ("StaticRouteManager::SPFCalculate (): " + "root = " << root); SPFVertex *v; // @@ -710,7 +716,7 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // the candidate list. // v = candidate.Pop (); - NS_DEBUG ("SPFCalculate: Popped vertex" << v->m_vertexId); + NS_DEBUG ("SPFCalculate: Popped vertex " << v->m_vertexId); // // Update the status field of the vertex to indicate that it is in the SPF // tree. @@ -730,19 +736,28 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // find all equal-cost paths. We don't do this at this moment, we should add // the treatment above codes. -- kunihiro. // -// // RFC2328 16.1. (4). // // This is the method that actually adds the routes. It'll walk the list // of nodes in the system, looking for the node corresponding to the router // ID of the root of the tree -- that is the router we're building the routes // for. It looks for the Ipv4 interface of that node and remembers it. So -// we are always adding routes to that one node at the root of the SPF tree. +// we are only actually adding routes to that one node at the root of the SPF +// tree. // -// We have a pointer to a vertex in the SPF tree. For each of the -// point-to-point Static Router Link Records of that vertex, we add a route -// using the existing next hop and outbound interface information we have -// already calculated. +// We're going to pop of a pointer to every vertex in the tree except the +// root in order of distance from the root. For each of the vertices, we call +// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the +// point-to-point Static Router Link Records (the links to nodes adjacent to +// the node represented by the vertex). We add a link to the IP address +// specified by the m_linkData field of each of those link records. This will +// be the *local* IP address associated with the interface attached to the +// link. We use the outbound interface and next hop information present in +// the vertex . +// +// To summarize, we're going to look at the node represented by and loop +// through its point-to-point links, adding a *host* route to the local IP +// address (at the side) for each of those links. // SPFIntraAddRouter (v); // @@ -755,18 +770,37 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // // Second stage of SPF calculation procedure's // NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); +// +// We're all done setting the routing information for the node at the root of +// the SPF tree. Delete all of the vertices and corresponding resources. Go +// possibly do it again for the next router. // delete m_spfroot; m_spfroot = 0; } +// // XXX this should probably be a method on Ipv4 +// +// Return the interface index corresponding to a given IP address +// uint32_t StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) { - +// +// We have an IP address and a vertex ID of the root of the SPF tree. +// The question is what interface index does this address correspond to. +// The answer is a little complicated since we have to find a pointer to +// the node corresponding to the vertex ID, find the Ipv4 interface on that +// node in order to iterate the interfaces and find the one corresponding to +// the address in question. +// Ipv4Address routerId = m_spfroot->m_vertexId; - +// +// Walk the list of nodes in the system looking for the one corresponding to +// the node at the root of the SPF tree. This is the node for which we are +// building the routing table. +// std::vector >::iterator i = NodeList::Begin (); for (; i != NodeList::End (); i++) { @@ -774,81 +808,147 @@ StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) Ptr rtr = node->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG (rtr, - "StaticRouteManager::FindOutgoingInterfaceId (): " - "QI for interface failed"); +// +// If the node doesn't have a StaticRouter interface it can't be the one +// we're interested in. +// + if (rtr == 0) + { + continue; + } + if (rtr->GetRouterId () == routerId) { +// +// This is the node we're building the routing table for. We're going to need +// the Ipv4 interface to look for the ipv4 interface index. Since this node +// is participating in routing IP version 4 packets, it certainly must have +// an Ipv4 interface. +// Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG (ipv4, "StaticRouteManager::FindOutgoingInterfaceId (): " "QI for interface failed"); +// +// Look through the interfaces on this node for one that has the IP address +// we're looking for. If we find one, return the corresponding interface +// index. +// for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) { - if (ipv4->GetAddress (i) == a) { - NS_DEBUG ("FindOutgoingInterfaceId: Interface match for " << a); - return i; - } + if (ipv4->GetAddress (i) == a) + { + NS_DEBUG ("StaticRouteManager::FindOutgoingInterfaceId (): " + "Interface match for " << a); + return i; + } } } - } + } +// +// Couldn't find it. +// return 0; } -// derived from quagga ospf_intra_add_router () // -// This is where we add host routes to the routing tables +// This method is derived from quagga ospf_intra_add_router () +// +// This is where we are actually going to add the host routes to the routing +// tables of the individual nodes. +// +// The vertex passed as a parameter has just been added to the SPF tree. +// This vertex must have a valid m_root_oid, corresponding to the outgoing +// interface on the root router of the tree that is the first hop on the path +// to the vertex. The vertex must also have a next hop address, corresponding +// to the next hop on the path to the vertex. The vertex has an m_lsa field +// that has some number of link records. For each point to point link record, +// the m_linkData is the local IP address of the link. This corresponds to +// a destination IP address, reachable from the root, to which we add a host +// route. +// void StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) { - // This vertex has just been added to the SPF tree - // - the vertex should have a valid m_root_oid corresponding - // to the outgoing interface on the root router of the tree - // that corresponds to the path to it - // - the vertex has an m_lsa field that has a number of link - // records. For each point to point record, the m_linkData - // is a destination IP address to which we add a host route - // + NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ()"); NS_ASSERT_MSG (m_spfroot, "StaticRouteManager::SPFIntraAddRouter (): Root pointer not set"); - +// +// The root of the Shortest Path First tree is the router to which we are +// going to write the actual routing table entries. The vertex corresponding +// to this router has a vertex ID which is the router ID of that node. We're +// going to use this ID to discover which node it is that we're actually going +// to update. +// Ipv4Address routerId = m_spfroot->m_vertexId; + NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ():" + "Vertex ID = " << routerId); +// +// We need to walk the list of nodes looking for the one that has the router +// ID corresponding to the root vertex. This is the one we're going to write +// the routing information to. +// std::vector >::iterator i = NodeList::Begin (); for (; i != NodeList::End (); i++) { Ptr node = *i; - +// +// The router ID is accessible through the StaticRouter interface, so we need +// to QI for that interface. If there's no StaticRouter interface, the node +// in question cannot be the router we want, so we continue. +// Ptr rtr = node->QueryInterface (StaticRouter::iid); - NS_ASSERT_MSG (rtr, - "StaticRouteManager::SPFIntraAddRouter (): " - "QI for interface failed"); + if (rtr == 0) + { + continue; + } +// +// If the router ID of the current node is equal to the router ID of the +// root of the SPF tree, then this node is the one for which we need to +// write the routing tables. +// if (rtr->GetRouterId () == routerId) { NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " "setting routes for node " << node->GetId ()); - +// +// Routing information is updated using the Ipv4 interface. We need to QI +// for that interface. If the node is acting as an IP version 4 router, it +// should absolutely have an Ipv4 interface. +// Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG (ipv4, "StaticRouteManager::SPFIntraAddRouter (): " "QI for interface failed"); - +// +// Get the Static Router Link State Advertisement from the vertex we're +// adding the routes to. The LSA will have a number of attached Static Router +// Link Records corresponding to links off of that vertex / node. We're going +// to be interested in the records corresponding to point-to-point links. +// StaticRouterLSA *lsa = v->m_lsa; NS_ASSERT_MSG (lsa, "StaticRouteManager::SPFIntraAddRouter (): " "Expected valid LSA in SPFVertex* v"); uint32_t nLinkRecords = lsa->GetNLinkRecords (); - - NS_ASSERT_MSG ((nLinkRecords & 1) == 0, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected even number of Link Records"); - +// +// Iterate through the link records on the vertex to which we're going to add +// routes. To make sure we're being clear, we're going to add routing table +// entries to the tables on the node corresping to the root of the SPF tree. +// These entries will have routes to the IP addresses we find from looking at +// the local side of the point-to-point links found on the node described by +// the vertex . +// for (uint32_t j = 0; j < nLinkRecords; j += 2) { +// +// We are only concerned about point-to-point links +// StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); if (lr->m_linkType != StaticRouterLinkRecord::PointToPoint) { @@ -856,19 +956,44 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) } NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " - "Add route to " << lr->m_linkData << + " Node " << node->GetId () << + " add route to " << lr->m_linkData << " using next hop " << v->m_nextHop << " via interface " << v->m_rootOif); - +// +// Here's why we did all of that work. We're going to add a host route to the +// host address found in the m_linkData field of the point-to-point link +// record. In the case of a point-to-point link, this is the local IP address +// of the node connected to the link. Each of these point-to-point links +// will correspond to a local interface that has an IP address to which +// the node at the root of the SPF tree can send packets. The vertex +// (corresponding to the node that has these links and interfaces) has +// an m_nextHop address precalculated for us that is the address to which the +// root node should send packets to be forwarded to these IP addresses. +// Similarly, the vertex has an m_rootOif (outbound interface index) to +// which the packets should be send for forwarding. +// ipv4->AddHostRouteTo (lr->m_linkData, v->m_nextHop, v->m_rootOif); } } +// +// We've found the node and added the routes. Don't need to search forward +// for another node we'll never find. +// + return; } } // Derived from quagga ospf_vertex_add_parents () -// Add a vertex to the list of children in each of its parents. +// +// This is a somewhat oddly named method (blame quagga). Although you might +// expect it to add a parent *to* something, it actually adds a vertex +// to the list of children *in* each of its parents. +// +// Given a pointer to a vertex, it links back to the vertex's parent that it +// already has set and adds itself to that vertex's list of children. +// void StaticRouteManager::SPFVertexAddParent (SPFVertex* v) { @@ -905,7 +1030,6 @@ StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) return 0; } - class StaticRouteManagerTest : public Test { public: StaticRouteManagerTest (); From 0921355a74d64ff5ce071ee4dc9f994c593227ca Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Wed, 18 Jul 2007 14:35:06 -0700 Subject: [PATCH 070/278] General cleanup -- const correctness, encapsulation, documentation, etc. --- src/routing/candidate-queue.cc | 10 +- src/routing/candidate-queue.h | 8 +- src/routing/static-route-manager.cc | 241 ++++++++------- src/routing/static-router.cc | 208 ++++++++++--- src/routing/static-router.h | 459 ++++++++++++++++++++-------- 5 files changed, 637 insertions(+), 289 deletions(-) diff --git a/src/routing/candidate-queue.cc b/src/routing/candidate-queue.cc index b45af7ac2..d34e49855 100644 --- a/src/routing/candidate-queue.cc +++ b/src/routing/candidate-queue.cc @@ -81,7 +81,7 @@ CandidateQueue::Pop (void) } SPFVertex * -CandidateQueue::Top (void) +CandidateQueue::Top (void) const { NS_DEBUG("CandidateQueue::Top ()"); @@ -94,7 +94,7 @@ CandidateQueue::Top (void) } bool -CandidateQueue::Empty (void) +CandidateQueue::Empty (void) const { NS_DEBUG("CandidateQueue::Empty ()"); @@ -102,7 +102,7 @@ CandidateQueue::Empty (void) } uint32_t -CandidateQueue::Size (void) +CandidateQueue::Size (void) const { NS_DEBUG("CandidateQueue::Size ()"); @@ -110,11 +110,11 @@ CandidateQueue::Size (void) } SPFVertex * -CandidateQueue::Find (const Ipv4Address addr) +CandidateQueue::Find (const Ipv4Address addr) const { NS_DEBUG("CandidateQueue::Find ()"); - CandidateList_t::iterator i = m_candidates.begin (); + CandidateList_t::const_iterator i = m_candidates.begin (); for (; i != m_candidates.end (); i++) { diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index 146de707c..e9c985287 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -95,13 +95,13 @@ public: * @see Pop () * @returns The Shortest Path First Vertex pointer at the top of the queue. */ - SPFVertex* Top (void); + SPFVertex* Top (void) const; /** * Test the Candidate Queue to determine if it is empty. * * @returns True if the queue is empty, false otherwise. */ - bool Empty (void); + bool Empty (void) const; /** * Return the number of Shortest Path First Vertex pointers presently * stored in the Candidate Queue. @@ -109,7 +109,7 @@ public: * @see SPFVertex * @returns The number of SPFVertex* pointers in the Candidate Queue. */ - uint32_t Size (void); + uint32_t Size (void) const; /** * Searches the Candidate Queue for a Shortest Path First Vertex pointer * that points to a vertex having the given IP address. @@ -118,7 +118,7 @@ public: * @param addr The IP address to search for. * @returns The SPFVertex* pointer corresponding to the given IP address. */ - SPFVertex* Find (const Ipv4Address addr); + SPFVertex* Find (const Ipv4Address addr) const; /** * Reorders the Candidate Queue according to the priority scheme. On * completion, the top of the queue will hold the Shortest Path First diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index e6142fa03..5e4aece04 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -44,7 +44,7 @@ SPFVertex::SPFVertex () : SPFVertex::SPFVertex (StaticRouterLSA* lsa) : m_vertexType (VertexRouter), - m_vertexId (lsa->m_linkStateId), + m_vertexId (lsa->GetLinkStateId ()), m_lsa (lsa), m_parent (0), m_children (), @@ -92,7 +92,7 @@ StaticRouteManagerLSDB::Initialize () for (i= m_database.begin (); i!= m_database.end (); i++) { StaticRouterLSA* temp = i->second; - temp->m_stat = StaticRouterLSA::LSA_SPF_NOT_EXPLORED; + temp->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); } } @@ -196,7 +196,7 @@ StaticRouteManager::BuildStaticRoutingDatabase () // // Write the newly discovered link state advertisement to the database. // - m_lsdb->Insert (lsa->m_linkStateId, lsa); + m_lsdb->Insert (lsa->GetLinkStateId (), lsa); } } } @@ -291,26 +291,23 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) if (true) { NS_DEBUG ("SPFNext: Examining " << v->m_vertexId << "'s " << - v->m_lsa->m_linkRecords.size () << " link records"); + v->m_lsa->GetNLinkRecords () << " link records"); // // Walk the list of link records in the link state advertisement associated // with the "current" router (represented by vertex ). // - for (StaticRouterLSA::ListOfLinkRecords_t::iterator i = - v->m_lsa->m_linkRecords.begin (); - i != v->m_lsa->m_linkRecords.end (); - i++) + for (uint32_t i = 0; i < v->m_lsa->GetNLinkRecords (); ++i) { // // (a) If this is a link to a stub network, examine the next link in V's LSA. // Links to stub networks will be considered in the second stage of the // shortest path calculation. // - StaticRouterLinkRecord* l = *i; - if (l->m_linkType == StaticRouterLinkRecord::StubNetwork) + StaticRouterLinkRecord *l = v->m_lsa->GetLinkRecord (i); + if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) { - NS_DEBUG ("SPFNext: Found a Stub record to " - << l->m_linkId); + NS_DEBUG ("SPFNext: Found a Stub record to " << + l->GetLinkId ()); continue; } // @@ -318,16 +315,16 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // the vertex W's LSA (router-LSA or network-LSA) in Area A's link state // database. // - if (l->m_linkType == StaticRouterLinkRecord::PointToPoint) + if (l->GetLinkType () == StaticRouterLinkRecord::PointToPoint) { // // Lookup the link state advertisement of the new link -- we call it in // the link state database. // - w_lsa = m_lsdb->GetLSA (l->m_linkId); + w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); NS_ASSERT (w_lsa); NS_DEBUG ("SPFNext: Found a P2P record from " << - v->m_vertexId << " to " << w_lsa->m_linkStateId); + v->m_vertexId << " to " << w_lsa->GetLinkStateId ()); // // (c) If vertex W is already on the shortest-path tree, examine the next // link in the LSA. @@ -335,10 +332,11 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // If the link is to a router that is already in the shortest path first tree // then we have it covered -- ignore it. // - if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_IN_SPFTREE) + if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_IN_SPFTREE) { NS_DEBUG ("SPFNext: Skipping-> LSA "<< - w_lsa->m_linkStateId << " already in SPF tree"); + w_lsa->GetLinkStateId () << " already in SPF tree"); continue; } // @@ -349,12 +347,13 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // calculated) shortest path to vertex V and the advertised cost of the link // between vertices V and W. // - distance = v->m_distanceFromRoot + l->m_metric; + distance = v->m_distanceFromRoot + l->GetMetric (); NS_DEBUG ("SPFNext: Considering w_lsa " << - w_lsa->m_linkStateId); + w_lsa->GetLinkStateId ()); - if (w_lsa->m_stat == StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { // // If we havent yet considered the link represented by we have to create @@ -369,7 +368,8 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // if (SPFNexthopCalculation (v, w, l, distance)) { - w_lsa->m_stat = StaticRouterLSA::LSA_SPF_CANDIDATE; + w_lsa->SetStatus ( + StaticRouterLSA::LSA_SPF_CANDIDATE); // // Push this new vertex onto the priority queue (ordered by distance from the // root node). @@ -379,8 +379,8 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) << ", parent vertexId: " << v->m_vertexId); } } - } else if (w_lsa->m_stat == - StaticRouterLSA::LSA_SPF_CANDIDATE) + } else if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_CANDIDATE) { // // We have already considered the link represented by . What wse have to @@ -389,7 +389,7 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // // So, locate the vertex in the candidate queue and take a look at the // distance. - w = candidate.Find (w_lsa->m_linkStateId); + w = candidate.Find (w_lsa->GetLinkStateId ()); if (w->m_distanceFromRoot < distance) { // @@ -507,13 +507,13 @@ StaticRouteManager::SPFNexthopCalculation ( // from the root node to the host represented by vertex , you have to send // the packet to the next hop address specified in w->m_nextHop. // - w->m_nextHop = linkRemote->m_linkData; + w->m_nextHop = linkRemote->GetLinkData (); // // Now find the outgoing interface corresponding to the point to point link // from the perspective of -- remember that is the link "from" // "to" . // - w->m_rootOif = FindOutgoingInterfaceId (l->m_linkData); + w->m_rootOif = FindOutgoingInterfaceId (l->GetLinkData ()); NS_DEBUG ("SPFNexthopCalculation: Next hop from " << v->m_vertexId << " to " << w->m_vertexId << @@ -587,13 +587,10 @@ StaticRouteManager::SPFGetNextLink ( // looking for records representing the point-to-point links off of this // vertex. // - for ( StaticRouterLSA::ListOfLinkRecords_t::iterator i = - v->m_lsa->m_linkRecords.begin (); - i != v->m_lsa->m_linkRecords.end (); - i++ ) + for (uint32_t i = 0; i < v->m_lsa->GetNLinkRecords (); ++i) { - l = *i; - if (l->m_linkType != StaticRouterLinkRecord::PointToPoint) + l = v->m_lsa->GetLinkRecord (i); + if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) { continue; } @@ -605,9 +602,9 @@ StaticRouteManager::SPFGetNextLink ( // We're just checking to see if the link is actually the link from to // . // - if (l->m_linkId == w->m_vertexId) { - NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId=" << - l->m_linkId << " linkData=" << l->m_linkData); + if (l->GetLinkId () == w->m_vertexId) { + NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << + l->GetLinkId () << " linkData = " << l->GetLinkData ()); // // If skip is false, don't (not too surprisingly) skip the link found -- it's // the one we're interested in. That's either because we didn't pass in a @@ -676,7 +673,7 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // m_spfroot= v; v->m_distanceFromRoot = 0; - v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; + v->m_lsa->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); for (;;) { @@ -721,7 +718,7 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // Update the status field of the vertex to indicate that it is in the SPF // tree. // - v->m_lsa->m_stat = StaticRouterLSA::LSA_SPF_IN_SPFTREE; + v->m_lsa->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); // // The current vertex has a parent pointer. By calling this rather oddly // named method (blame quagga) we add the current vertex to the list of @@ -950,14 +947,14 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) // We are only concerned about point-to-point links // StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); - if (lr->m_linkType != StaticRouterLinkRecord::PointToPoint) + if (lr->GetLinkType () != StaticRouterLinkRecord::PointToPoint) { continue; } NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " " Node " << node->GetId () << - " add route to " << lr->m_linkData << + " add route to " << lr->GetLinkData () << " using next hop " << v->m_nextHop << " via interface " << v->m_rootOif); // @@ -973,7 +970,7 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) // Similarly, the vertex has an m_rootOif (outbound interface index) to // which the packets should be send for forwarding. // - ipv4->AddHostRouteTo (lr->m_linkData, v->m_nextHop, + ipv4->AddHostRouteTo (lr->GetLinkData (), v->m_nextHop, v->m_rootOif); } } @@ -1089,73 +1086,83 @@ StaticRouteManagerTest::RunTests (void) // link2: 10.1.3.1/30, 10.1.3.2/30 // // Router 0 - StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord (); - lr0->m_linkId.Set (2); // router ID 0.0.0.2 - lr0->m_linkData.Set ("10.1.1.1"); - lr0->m_linkType = StaticRouterLinkRecord::PointToPoint; - lr0->m_metric = 1; - StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord (); - lr1->m_linkId.Set ("10.1.1.1"); - lr1->m_linkData.Set ("255.255.255.252"); - lr1->m_linkType = StaticRouterLinkRecord::StubNetwork; - lr1->m_metric = 1; + StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", // router ID 0.0.0.2 + "10.1.1.1", // local ID + 1); // metric + + StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.1.1", + "255.255.255.252", + 1); + StaticRouterLSA* lsa0 = new StaticRouterLSA (); - lsa0->m_linkStateId.Set ("0.0.0.0"); - lsa0->m_advertisingRtr.Set ("0.0.0.0"); + lsa0->SetLinkStateId ("0.0.0.0"); + lsa0->SetAdvertisingRouter ("0.0.0.0"); lsa0->AddLinkRecord (lr0); lsa0->AddLinkRecord (lr1); // Router 1 - StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord (); - lr2->m_linkId.Set (2); // router ID 0.0.0.2 - lr2->m_linkData.Set ("10.1.2.1"); - lr2->m_linkType = StaticRouterLinkRecord::PointToPoint; - lr2->m_metric = 1; - StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord (); - lr3->m_linkId.Set ("10.1.2.1"); - lr3->m_linkData.Set ("255.255.255.252"); - lr3->m_linkType = StaticRouterLinkRecord::StubNetwork; - lr3->m_metric = 1; + StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + + StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + StaticRouterLSA* lsa1 = new StaticRouterLSA (); - lsa1->m_linkStateId.Set (1); - lsa1->m_advertisingRtr.Set (1); + lsa1->SetLinkStateId ("0.0.0.1"); + lsa1->SetAdvertisingRouter ("0.0.0.1"); lsa1->AddLinkRecord (lr2); lsa1->AddLinkRecord (lr3); // Router 2 - StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord (); - lr4->m_linkId.Set ("0.0.0.0"); - lr4->m_linkData.Set ("10.1.1.2"); - lr4->m_linkType = StaticRouterLinkRecord::PointToPoint; - lr4->m_metric = 1; - StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord (); - lr5->m_linkId.Set ("10.1.1.2"); - lr5->m_linkData.Set ("255.255.255.252"); - lr5->m_linkType = StaticRouterLinkRecord::StubNetwork; - lr5->m_metric = 1; - StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord (); - lr6->m_linkId.Set (1); - lr6->m_linkData.Set ("10.1.2.2"); - lr6->m_linkType = StaticRouterLinkRecord::PointToPoint; - lr6->m_metric = 1; - StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord (); - lr7->m_linkId.Set ("10.1.2.2"); - lr7->m_linkData.Set ("255.255.255.252"); - lr7->m_linkType = StaticRouterLinkRecord::StubNetwork; - lr7->m_metric = 1; - StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord (); - lr8->m_linkId.Set (3); - lr8->m_linkData.Set ("10.1.3.2"); - lr8->m_linkType = StaticRouterLinkRecord::PointToPoint; - lr8->m_metric = 1; - StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord (); - lr9->m_linkId.Set ("10.1.3.2"); - lr9->m_linkData.Set ("255.255.255.252"); - lr9->m_linkType = StaticRouterLinkRecord::StubNetwork; - lr9->m_metric = 1; + StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.0", + "10.1.1.2", + 1); + + StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.1.2", + "255.255.255.252", + 1); + + StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.1", + "10.1.2.2", + 1); + + StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.2", + "255.255.255.252", + 1); + + StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.3", + "10.1.3.2", + 1); + + StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.3.2", + "255.255.255.252", + 1); + StaticRouterLSA* lsa2 = new StaticRouterLSA (); - lsa2->m_linkStateId.Set (2); - lsa2->m_advertisingRtr.Set (2); + lsa2->SetLinkStateId ("0.0.0.2"); + lsa2->SetAdvertisingRouter ("0.0.0.2"); lsa2->AddLinkRecord (lr4); lsa2->AddLinkRecord (lr5); lsa2->AddLinkRecord (lr6); @@ -1164,36 +1171,38 @@ StaticRouteManagerTest::RunTests (void) lsa2->AddLinkRecord (lr9); // Router 3 - StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord (); - lr10->m_linkId.Set (2); // router ID 0.0.0.2 - lr10->m_linkData.Set ("10.1.2.1"); - lr10->m_linkType = StaticRouterLinkRecord::PointToPoint; - lr10->m_metric = 1; - StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord (); - lr11->m_linkId.Set ("10.1.2.1"); - lr11->m_linkData.Set ("255.255.255.252"); - lr11->m_linkType = StaticRouterLinkRecord::StubNetwork; - lr11->m_metric = 1; + StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + + StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + StaticRouterLSA* lsa3 = new StaticRouterLSA (); - lsa3->m_linkStateId.Set (3); - lsa3->m_advertisingRtr.Set (3); - lsa3->AddLinkRecord (lr2); - lsa3->AddLinkRecord (lr3); + lsa3->SetLinkStateId ("0.0.0.3"); + lsa3->SetAdvertisingRouter ("0.0.0.3"); + lsa3->AddLinkRecord (lr10); + lsa3->AddLinkRecord (lr11); // Test the database StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); - srmlsdb->Insert (lsa0->m_linkStateId, lsa0); - srmlsdb->Insert (lsa1->m_linkStateId, lsa1); - srmlsdb->Insert (lsa2->m_linkStateId, lsa2); - srmlsdb->Insert (lsa3->m_linkStateId, lsa3); - NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->m_linkStateId)); + srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0); + srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1); + srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2); + srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3); + NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); // XXX next, calculate routes based on the manually created LSDB StaticRouteManager* srm = new StaticRouteManager (); srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB // Note-- this will succeed without any nodes in the topology // because the NodeList is empty - srm->DebugSPFCalculate (lsa0->m_linkStateId); // node n0 + srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 // This delete clears the srm, which deletes the LSDB, which clears // all of the LSAs, which each destroys the attached LinkRecords. diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index 81bbee2a6..b70d865e1 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -26,19 +26,120 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); namespace ns3 { +StaticRouterLinkRecord::StaticRouterLinkRecord () +: + m_linkId ("0.0.0.0"), + m_linkData ("0.0.0.0"), + m_linkType (Unknown), + m_metric (0) +{ + NS_DEBUG("StaticRouterLinkRecord::StaticRouterLinkRecord ()"); +} + +StaticRouterLinkRecord::StaticRouterLinkRecord ( + LinkType linkType, + Ipv4Address linkId, + Ipv4Address linkData, + uint32_t metric) +: + m_linkId (linkId), + m_linkData (linkData), + m_linkType (linkType), + m_metric (metric) +{ + NS_DEBUG("StaticRouterLinkRecord::StaticRouterLinkRecord (" << + linkType << ", " << linkId << ", " << linkData << ", " << metric << ")"); +} + +StaticRouterLinkRecord::~StaticRouterLinkRecord () +{ + NS_DEBUG("StaticRouterLinkRecord::~StaticRouterLinkRecord ()"); +} + + Ipv4Address +StaticRouterLinkRecord::GetLinkId (void) const +{ + NS_DEBUG("StaticRouterLinkRecord::GetLinkId ()"); + return m_linkId; +} + + void +StaticRouterLinkRecord::SetLinkId (Ipv4Address addr) +{ + NS_DEBUG("StaticRouterLinkRecord::SetLinkId ()"); + m_linkId = addr; +} + + Ipv4Address +StaticRouterLinkRecord::GetLinkData (void) const +{ + NS_DEBUG("StaticRouterLinkRecord::GetLinkData ()"); + return m_linkData; +} + + void +StaticRouterLinkRecord::SetLinkData (Ipv4Address addr) +{ + NS_DEBUG("StaticRouterLinkRecord::SetLinkData ()"); + m_linkData = addr; +} + + StaticRouterLinkRecord::LinkType +StaticRouterLinkRecord::GetLinkType (void) const +{ + NS_DEBUG("StaticRouterLinkRecord::GetLinkType ()"); + return m_linkType; +} + + void +StaticRouterLinkRecord::SetLinkType ( + StaticRouterLinkRecord::LinkType linkType) +{ + NS_DEBUG("StaticRouterLinkRecord::SetLinkType ()"); + m_linkType = linkType; +} + + uint32_t +StaticRouterLinkRecord::GetMetric (void) const +{ + NS_DEBUG("StaticRouterLinkRecord::GetMetric ()"); + return m_metric; +} + + void +StaticRouterLinkRecord::SetMetric (uint32_t metric) +{ + NS_DEBUG("StaticRouterLinkRecord::SetMetric ()"); + m_metric = metric; +} + StaticRouterLSA::StaticRouterLSA() : m_linkStateId("0.0.0.0"), m_advertisingRtr("0.0.0.0"), m_linkRecords(), - m_stat(StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + m_status(StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); } +StaticRouterLSA::StaticRouterLSA ( + StaticRouterLSA::SPFStatus status, + Ipv4Address linkStateId, + Ipv4Address advertisingRtr) +: + m_linkStateId(linkStateId), + m_advertisingRtr(advertisingRtr), + m_linkRecords(), + m_status(status) +{ + NS_DEBUG("StaticRouterLSA::StaticRouterLSA (" << status << ", " << + linkStateId << ", " << advertisingRtr << ")"); +} + StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr), - m_stat(lsa.m_stat) + m_status(lsa.m_status) { NS_ASSERT_MSG(IsEmpty(), "StaticRouterLSA::StaticRouterLSA (): Non-empty LSA in constructor"); @@ -46,11 +147,11 @@ StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) } StaticRouterLSA& -StaticRouterLSA::operator= (StaticRouterLSA& lsa) +StaticRouterLSA::operator= (const StaticRouterLSA& lsa) { m_linkStateId = lsa.m_linkStateId; m_advertisingRtr = lsa.m_advertisingRtr; - m_stat = lsa.m_stat; + m_status = lsa.m_status; ClearLinkRecords (); CopyLinkRecords (lsa); @@ -58,17 +159,19 @@ StaticRouterLSA::operator= (StaticRouterLSA& lsa) } void -StaticRouterLSA::CopyLinkRecords (StaticRouterLSA& lsa) +StaticRouterLSA::CopyLinkRecords (const StaticRouterLSA& lsa) { - for ( ListOfLinkRecords_t::iterator i = lsa.m_linkRecords.begin (); - i != lsa.m_linkRecords.end (); - i++) + for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin (); + i != lsa.m_linkRecords.end (); + i++) { StaticRouterLinkRecord *pSrc = *i; StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; - pDst->m_linkId = pSrc->m_linkId; - pDst->m_linkData = pSrc->m_linkData; - pDst->m_linkType = pSrc->m_linkType; + + pDst->SetLinkType (pSrc->GetLinkType ()); + pDst->SetLinkId (pSrc->GetLinkId ()); + pDst->SetLinkData (pSrc->GetLinkData ()); + m_linkRecords.push_back(pDst); pDst = 0; } @@ -107,16 +210,16 @@ StaticRouterLSA::AddLinkRecord (StaticRouterLinkRecord* lr) } uint32_t -StaticRouterLSA::GetNLinkRecords (void) +StaticRouterLSA::GetNLinkRecords (void) const { return m_linkRecords.size (); } StaticRouterLinkRecord * -StaticRouterLSA::GetLinkRecord (uint32_t n) +StaticRouterLSA::GetLinkRecord (uint32_t n) const { uint32_t j = 0; - for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); + for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin (); i != m_linkRecords.end (); i++, j++) { @@ -129,27 +232,62 @@ StaticRouterLSA::GetLinkRecord (uint32_t n) return 0; } - bool -StaticRouterLSA::IsEmpty (void) +StaticRouterLSA::IsEmpty (void) const { return m_linkRecords.size () == 0; } + Ipv4Address +StaticRouterLSA::GetLinkStateId (void) const +{ + return m_linkStateId; +} + + void +StaticRouterLSA::SetLinkStateId (Ipv4Address addr) +{ + m_linkStateId = addr; +} + + Ipv4Address +StaticRouterLSA::GetAdvertisingRouter (void) const +{ + return m_advertisingRtr; +} + + void +StaticRouterLSA::SetAdvertisingRouter (Ipv4Address addr) +{ + m_advertisingRtr = addr; +} + + StaticRouterLSA::SPFStatus +StaticRouterLSA::GetStatus (void) const +{ + return m_status; +} + + void +StaticRouterLSA::SetStatus (StaticRouterLSA::SPFStatus status) +{ + m_status = status; +} + void -StaticRouterLSA::Print (std::ostream &os) +StaticRouterLSA::Print (std::ostream &os) const { os << "m_linkStateId = " << m_linkStateId << std::endl << "m_advertisingRtr = " << m_advertisingRtr << std::endl; - for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); + for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin (); i != m_linkRecords.end (); i++) { StaticRouterLinkRecord *p = *i; os << "----------" << std::endl; - os << "m_linkId = " << p->m_linkId << std::endl; - os << "m_linkData = " << p->m_linkData << std::endl; + os << "m_linkId = " << p->GetLinkId () << std::endl; + os << "m_linkData = " << p->GetLinkData () << std::endl; } } @@ -198,7 +336,7 @@ StaticRouter::ClearLSAs () } Ipv4Address -StaticRouter::GetRouterId (void) +StaticRouter::GetRouterId (void) const { return m_routerId; } @@ -230,9 +368,9 @@ StaticRouter::DiscoverLSAs (void) // return exactly one. // StaticRouterLSA *pLSA = new StaticRouterLSA; - pLSA->m_linkStateId = m_routerId; - pLSA->m_advertisingRtr = m_routerId; - pLSA->m_stat = StaticRouterLSA::LSA_SPF_NOT_EXPLORED; + pLSA->SetLinkStateId (m_routerId); + pLSA->SetAdvertisingRouter (m_routerId); + pLSA->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); // // We need to ask the node for the number of net devices attached. This isn't // necessarily equal to the number of links to adjacent nodes (other routers) @@ -315,16 +453,16 @@ StaticRouter::DiscoverLSAs (void) // the second is a stub network record with the network number. // StaticRouterLinkRecord *plr = new StaticRouterLinkRecord; - plr->m_linkType = StaticRouterLinkRecord::PointToPoint; - plr->m_linkId = rtrIdRemote; - plr->m_linkData = addrLocal; + plr->SetLinkType (StaticRouterLinkRecord::PointToPoint); + plr->SetLinkId (rtrIdRemote); + plr->SetLinkData (addrLocal); pLSA->AddLinkRecord(plr); plr = 0; plr = new StaticRouterLinkRecord; - plr->m_linkType = StaticRouterLinkRecord::StubNetwork; - plr->m_linkId = addrRemote; - plr->m_linkData.Set(maskRemote.GetHostOrder()); // Frown + plr->SetLinkType (StaticRouterLinkRecord::StubNetwork); + plr->SetLinkId (addrRemote); + plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown pLSA->AddLinkRecord(plr); plr = 0; } @@ -337,7 +475,7 @@ StaticRouter::DiscoverLSAs (void) } uint32_t -StaticRouter::GetNumLSAs (void) +StaticRouter::GetNumLSAs (void) const { NS_DEBUG("StaticRouter::GetNumLSAs ()"); return m_LSAs.size (); @@ -347,7 +485,7 @@ StaticRouter::GetNumLSAs (void) // Get the nth link state advertisement from this router. // bool -StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) +StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) const { NS_ASSERT_MSG(lsa.IsEmpty(), "StaticRouter::GetLSA (): Must pass empty LSA"); // @@ -355,7 +493,7 @@ StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) // walk the list of link state advertisements created there and return the // one the client is interested in. // - ListOfLSAs_t::iterator i = m_LSAs.begin (); + ListOfLSAs_t::const_iterator i = m_LSAs.begin (); uint32_t j = 0; for (; i != m_LSAs.end (); i++, j++) @@ -376,7 +514,7 @@ StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) // other end. This only makes sense with a point-to-point channel. // Ptr -StaticRouter::GetAdjacent(Ptr nd, Ptr ch) +StaticRouter::GetAdjacent(Ptr nd, Ptr ch) const { // // Double-check that channel agrees with device that it's a point-to-point @@ -417,7 +555,7 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) // corresponds to that net device. // uint32_t -StaticRouter::FindIfIndexForDevice(Ptr node, Ptr nd) +StaticRouter::FindIfIndexForDevice(Ptr node, Ptr nd) const { Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4, "QI for interface failed"); diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 4f777e484..f1e5252b0 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -1,3 +1,4 @@ + /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * This program is free software; you can redistribute it and/or modify @@ -34,42 +35,163 @@ namespace ns3 { * The StaticRouterLinkRecord is modeled after the OSPF link record field of * a Link State Advertisement. Right now we will only see two types of link * records corresponding to a stub network and a point-to-point link (channel). - * - * For Type 3 link (Stub), */ class StaticRouterLinkRecord { public: -// -// For Type 1 link (PointToPoint), set m_linkId to Router ID of -// neighboring router. -// -// For Type 3 link (Stub), set m_linkId to neighbor's IP address -// - Ipv4Address m_linkId; -// -// For Type 1 link (PointToPoint), set m_linkData to local IP address -// -// For Type 3 link (Stub), set m_linkData to mask 0xffffffff -// - Ipv4Address m_linkData; // for links to RouterLSA, /** * Enumeration of the possible types of Static Router Link Records. These * are defined in the OSPF spec. We currently only use PointToPoint and * StubNetwork types. */ enum LinkType { - PointToPoint = 1, /**< Record representing a point to point channel */ + Unknown = 0, /**< Uninitialized Link Record */ + PointToPoint, /**< Record representing a point to point channel */ TransitNetwork, /**< Unused -- for future OSPF compatibility */ StubNetwork, /**< Record represents a leaf node network */ VirtualLink /**< Unused -- for future OSPF compatibility */ - } m_linkType; + }; /** - * An abstract cost associated with forwarding a packet across a link. - * A sum of metrics must have a well-defined meaning. That is, you shouldn't - * use bandwidth as a metric (how does the sum of the bandwidth of two hops - * relate to the cost of sending a packet); rather you should use something - * like delay. + * Construct an empty ("uninitialized") Static Router Link Record. + * + * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0"; + * The Link Type is set to Unknown; + * The metric is set to 0. + */ + StaticRouterLinkRecord (); + /** + * Construct a fully uninitialized Static Router Link Record. + * + * @param linkType The type of link record to construct. + * @param linkId The link ID for the record. + * @param linkData The link data field for the record. + * @param metric The metric field for the record. + * @see LinkType + * @see SetLinkId + * @see SetLinkData + */ + StaticRouterLinkRecord ( + LinkType linkType, + Ipv4Address linkId, + Ipv4Address linkData, + uint32_t metric); + /** + * Destroy a Static Router Link Record. + * + * Currently does nothing. Here as a placeholder only. + */ + ~StaticRouterLinkRecord (); + /** + * Get the Link ID field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID + * of the neighboring router. + * + * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent + * neighbor's IP address + */ + Ipv4Address GetLinkId(void) const; + /** + * Set the Link ID field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID + * of the neighboring router. + * + * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent + * neighbor's IP address + */ + void SetLinkId(Ipv4Address addr); + /** + * Get the Link Data field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP + * address of the node of the local side of the link. + * + * For an OSPF type 3 link (StubNetwork), the Link Data will be the + * network mask + */ + Ipv4Address GetLinkData(void) const; + /** + * Set the Link Data field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP + * address of the node of the local side of the link. + * + * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the + * network mask + */ + void SetLinkData(Ipv4Address addr); + /** + * Get the Link Type field of the Static Router Link Record. + * + * The Link Type describes the kind of link a given record represents. The + * values are defined by OSPF. + * + * @see LinkType + */ + LinkType GetLinkType(void) const; + /** + * Set the Link Type field of the Static Router Link Record. + * + * The Link Type describes the kind of link a given record represents. The + * values are defined by OSPF. + * + * @see LinkType + */ + void SetLinkType(LinkType linkType); + /** + * Get the Metric Data field of the Static Router Link Record. + * + * The metric is an abstract cost associated with forwarding a packet across + * a link. A sum of metrics must have a well-defined meaning. That is, you + * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of + * two hops relate to the cost of sending a packet); rather you should use + * something like delay. + */ + uint32_t GetMetric(void) const; + /** + * Set the Metric Data field of the Static Router Link Record. + * + * The metric is an abstract cost associated with forwarding a packet across + * a link. A sum of metrics must have a well-defined meaning. That is, you + * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of + * two hops relate to the cost of sending a packet); rather you should use + * something like delay. + */ + void SetMetric(uint32_t metric); + +private: + /** + * m_linkId and m_linkData are defined by OSPF to have different meanings + * depending on the type of link a given link records represents. They work + * together. + * + * For Type 1 link (PointToPoint), set m_linkId to Router ID of + * neighboring router. + * + * For Type 3 link (Stub), set m_linkId to neighbor's IP address + */ + Ipv4Address m_linkId; + /** + * m_linkId and m_linkData are defined by OSPF to have different meanings + * depending on the type of link a given link records represents. They work + * together. + * + * For Type 1 link (PointToPoint), set m_linkData to local IP address + * + * For Type 3 link (Stub), set m_linkData to mask + */ + Ipv4Address m_linkData; // for links to RouterLSA, + + LinkType m_linkType; + /** + * The metric for a given link. + * + * A metric is abstract cost associated with forwarding a packet across a + * link. A sum of metrics must have a well-defined meaning. That is, you + * shouldn't use bandwidth as a metric (how does the sum of the bandwidth + * of two hops relate to the cost of sending a packet); rather you should + * use something like delay. */ uint32_t m_metric; }; @@ -84,110 +206,189 @@ public: class StaticRouterLSA { public: - /** - * Create a blank Static Router Link State Advertisement. On completion, - * any Ipv4Address variables initialized to 0.0.0.0 and the list of Link - * State Records is empty. - */ - StaticRouterLSA(); - /** - * Copy constructor for a Static Router Link State Advertisement. - * Takes a piece of memory and constructs a semantically identical copy of - * the given LSA. - * - * @param lsa The existing LSA to be used as the source. - */ - StaticRouterLSA (StaticRouterLSA& lsa); - /** - * Destroy an existing Static Router Link State Advertisement. Any Static - * router Link Records present in the list are freed. - */ - ~StaticRouterLSA(); - /** - * Assignment operator for a Static Router Link State Advertisement. - * Takes an existing Static Router Link State Advertisement and overwrites - * it to make a semantically identical copy of a given prototype LSA. - * - * If there are any Static Router Link Records present in the existing - * LSA, they are freed before the assignment happens. - * - * @param lsa The existing LSA to be used as the source. - * @returns Reference to the overwritten LSA. - */ - StaticRouterLSA& operator= (StaticRouterLSA& lsa); - /** - * Copy any Static Router Link Records in a given Static Router Link - * State Advertisement to the current LSA. Existing Link Records are not - * deleted -- this is a concatenation of Link Records. - * - * @see ClearLinkRecords () - * @param lsa The LSA to copy the Link Records from. - */ - void CopyLinkRecords (StaticRouterLSA& lsa); - /** - * Add a given Static Router Link Record to the LSA. - * - * @param lr The Static Router Link Record to be added. - * @returns The number of link records in the list. - */ - uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); - /** - * Return the number of Static Router Link Records in the LSA. - * - * @returns The number of link records in the list. - */ - uint32_t GetNLinkRecords (void); - /** - * Return a pointer to the specified Static Router Link Record. - * - * @param n The LSA number desired. - * @returns The number of link records in the list. - */ - StaticRouterLinkRecord* GetLinkRecord (uint32_t n); - /** - * Release all of the Static Router Link Records present in the Static - * Router Link State Advertisement and make the list of link records empty. - */ - void ClearLinkRecords(void); - /** - * Check to see of the list of Static Router Link Records present in the - * Static Router Link State Advertisement is empty. - * - * @returns True if the list is empty, false otherwise. - */ - bool IsEmpty(void); - /** - * Print the contents of the Static Router Link State Advertisement and - * any Static Router Link Records present in the list. Quite verbose. - */ - void Print (std::ostream &os); - /** - * The Link State ID is defined by the OSPF spec. We always set it to the - * router ID of the router making the advertisement. - * - * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () - */ - Ipv4Address m_linkStateId; - /** - * The Advertising Router is defined by the OSPF spec. We always set it to - * the router ID of the router making the advertisement. - * - * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () - */ - Ipv4Address m_advertisingRtr; - - typedef std::list ListOfLinkRecords_t; - ListOfLinkRecords_t m_linkRecords; - - // this is a tristate flag used internally in the SPF computation +/** + * Enumeration of the possible values of the status flag in the Router Link + * State Advertisements. + */ enum SPFStatus { - LSA_SPF_NOT_EXPLORED = 0, - LSA_SPF_CANDIDATE, - LSA_SPF_IN_SPFTREE - } m_stat; + LSA_SPF_NOT_EXPLORED = 0, /**< New vertex not yet considered */ + LSA_SPF_CANDIDATE, /**< Vertex is in the SPF candidate queue */ + LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */ + }; +/** + * Create a blank Static Router Link State Advertisement. On completion, + * any Ipv4Address variables initialized to 0.0.0.0 and the list of Link + * State Records is empty. + */ + StaticRouterLSA(); +/** + * Create an initialized Static Router Link State Advertisement. On + * completion the list of Link State Records is empty. + * + * @param status The status to of the new LSA. + * @param linkStateId The Ipv4Address for the link state ID field. + * @param advertisingRouter The Ipv4Address for the advertising router field. + */ + StaticRouterLSA(SPFStatus status, Ipv4Address linkStateId, + Ipv4Address advertisingRtr); +/** + * Copy constructor for a Static Router Link State Advertisement. + * Takes a piece of memory and constructs a semantically identical copy of + * the given LSA. + * + * @param lsa The existing LSA to be used as the source. + */ + StaticRouterLSA (StaticRouterLSA& lsa); +/** + * Destroy an existing Static Router Link State Advertisement. Any Static + * router Link Records present in the list are freed. + */ + ~StaticRouterLSA(); +/** + * Assignment operator for a Static Router Link State Advertisement. + * Takes an existing Static Router Link State Advertisement and overwrites + * it to make a semantically identical copy of a given prototype LSA. + * + * If there are any Static Router Link Records present in the existing + * LSA, they are freed before the assignment happens. + * + * @param lsa The existing LSA to be used as the source. + * @returns Reference to the overwritten LSA. + */ + StaticRouterLSA& operator= (const StaticRouterLSA& lsa); +/** + * Copy any Static Router Link Records in a given Static Router Link + * State Advertisement to the current LSA. Existing Link Records are not + * deleted -- this is a concatenation of Link Records. + * + * @see ClearLinkRecords () + * @param lsa The LSA to copy the Link Records from. + */ + void CopyLinkRecords (const StaticRouterLSA& lsa); +/** + * Add a given Static Router Link Record to the LSA. + * + * @param lr The Static Router Link Record to be added. + * @returns The number of link records in the list. + */ + uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); +/** + * Return the number of Static Router Link Records in the LSA. + * + * @returns The number of link records in the list. + */ + uint32_t GetNLinkRecords (void) const; +/** + * Return a pointer to the specified Static Router Link Record. + * + * @param n The LSA number desired. + * @returns The number of link records in the list. + */ + StaticRouterLinkRecord* GetLinkRecord (uint32_t n) const; +/** + * Release all of the Static Router Link Records present in the Static + * Router Link State Advertisement and make the list of link records empty. + */ + void ClearLinkRecords(void); +/** + * Check to see of the list of Static Router Link Records present in the + * Static Router Link State Advertisement is empty. + * + * @returns True if the list is empty, false otherwise. + */ + bool IsEmpty(void) const; +/** + * Print the contents of the Static Router Link State Advertisement and + * any Static Router Link Records present in the list. Quite verbose. + */ + void Print (std::ostream &os) const; +/** + * Get the Link State ID as defined by the OSPF spec. We always set it to + * the router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + * @returns The Ipv4Address stored as the link state ID. + */ + Ipv4Address GetLinkStateId (void) const; +/** + * Set the Link State ID is defined by the OSPF spec. We always set it to + * the router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + */ + void SetLinkStateId (Ipv4Address addr); +/** + * Get the Advertising Router as defined by the OSPF spec. We always set + * it to the router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + * @returns The Ipv4Address stored as the advetising router. + */ + Ipv4Address GetAdvertisingRouter (void) const; +/** + * Set the Advertising Router as defined by the OSPF spec. We always set + * it to the router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + */ + void SetAdvertisingRouter (Ipv4Address rtr); +/** + * Get the SPF status of the advertisement. + * + * @see SPFStatus + * @returns The SPFStatus of the LSA. + */ + SPFStatus GetStatus (void) const; +/** + * Set the SPF status of the advertisement + * + * @see SPFStatus + */ + void SetStatus (SPFStatus status); +private: +/** + * The Link State ID is defined by the OSPF spec. We always set it to the + * router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + */ + Ipv4Address m_linkStateId; +/** + * The Advertising Router is defined by the OSPF spec. We always set it to + * the router ID of the router making the advertisement. + * + * @see RoutingEnvironment::AllocateRouterId () + * @see StaticRouter::GetRouterId () + */ + Ipv4Address m_advertisingRtr; +/** + * A convenience typedef to avoid too much writers cramp. + */ + typedef std::list ListOfLinkRecords_t; +/** + * Each Link State Advertisement contains a number of Link Records that + * describe the kinds of links that are attached to a given node. We + * consider PointToPoint and StubNetwork links. + * + * m_linkRecords is an STL list container to hold the Link Records that have + * been discovered and prepared for the advertisement. + * + * @see StaticRouter::DiscoverLSAs () + */ + ListOfLinkRecords_t m_linkRecords; +/** + * This is a tristate flag used internally in the SPF computation to mark + * if an SPFVertex (a data structure representing a vertex in the SPF tree + * -- a router) is new, is a candidate for a shortest path, or is in its + * proper position in the tree. + */ + SPFStatus m_status; }; std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); @@ -225,7 +426,7 @@ public: * @see RoutingEnvironment::AllocateRouterId () * @returns The Router ID associated with the Static Router. */ - Ipv4Address GetRouterId(void); + Ipv4Address GetRouterId (void) const; /** * Walk the connected channels, discover the adjacent routers and build * the associated number of Static Router Link State Advertisements that @@ -256,7 +457,7 @@ public: * @see StaticRouter::GetLSA () * @returns The number of Static Router Link State Advertisements. */ - uint32_t GetNumLSAs (void); + uint32_t GetNumLSAs (void) const; /** * Get a Static Router Link State Advertisements that this router has said * that it can export. @@ -277,14 +478,14 @@ public: * @param lsa The StaticRouterLSA class to receive the LSA information. * @returns The number of Static Router Link State Advertisements. */ - bool GetLSA (uint32_t n, StaticRouterLSA &lsa); + bool GetLSA (uint32_t n, StaticRouterLSA &lsa) const; protected: virtual ~StaticRouter (); void ClearLSAs (void); - Ptr GetAdjacent(Ptr nd, Ptr ch); - uint32_t FindIfIndexForDevice(Ptr node, Ptr nd); + Ptr GetAdjacent(Ptr nd, Ptr ch) const; + uint32_t FindIfIndexForDevice(Ptr node, Ptr nd) const; Ptr m_node; From e3283739ce619a225d7f54e90c774d2c3e63e9c6 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Wed, 18 Jul 2007 16:57:54 -0700 Subject: [PATCH 071/278] general cleanup of routing --- SConstruct | 7 - samples/main-candidate-queue.cc | 93 ------- src/routing/candidate-queue.cc | 4 +- src/routing/static-route-manager.cc | 242 +++++++++++++---- src/routing/static-route-manager.h | 79 +++++- src/routing/static-router.h | 405 ++++++++++++++-------------- 6 files changed, 459 insertions(+), 371 deletions(-) delete mode 100644 samples/main-candidate-queue.cc diff --git a/SConstruct b/SConstruct index 111358020..8d8468c27 100644 --- a/SConstruct +++ b/SConstruct @@ -503,13 +503,6 @@ ns3.add(sample_component_manager) sample_component_manager.add_deps(['core']) sample_component_manager.add_source('main-component-manager.cc') -sample_candidate_queue = build.Ns3Module('sample-candidate-queue', 'samples') -sample_candidate_queue.set_executable() -ns3.add(sample_candidate_queue) -sample_candidate_queue.add_deps(['core']) -sample_candidate_queue.add_deps(['routing']) -sample_candidate_queue.add_source('main-candidate-queue.cc') - # examples example_simple_p2p = build.Ns3Module('simple-p2p', 'examples') example_simple_p2p.set_executable() diff --git a/samples/main-candidate-queue.cc b/samples/main-candidate-queue.cc deleted file mode 100644 index ca111f0dc..000000000 --- a/samples/main-candidate-queue.cc +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ns3/debug.h" -#include "ns3/assert.h" -#include "ns3/candidate-queue.h" - -using namespace ns3; - - int -main (int argc, char *argv[]) -{ - NS_DEBUG_UNCOND("Candidate Queue Test"); - -#if 0 - DebugComponentEnable("CandidateQueue"); -#endif - - CandidateQueue candidate; - NS_ASSERT(candidate.Size () == 0); - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = new SPFVertex; - v->m_distanceFromRoot = rand () % 100; - candidate.Push (v); - } - - uint32_t lastDistance = 0; - bool ok = true; - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = candidate.Top (); - candidate.Pop (); - if (v->m_distanceFromRoot < lastDistance) - { - ok = false; - NS_ASSERT(0); - } - lastDistance = v->m_distanceFromRoot; - } - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = new SPFVertex; - v->m_distanceFromRoot = rand () % 100; - candidate.Push (v); - } - -#if 0 - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = candidate.Find (i); - if (v) { - v->m_distanceFromRoot = rand () % 100; - } - } -#endif - - candidate.Reorder (); - - lastDistance = 0; - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = candidate.Top (); - candidate.Pop (); - if (v->m_distanceFromRoot < lastDistance) - { - ok = false; - NS_ASSERT(0); - } - lastDistance = v->m_distanceFromRoot; - } - - NS_ASSERT(candidate.Size () == 0); - - return 0; -} diff --git a/src/routing/candidate-queue.cc b/src/routing/candidate-queue.cc index d34e49855..67bec63b1 100644 --- a/src/routing/candidate-queue.cc +++ b/src/routing/candidate-queue.cc @@ -57,7 +57,7 @@ CandidateQueue::Push (SPFVertex *vNew) for (; i != m_candidates.end (); i++) { SPFVertex *v = *i; - if (vNew->m_distanceFromRoot < v->m_distanceFromRoot) + if (vNew->GetDistanceFromRoot () < v->GetDistanceFromRoot ()) { break; } @@ -119,7 +119,7 @@ CandidateQueue::Find (const Ipv4Address addr) const for (; i != m_candidates.end (); i++) { SPFVertex *v = *i; - if (v->m_vertexId == addr) + if (v->GetVertexId() == addr) { return v; } diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 5e4aece04..408f2a91d 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -34,11 +34,11 @@ SPFVertex::SPFVertex () : m_vertexType (VertexUnknown), m_vertexId ("255.255.255.255"), m_lsa (0), - m_parent (0), - m_children (), m_distanceFromRoot (SPF_INFINITY), m_rootOif (SPF_INFINITY), - m_nextHop ("0.0.0.0") + m_nextHop ("0.0.0.0"), + m_parent (0), + m_children () { } @@ -46,19 +46,19 @@ SPFVertex::SPFVertex (StaticRouterLSA* lsa) : m_vertexType (VertexRouter), m_vertexId (lsa->GetLinkStateId ()), m_lsa (lsa), - m_parent (0), - m_children (), m_distanceFromRoot (SPF_INFINITY), m_rootOif (SPF_INFINITY), - m_nextHop ("0.0.0.0") + m_nextHop ("0.0.0.0"), + m_parent (0), + m_children () { } SPFVertex::~SPFVertex () { - for ( t_listOfSPFVertex::iterator i = m_children.begin (); - i != m_children.end (); - i++) + for ( ListOfSPFVertex_t::iterator i = m_children.begin (); + i != m_children.end (); + i++) { SPFVertex *p = *i; delete p; @@ -68,6 +68,128 @@ SPFVertex::~SPFVertex () m_children.clear (); } + void +SPFVertex::SetVertexType (SPFVertex::VertexType type) +{ + m_vertexType = type; +} + + SPFVertex::VertexType +SPFVertex::GetVertexType (void) const +{ + return m_vertexType; +} + + void +SPFVertex::SetVertexId (Ipv4Address id) +{ + m_vertexId = id; +} + + Ipv4Address +SPFVertex::GetVertexId (void) const +{ + return m_vertexId; +} + + void +SPFVertex::SetLSA (StaticRouterLSA* lsa) +{ + m_lsa = lsa; +} + + StaticRouterLSA* +SPFVertex::GetLSA (void) const +{ + return m_lsa; +} + + void +SPFVertex::SetDistanceFromRoot (uint32_t distance) +{ + m_distanceFromRoot = distance; +} + + uint32_t +SPFVertex::GetDistanceFromRoot (void) const +{ + return m_distanceFromRoot; +} + + void +SPFVertex::SetOutgoingInterfaceId (uint32_t id) +{ + m_rootOif = id; +} + + uint32_t +SPFVertex::GetOutgoingInterfaceId (void) const +{ + return m_rootOif; +} + + void +SPFVertex::SetNextHop (Ipv4Address nextHop) +{ + m_nextHop = nextHop; +} + + Ipv4Address +SPFVertex::GetNextHop (void) const +{ + return m_nextHop; +} + + void +SPFVertex::SetParent (SPFVertex* parent) +{ + m_parent = parent; +} + + SPFVertex* +SPFVertex::GetParent (void) const +{ + return m_parent; +} + + uint32_t +SPFVertex::GetNChildren (void) const +{ + return m_children.size (); +} + + SPFVertex* +SPFVertex::GetChild (uint32_t n) const +{ + uint32_t j = 0; + + for ( ListOfSPFVertex_t::const_iterator i = m_children.begin (); + i != m_children.end (); + i++, j++) + { + if (j == n) + { + return *i; + } + } + NS_ASSERT_MSG(false, "Index out of range."); + return 0; +} + + uint32_t +SPFVertex::AddChild (SPFVertex* child) +{ + m_children.push_back (child); + return m_children.size (); +} + +StaticRouteManagerLSDB::StaticRouteManagerLSDB () +: + m_database () +{ + NS_DEBUG ("StaticRouteManagerLSDB::StaticRouteManagerLSDB ()"); +} + StaticRouteManagerLSDB::~StaticRouteManagerLSDB () { NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); @@ -286,24 +408,24 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // // Always true for now, since all our LSAs are RouterLSAs. // - if (v->m_vertexType == SPFVertex::VertexRouter) + if (v->GetVertexType () == SPFVertex::VertexRouter) { if (true) { - NS_DEBUG ("SPFNext: Examining " << v->m_vertexId << "'s " << - v->m_lsa->GetNLinkRecords () << " link records"); + NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " << + v->GetLSA ()->GetNLinkRecords () << " link records"); // // Walk the list of link records in the link state advertisement associated // with the "current" router (represented by vertex ). // - for (uint32_t i = 0; i < v->m_lsa->GetNLinkRecords (); ++i) + for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) { // // (a) If this is a link to a stub network, examine the next link in V's LSA. // Links to stub networks will be considered in the second stage of the // shortest path calculation. // - StaticRouterLinkRecord *l = v->m_lsa->GetLinkRecord (i); + StaticRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) { NS_DEBUG ("SPFNext: Found a Stub record to " << @@ -324,7 +446,7 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); NS_ASSERT (w_lsa); NS_DEBUG ("SPFNext: Found a P2P record from " << - v->m_vertexId << " to " << w_lsa->GetLinkStateId ()); + v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); // // (c) If vertex W is already on the shortest-path tree, examine the next // link in the LSA. @@ -347,7 +469,7 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // calculated) shortest path to vertex V and the advertised cost of the link // between vertices V and W. // - distance = v->m_distanceFromRoot + l->GetMetric (); + distance = v->GetDistanceFromRoot () + l->GetMetric (); NS_DEBUG ("SPFNext: Considering w_lsa " << w_lsa->GetLinkStateId ()); @@ -375,8 +497,9 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // root node). // candidate.Push (w); - NS_DEBUG ("SPFNext: Pushing " << w->m_vertexId - << ", parent vertexId: " << v->m_vertexId); + NS_DEBUG ("SPFNext: Pushing " << + w->GetVertexId () << ", parent vertexId: " << + v->GetVertexId ()); } } } else if (w_lsa->GetStatus () == @@ -390,22 +513,22 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // So, locate the vertex in the candidate queue and take a look at the // distance. w = candidate.Find (w_lsa->GetLinkStateId ()); - if (w->m_distanceFromRoot < distance) + if (w->GetDistanceFromRoot () < distance) { // // This is not a shorter path, so don't do anything. // continue; } - else if (w->m_distanceFromRoot == distance) - { + else if (w->GetDistanceFromRoot () == distance) + { // // This path is one with an equal cost. Do nothing for now -- we're not doing // equal-cost multipath cases yet. // - } - else - { + } + else + { // // this path represents a new, lower-cost path to (the vertex we found in // the current link record of the link state advertisement of the current root @@ -414,15 +537,15 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // N.B. the nexthop_calculation is conditional, if it finds a valid nexthop // it will call spf_add_parents, which will flush the old parents // - if (SPFNexthopCalculation (v, w, l, distance)) - { + if (SPFNexthopCalculation (v, w, l, distance)) + { // // If we've changed the cost to get to the vertex represented by , we // must reorder the priority queue keyed to that cost. // - candidate.Reorder (); - } - } + candidate.Reorder (); + } + } } // point-to-point } // for loop } @@ -479,7 +602,7 @@ StaticRouteManager::SPFNexthopCalculation ( // node if this root node is a router. We then need to see if this node // is a router. // - if (w->m_vertexType == SPFVertex::VertexRouter) + if (w->GetVertexType () == SPFVertex::VertexRouter) { // // In the case of point-to-point links, the link data field (m_linkData) of a @@ -507,18 +630,19 @@ StaticRouteManager::SPFNexthopCalculation ( // from the root node to the host represented by vertex , you have to send // the packet to the next hop address specified in w->m_nextHop. // - w->m_nextHop = linkRemote->GetLinkData (); + w->SetNextHop(linkRemote->GetLinkData ()); // // Now find the outgoing interface corresponding to the point to point link // from the perspective of -- remember that is the link "from" // "to" . // - w->m_rootOif = FindOutgoingInterfaceId (l->GetLinkData ()); + w->SetOutgoingInterfaceId ( + FindOutgoingInterfaceId (l->GetLinkData ())); NS_DEBUG ("SPFNexthopCalculation: Next hop from " << - v->m_vertexId << " to " << w->m_vertexId << - " goes through next hop " << w->m_nextHop << - " via outgoing interface " << w->m_rootOif); + v->GetVertexId () << " to " << w->GetVertexId () << + " goes through next hop " << w->GetNextHop () << + " via outgoing interface " << w->GetOutgoingInterfaceId ()); } } else @@ -536,14 +660,14 @@ StaticRouteManager::SPFNexthopCalculation ( // (shortest) paths. So the next hop and outoing interface remain the same // (are inherited). // - w->m_nextHop = v->m_nextHop; - w->m_rootOif = v->m_rootOif; + w->SetNextHop (v->GetNextHop ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); } // // In all cases, we need valid values for the distance metric and a parent. // - w->m_distanceFromRoot = distance; - w->m_parent = v; + w->SetDistanceFromRoot (distance); + w->SetParent (v); return 1; } @@ -587,9 +711,9 @@ StaticRouteManager::SPFGetNextLink ( // looking for records representing the point-to-point links off of this // vertex. // - for (uint32_t i = 0; i < v->m_lsa->GetNLinkRecords (); ++i) + for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) { - l = v->m_lsa->GetLinkRecord (i); + l = v->GetLSA ()->GetLinkRecord (i); if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) { continue; @@ -602,7 +726,7 @@ StaticRouteManager::SPFGetNextLink ( // We're just checking to see if the link is actually the link from to // . // - if (l->GetLinkId () == w->m_vertexId) { + if (l->GetLinkId () == w->GetVertexId ()) { NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << l->GetLinkId () << " linkData = " << l->GetLinkData ()); // @@ -672,8 +796,8 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // We also mark this vertex as being in the SPF tree. // m_spfroot= v; - v->m_distanceFromRoot = 0; - v->m_lsa->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); + v->SetDistanceFromRoot (0); + v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); for (;;) { @@ -713,12 +837,12 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // the candidate list. // v = candidate.Pop (); - NS_DEBUG ("SPFCalculate: Popped vertex " << v->m_vertexId); + NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ()); // // Update the status field of the vertex to indicate that it is in the SPF // tree. // - v->m_lsa->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); + v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); // // The current vertex has a parent pointer. By calling this rather oddly // named method (blame quagga) we add the current vertex to the list of @@ -792,7 +916,7 @@ StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) // node in order to iterate the interfaces and find the one corresponding to // the address in question. // - Ipv4Address routerId = m_spfroot->m_vertexId; + Ipv4Address routerId = m_spfroot->GetVertexId (); // // Walk the list of nodes in the system looking for the one corresponding to // the node at the root of the SPF tree. This is the node for which we are @@ -878,7 +1002,7 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) // going to use this ID to discover which node it is that we're actually going // to update. // - Ipv4Address routerId = m_spfroot->m_vertexId; + Ipv4Address routerId = m_spfroot->GetVertexId (); NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ():" "Vertex ID = " << routerId); @@ -927,7 +1051,7 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) // Link Records corresponding to links off of that vertex / node. We're going // to be interested in the records corresponding to point-to-point links. // - StaticRouterLSA *lsa = v->m_lsa; + StaticRouterLSA *lsa = v->GetLSA (); NS_ASSERT_MSG (lsa, "StaticRouteManager::SPFIntraAddRouter (): " "Expected valid LSA in SPFVertex* v"); @@ -955,8 +1079,8 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " " Node " << node->GetId () << " add route to " << lr->GetLinkData () << - " using next hop " << v->m_nextHop << - " via interface " << v->m_rootOif); + " using next hop " << v->GetNextHop () << + " via interface " << v->GetOutgoingInterfaceId ()); // // Here's why we did all of that work. We're going to add a host route to the // host address found in the m_linkData field of the point-to-point link @@ -970,8 +1094,8 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) // Similarly, the vertex has an m_rootOif (outbound interface index) to // which the packets should be send for forwarding. // - ipv4->AddHostRouteTo (lr->GetLinkData (), v->m_nextHop, - v->m_rootOif); + ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (), + v->GetOutgoingInterfaceId ()); } } // @@ -994,8 +1118,10 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) void StaticRouteManager::SPFVertexAddParent (SPFVertex* v) { - // For now, only one parent (not doing equal-cost multipath) - v->m_parent->m_children.push_back (v); +// +// For now, only one parent (not doing equal-cost multipath) +// + v->GetParent ()->AddChild (v); } } // namespace ns3 @@ -1052,7 +1178,7 @@ StaticRouteManagerTest::RunTests (void) for (int i = 0; i < 100; ++i) { SPFVertex *v = new SPFVertex; - v->m_distanceFromRoot = rand () % 100; + v->SetDistanceFromRoot (rand () % 100); candidate.Push (v); } @@ -1061,11 +1187,11 @@ StaticRouteManagerTest::RunTests (void) for (int i = 0; i < 100; ++i) { SPFVertex *v = candidate.Pop (); - if (v->m_distanceFromRoot < lastDistance) + if (v->GetDistanceFromRoot () < lastDistance) { ok = false; } - lastDistance = v->m_distanceFromRoot; + lastDistance = v->GetDistanceFromRoot (); delete v; v = 0; } diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 2f47d0b40..a54cf2fdd 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -47,23 +47,58 @@ public: VertexUnknown = 0, VertexRouter, VertexNetwork - } m_vertexType; + }; + void SetVertexType (VertexType type); + VertexType GetVertexType (void) const; + + void SetVertexId (Ipv4Address idV); + Ipv4Address GetVertexId (void) const; + + void SetLSA (StaticRouterLSA* lsa); + StaticRouterLSA* GetLSA (void) const; + + void SetDistanceFromRoot (uint32_t distance); + uint32_t GetDistanceFromRoot (void) const; + + void SetOutgoingInterfaceId (uint32_t id); + uint32_t GetOutgoingInterfaceId (void) const; + + void SetNextHop (Ipv4Address nextHop); + Ipv4Address GetNextHop (void) const; + + void SetParent (SPFVertex* parent); + SPFVertex* GetParent (void) const; + + uint32_t GetNChildren (void) const; + SPFVertex* GetChild (uint32_t n) const; + + uint32_t AddChild (SPFVertex* child); + +private: + VertexType m_vertexType; Ipv4Address m_vertexId; // router id - StaticRouterLSA* m_lsa; // This pointer owns LSA for mem. mgmt purposes - - // need to keep track of current parent vertex - SPFVertex* m_parent; - // m_children lists the leaves from your SPF tree - typedef std::list t_listOfSPFVertex; - t_listOfSPFVertex m_children; - t_listOfSPFVertex::iterator m_SPFVertexIter; - uint32_t m_distanceFromRoot; uint32_t m_rootOif; Ipv4Address m_nextHop; + // need to keep track of current parent vertex + SPFVertex* m_parent; + + // m_children lists the leaves from your SPF tree + typedef std::list ListOfSPFVertex_t; + ListOfSPFVertex_t m_children; +/** + * The SPFVertex copy construction is disallowed. There's no need for + * it and a compiler provided shallow copy would be wrong. + */ + SPFVertex (SPFVertex& v); +/** + * The SPFVertex copy assignment operator is disallowed. There's no need for + * it and a compiler provided shallow copy would be wrong. + */ + SPFVertex& operator= (SPFVertex& v); }; /** @@ -72,6 +107,7 @@ public: class StaticRouteManagerLSDB { public: + StaticRouteManagerLSDB (); ~StaticRouteManagerLSDB (); void Insert(Ipv4Address addr, StaticRouterLSA* lsa); StaticRouterLSA* GetLSA (Ipv4Address addr); @@ -83,6 +119,17 @@ public: typedef std::map LSDBMap_t; typedef std::pair LSDBPair_t; LSDBMap_t m_database; +private: +/** + * StaticRouteManagerLSDB copy construction is disallowed. There's no + * need for it and a compiler provided shallow copy would be hopelessly wrong. + */ + StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); +/** + * The SPFVertex copy assignment operator is disallowed. There's no need for + * it and a compiler provided shallow copy would be wrong. + */ + StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); }; /** @@ -126,6 +173,18 @@ public: protected: private: +/** + * Static Route Manager copy construction is disallowed. There's no need for + * it and a compiler provided shallow copy would be hopelessly wrong. + * + */ + StaticRouteManager (StaticRouteManager& srm); +/** + * Static Router copy assignment operator is disallowed. There's no need for + * it and a compiler provided shallow copy would be hopelessly wrong. + */ + StaticRouteManager& operator= (StaticRouteManager& srm); + SPFVertex* m_spfroot; StaticRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); diff --git a/src/routing/static-router.h b/src/routing/static-router.h index f1e5252b0..6f3f66cc6 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -39,11 +39,11 @@ namespace ns3 { class StaticRouterLinkRecord { public: - /** - * Enumeration of the possible types of Static Router Link Records. These - * are defined in the OSPF spec. We currently only use PointToPoint and - * StubNetwork types. - */ +/** + * Enumeration of the possible types of Static Router Link Records. These + * are defined in the OSPF spec. We currently only use PointToPoint and + * StubNetwork types. + */ enum LinkType { Unknown = 0, /**< Uninitialized Link Record */ PointToPoint, /**< Record representing a point to point channel */ @@ -51,148 +51,151 @@ public: StubNetwork, /**< Record represents a leaf node network */ VirtualLink /**< Unused -- for future OSPF compatibility */ }; - /** - * Construct an empty ("uninitialized") Static Router Link Record. - * - * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0"; - * The Link Type is set to Unknown; - * The metric is set to 0. - */ +/** + * Construct an empty ("uninitialized") Static Router Link Record. + * + * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0"; + * The Link Type is set to Unknown; + * The metric is set to 0. + */ StaticRouterLinkRecord (); - /** - * Construct a fully uninitialized Static Router Link Record. - * - * @param linkType The type of link record to construct. - * @param linkId The link ID for the record. - * @param linkData The link data field for the record. - * @param metric The metric field for the record. - * @see LinkType - * @see SetLinkId - * @see SetLinkData - */ +/** + * Construct a fully uninitialized Static Router Link Record. + * + * @param linkType The type of link record to construct. + * @param linkId The link ID for the record. + * @param linkData The link data field for the record. + * @param metric The metric field for the record. + * @see LinkType + * @see SetLinkId + * @see SetLinkData + */ StaticRouterLinkRecord ( LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, uint32_t metric); - /** - * Destroy a Static Router Link Record. - * - * Currently does nothing. Here as a placeholder only. - */ +/** + * Destroy a Static Router Link Record. + * + * Currently does nothing. Here as a placeholder only. + */ ~StaticRouterLinkRecord (); - /** - * Get the Link ID field of the Static Router Link Record. - * - * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID - * of the neighboring router. - * - * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent - * neighbor's IP address - */ +/** + * Get the Link ID field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID + * of the neighboring router. + * + * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent + * neighbor's IP address + */ Ipv4Address GetLinkId(void) const; - /** - * Set the Link ID field of the Static Router Link Record. - * - * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID - * of the neighboring router. - * - * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent - * neighbor's IP address - */ +/** + * Set the Link ID field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID + * of the neighboring router. + * + * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent + * neighbor's IP address + */ void SetLinkId(Ipv4Address addr); - /** - * Get the Link Data field of the Static Router Link Record. - * - * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP - * address of the node of the local side of the link. - * - * For an OSPF type 3 link (StubNetwork), the Link Data will be the - * network mask - */ +/** + * Get the Link Data field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP + * address of the node of the local side of the link. + * + * For an OSPF type 3 link (StubNetwork), the Link Data will be the + * network mask + */ Ipv4Address GetLinkData(void) const; - /** - * Set the Link Data field of the Static Router Link Record. - * - * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP - * address of the node of the local side of the link. - * - * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the - * network mask - */ +/** + * Set the Link Data field of the Static Router Link Record. + * + * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP + * address of the node of the local side of the link. + * + * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the + * network mask + */ void SetLinkData(Ipv4Address addr); - /** - * Get the Link Type field of the Static Router Link Record. - * - * The Link Type describes the kind of link a given record represents. The - * values are defined by OSPF. - * - * @see LinkType - */ +/** + * Get the Link Type field of the Static Router Link Record. + * + * The Link Type describes the kind of link a given record represents. The + * values are defined by OSPF. + * + * @see LinkType + */ LinkType GetLinkType(void) const; - /** - * Set the Link Type field of the Static Router Link Record. - * - * The Link Type describes the kind of link a given record represents. The - * values are defined by OSPF. - * - * @see LinkType - */ +/** + * Set the Link Type field of the Static Router Link Record. + * + * The Link Type describes the kind of link a given record represents. The + * values are defined by OSPF. + * + * @see LinkType + */ void SetLinkType(LinkType linkType); - /** - * Get the Metric Data field of the Static Router Link Record. - * - * The metric is an abstract cost associated with forwarding a packet across - * a link. A sum of metrics must have a well-defined meaning. That is, you - * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of - * two hops relate to the cost of sending a packet); rather you should use - * something like delay. - */ +/** + * Get the Metric Data field of the Static Router Link Record. + * + * The metric is an abstract cost associated with forwarding a packet across + * a link. A sum of metrics must have a well-defined meaning. That is, you + * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of + * two hops relate to the cost of sending a packet); rather you should use + * something like delay. + */ uint32_t GetMetric(void) const; - /** - * Set the Metric Data field of the Static Router Link Record. - * - * The metric is an abstract cost associated with forwarding a packet across - * a link. A sum of metrics must have a well-defined meaning. That is, you - * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of - * two hops relate to the cost of sending a packet); rather you should use - * something like delay. - */ +/** + * Set the Metric Data field of the Static Router Link Record. + * + * The metric is an abstract cost associated with forwarding a packet across + * a link. A sum of metrics must have a well-defined meaning. That is, you + * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of + * two hops relate to the cost of sending a packet); rather you should use + * something like delay. + */ void SetMetric(uint32_t metric); private: - /** - * m_linkId and m_linkData are defined by OSPF to have different meanings - * depending on the type of link a given link records represents. They work - * together. - * - * For Type 1 link (PointToPoint), set m_linkId to Router ID of - * neighboring router. - * - * For Type 3 link (Stub), set m_linkId to neighbor's IP address - */ +/** + * m_linkId and m_linkData are defined by OSPF to have different meanings + * depending on the type of link a given link records represents. They work + * together. + * + * For Type 1 link (PointToPoint), set m_linkId to Router ID of + * neighboring router. + * + * For Type 3 link (Stub), set m_linkId to neighbor's IP address + */ Ipv4Address m_linkId; - /** - * m_linkId and m_linkData are defined by OSPF to have different meanings - * depending on the type of link a given link records represents. They work - * together. - * - * For Type 1 link (PointToPoint), set m_linkData to local IP address - * - * For Type 3 link (Stub), set m_linkData to mask - */ +/** + * m_linkId and m_linkData are defined by OSPF to have different meanings + * depending on the type of link a given link records represents. They work + * together. + * + * For Type 1 link (PointToPoint), set m_linkData to local IP address + * + * For Type 3 link (Stub), set m_linkData to mask + */ Ipv4Address m_linkData; // for links to RouterLSA, - +/** + * The type of the Static Router Link Record. Defined in the OSPF spec. + * We currently only use PointToPoint and StubNetwork types. + */ LinkType m_linkType; - /** - * The metric for a given link. - * - * A metric is abstract cost associated with forwarding a packet across a - * link. A sum of metrics must have a well-defined meaning. That is, you - * shouldn't use bandwidth as a metric (how does the sum of the bandwidth - * of two hops relate to the cost of sending a packet); rather you should - * use something like delay. - */ +/** + * The metric for a given link. + * + * A metric is abstract cost associated with forwarding a packet across a + * link. A sum of metrics must have a well-defined meaning. That is, you + * shouldn't use bandwidth as a metric (how does the sum of the bandwidth + * of two hops relate to the cost of sending a packet); rather you should + * use something like delay. + */ uint32_t m_metric; }; @@ -405,79 +408,79 @@ std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); class StaticRouter : public Object { public: - /** - * The Interface ID of the Static Router interface. - * - * @see Object::QueryInterface () - */ +/** + * The Interface ID of the Static Router interface. + * + * @see Object::QueryInterface () + */ static const InterfaceId iid; - /** - * Create a Static Router class and aggregate its interface onto the Node - * provided. - * - * @param node The existing Node onto which this router will be aggregated. - */ +/** + * Create a Static Router class and aggregate its interface onto the Node + * provided. + * + * @param node The existing Node onto which this router will be aggregated. + */ StaticRouter (Ptr node); - /** - * Get the Router ID associated with this Static Router. The Router IDs - * are allocated in the RoutingEnvironment -- one per Router, starting at - * 0.0.0.1 and incrementing with each instantiation of a router. - * - * @see RoutingEnvironment::AllocateRouterId () - * @returns The Router ID associated with the Static Router. - */ +/** + * Get the Router ID associated with this Static Router. The Router IDs + * are allocated in the RoutingEnvironment -- one per Router, starting at + * 0.0.0.1 and incrementing with each instantiation of a router. + * + * @see RoutingEnvironment::AllocateRouterId () + * @returns The Router ID associated with the Static Router. + */ Ipv4Address GetRouterId (void) const; - /** - * Walk the connected channels, discover the adjacent routers and build - * the associated number of Static Router Link State Advertisements that - * this router can export. - * - * This is a fairly expensive operation in that every time it is called - * the current list of LSAs is built by walking connected point-to-point - * channels and peeking into adjacent IPV4 stacks to get address information. - * This is done to allow for limited dymanics of the Static Routing - * environment. By that we mean that you can discover new link state - * advertisements after a network topology change by calling DiscoverLSAs - * and then by reading those advertisements. - * - * @see StaticRouterLSA - * @see StaticRouter::GetLSA () - * @returns The number of Static Router Link State Advertisements. - */ +/** + * Walk the connected channels, discover the adjacent routers and build + * the associated number of Static Router Link State Advertisements that + * this router can export. + * + * This is a fairly expensive operation in that every time it is called + * the current list of LSAs is built by walking connected point-to-point + * channels and peeking into adjacent IPV4 stacks to get address information. + * This is done to allow for limited dymanics of the Static Routing + * environment. By that we mean that you can discover new link state + * advertisements after a network topology change by calling DiscoverLSAs + * and then by reading those advertisements. + * + * @see StaticRouterLSA + * @see StaticRouter::GetLSA () + * @returns The number of Static Router Link State Advertisements. + */ uint32_t DiscoverLSAs (void); - /** - * Get the Number of Static Router Link State Advertisements that this - * router can export. To get meaningful information you must have - * previously called DiscoverLSAs. After you know how many LSAs are - * present in the router, you may call GetLSA () to retrieve the actual - * advertisement. - * - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @see StaticRouter::GetLSA () - * @returns The number of Static Router Link State Advertisements. - */ +/** + * Get the Number of Static Router Link State Advertisements that this + * router can export. To get meaningful information you must have + * previously called DiscoverLSAs. After you know how many LSAs are + * present in the router, you may call GetLSA () to retrieve the actual + * advertisement. + * + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @see StaticRouter::GetLSA () + * @returns The number of Static Router Link State Advertisements. + */ uint32_t GetNumLSAs (void) const; - /** - * Get a Static Router Link State Advertisements that this router has said - * that it can export. - * - * This is a fairly inexpensive expensive operation in that the hard work - * was done in GetNumLSAs. We just copy the indicated Static Router Link - * State Advertisement into the requested StaticRouterLSA object. - * - * You must call StaticRouter::GetNumLSAs before calling this method in - * order to discover the adjacent routers and build the advertisements. - * GetNumLSAs will return the number of LSAs this router advertises. - * The parameter n (requested LSA number) must be in the range 0 to - * GetNumLSAs() - 1. - * - * @see StaticRouterLSA - * @see StaticRouter::GetNumLSAs () - * @param n The index number of the LSA you want to read. - * @param lsa The StaticRouterLSA class to receive the LSA information. - * @returns The number of Static Router Link State Advertisements. - */ +/** + * Get a Static Router Link State Advertisements that this router has said + * that it can export. + * + * This is a fairly inexpensive expensive operation in that the hard work + * was done in GetNumLSAs. We just copy the indicated Static Router Link + * State Advertisement into the requested StaticRouterLSA object. + * + * You must call StaticRouter::GetNumLSAs before calling this method in + * order to discover the adjacent routers and build the advertisements. + * GetNumLSAs will return the number of LSAs this router advertises. + * The parameter n (requested LSA number) must be in the range 0 to + * GetNumLSAs() - 1. + * + * @see StaticRouterLSA + * @see StaticRouter::GetNumLSAs () + * @param n The index number of the LSA you want to read. + * @param lsa The StaticRouterLSA class to receive the LSA information. + * @returns The number of Static Router Link State Advertisements. + */ bool GetLSA (uint32_t n, StaticRouterLSA &lsa) const; protected: @@ -495,13 +498,13 @@ protected: Ipv4Address m_routerId; private: - /** - * Static Router copy construction is disallowed. - */ +/** + * Static Router copy construction is disallowed. + */ StaticRouter (StaticRouter& sr); - /** - * Static Router copy assignment operator is disallowed. - */ +/** + * Static Router copy assignment operator is disallowed. + */ StaticRouter& operator= (StaticRouter& sr); }; From f3523e838195ad30bf1587cde4c446bae97e1e5b Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 19 Jul 2007 22:48:50 -0700 Subject: [PATCH 072/278] last parts of general cleaup and commenting --- src/routing/candidate-queue.h | 18 +- src/routing/static-route-manager.cc | 86 ++-- src/routing/static-route-manager.h | 613 +++++++++++++++++++++++++--- src/routing/static-router.cc | 18 + src/routing/static-router.h | 16 +- 5 files changed, 643 insertions(+), 108 deletions(-) diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index e9c985287..5d8993f2e 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -24,7 +24,7 @@ namespace ns3 { /** - * \brief a Candidate Queue used in static routing. + * \brief A Candidate Queue used in static routing. * * The CandidateQueue is used in the OSPF shortest path computations. It * is a priority queue used to store candidates for the shortest path to a @@ -62,7 +62,7 @@ public: * * @see SPFVertex */ - void Clear (void); + void Clear (void); /** * Push a Shortest Path First Vertex pointer onto the queue according to the * priority scheme. @@ -75,7 +75,7 @@ public: * @see SPFVertex * @param vNew The Shortest Path First Vertex to add to the queue. */ - void Push (SPFVertex *vNew); + void Push (SPFVertex *vNew); /** * Pop the Shortest Path First Vertex pointer at the top of the queue. * The caller is given the responsiblity for releasing the resources @@ -85,7 +85,7 @@ public: * @see Top () * @returns The Shortest Path First Vertex pointer at the top of the queue. */ - SPFVertex* Pop (void); + SPFVertex* Pop (void); /** * Return the Shortest Path First Vertex pointer at the top of the queue. * This method does not pop the SPFVertex* off of the queue, it simply @@ -95,13 +95,13 @@ public: * @see Pop () * @returns The Shortest Path First Vertex pointer at the top of the queue. */ - SPFVertex* Top (void) const; + SPFVertex* Top (void) const; /** * Test the Candidate Queue to determine if it is empty. * * @returns True if the queue is empty, false otherwise. */ - bool Empty (void) const; + bool Empty (void) const; /** * Return the number of Shortest Path First Vertex pointers presently * stored in the Candidate Queue. @@ -109,7 +109,7 @@ public: * @see SPFVertex * @returns The number of SPFVertex* pointers in the Candidate Queue. */ - uint32_t Size (void) const; + uint32_t Size (void) const; /** * Searches the Candidate Queue for a Shortest Path First Vertex pointer * that points to a vertex having the given IP address. @@ -118,7 +118,7 @@ public: * @param addr The IP address to search for. * @returns The SPFVertex* pointer corresponding to the given IP address. */ - SPFVertex* Find (const Ipv4Address addr) const; + SPFVertex* Find (const Ipv4Address addr) const; /** * Reorders the Candidate Queue according to the priority scheme. On * completion, the top of the queue will hold the Shortest Path First @@ -131,7 +131,7 @@ public: * * @see SPFVertex */ - void Reorder (void); + void Reorder (void); protected: typedef std::list CandidateList_t; diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 408f2a91d..02948ac9c 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -30,6 +30,12 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); namespace ns3 { +// --------------------------------------------------------------------------- +// +// SPFVertex Implementation +// +// --------------------------------------------------------------------------- + SPFVertex::SPFVertex () : m_vertexType (VertexUnknown), m_vertexId ("255.255.255.255"), @@ -183,6 +189,12 @@ SPFVertex::AddChild (SPFVertex* child) return m_children.size (); } +// --------------------------------------------------------------------------- +// +// StaticRouteManagerLSDB Implementation +// +// --------------------------------------------------------------------------- + StaticRouteManagerLSDB::StaticRouteManagerLSDB () : m_database () @@ -205,7 +217,7 @@ StaticRouteManagerLSDB::~StaticRouteManagerLSDB () m_database.clear (); } -void + void StaticRouteManagerLSDB::Initialize () { NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); @@ -218,19 +230,21 @@ StaticRouteManagerLSDB::Initialize () } } -void + void StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) { NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); m_database.insert (LSDBPair_t (addr, lsa)); } -StaticRouterLSA* -StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) + StaticRouterLSA* +StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const { NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); - // Look up an LSA by its address - LSDBMap_t::iterator i; +// +// Look up an LSA by its address. +// + LSDBMap_t::const_iterator i; for (i= m_database.begin (); i!= m_database.end (); i++) { if (i->first == addr) @@ -241,7 +255,15 @@ StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) return 0; } -StaticRouteManager::StaticRouteManager () : m_spfroot (0) +// --------------------------------------------------------------------------- +// +// StaticRouteManager Implementation +// +// --------------------------------------------------------------------------- + +StaticRouteManager::StaticRouteManager () +: + m_spfroot (0) { m_lsdb = new StaticRouteManagerLSDB (); } @@ -256,7 +278,7 @@ StaticRouteManager::~StaticRouteManager () } } -void + void StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) { if (m_lsdb) @@ -273,7 +295,7 @@ StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) // add them to the Link State DataBase (LSDB) from which the routes will // ultimately be computed. // -void + void StaticRouteManager::BuildStaticRoutingDatabase () { NS_DEBUG ("StaticRouteManager::BuildStaticRoutingDatabase()"); @@ -356,7 +378,7 @@ StaticRouteManager::BuildStaticRoutingDatabase () // algorithm then iterates again. It terminates when the candidate // list becomes empty. // -void + void StaticRouteManager::InitializeRoutes () { NS_DEBUG ("StaticRouteManager::InitializeRoutes ()"); @@ -397,7 +419,7 @@ StaticRouteManager::InitializeRoutes () // vertices not already on the list. If a lower-cost path is found to a // vertex already on the candidate list, store the new (lower) cost. // -void + void StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) { SPFVertex* w = 0; @@ -561,7 +583,7 @@ StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) // // For now, this is greatly simplified from the quagga code // -int + int StaticRouteManager::SPFNexthopCalculation ( SPFVertex* v, SPFVertex* w, @@ -684,15 +706,14 @@ StaticRouteManager::SPFNexthopCalculation ( // to . If prev_link is not NULL, we return a Static Router Link Record // representing a possible *second* link from to . // -// BUGBUG This seems to be a bug? Shouldn't this function look for any link -// records after pre_link and not just after the first? +// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for +// any link records after pre_link and not just after the first? // -StaticRouterLinkRecord* + StaticRouterLinkRecord* StaticRouteManager::SPFGetNextLink ( SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* prev_link - ) + StaticRouterLinkRecord* prev_link) { NS_DEBUG ("StaticRouteManager::SPFGetNextLink ()"); @@ -760,14 +781,14 @@ StaticRouteManager::SPFGetNextLink ( // // Used for unit tests. // -void + void StaticRouteManager::DebugSPFCalculate (Ipv4Address root) { SPFCalculate (root); } // quagga ospf_spf_calculate -void + void StaticRouteManager::SPFCalculate (Ipv4Address root) { NS_DEBUG ("StaticRouteManager::SPFCalculate (): " @@ -870,11 +891,11 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) // root in order of distance from the root. For each of the vertices, we call // SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the // point-to-point Static Router Link Records (the links to nodes adjacent to -// the node represented by the vertex). We add a link to the IP address +// the node represented by the vertex). We add a route to the IP address // specified by the m_linkData field of each of those link records. This will // be the *local* IP address associated with the interface attached to the // link. We use the outbound interface and next hop information present in -// the vertex . +// the vertex which have possibly been inherited from the root. // // To summarize, we're going to look at the node represented by and loop // through its point-to-point links, adding a *host* route to the local IP @@ -901,11 +922,11 @@ StaticRouteManager::SPFCalculate (Ipv4Address root) } // -// XXX this should probably be a method on Ipv4 +// BUGBUG FIXME: This should probably be a method on Ipv4 // // Return the interface index corresponding to a given IP address // -uint32_t + uint32_t StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) { // @@ -988,7 +1009,7 @@ StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) // a destination IP address, reachable from the root, to which we add a host // route. // -void + void StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) { NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ()"); @@ -1115,12 +1136,11 @@ StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) // Given a pointer to a vertex, it links back to the vertex's parent that it // already has set and adds itself to that vertex's list of children. // -void -StaticRouteManager::SPFVertexAddParent (SPFVertex* v) -{ -// // For now, only one parent (not doing equal-cost multipath) // + void +StaticRouteManager::SPFVertexAddParent (SPFVertex* v) +{ v->GetParent ()->AddChild (v); } @@ -1128,6 +1148,12 @@ StaticRouteManager::SPFVertexAddParent (SPFVertex* v) #ifdef RUN_SELF_TESTS +// --------------------------------------------------------------------------- +// +// Unit Tests +// +// --------------------------------------------------------------------------- + #include "ns3/test.h" namespace ns3 { @@ -1147,7 +1173,7 @@ StaticRouterTestNode::StaticRouterTestNode () // Ptr ipv4 = Create (this); } -TraceResolver* + TraceResolver* StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) { return 0; @@ -1168,7 +1194,7 @@ StaticRouteManagerTest::StaticRouteManagerTest () StaticRouteManagerTest::~StaticRouteManagerTest () {} -bool + bool StaticRouteManagerTest::RunTests (void) { bool ok = true; diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index a54cf2fdd..67e120da4 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -32,140 +32,618 @@ const uint32_t SPF_INFINITY = 0xffffffff; class CandidateQueue; /** - * \brief Vertex used in shortest path first (SPF) computations + * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328, + * Section 16. * - * See RFC 2328, Section 16. + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is the SPFVertex representing the router that is having + * its routing tables set. The SPFVertex objects representing other routers + * or networks in the simulation are arranged in the SPF tree. It is this + * tree that represents the Shortest Paths to the other networks. + * + * Each SPFVertex has a pointer to the Static Router Link State Advertisement + * (LSA) that its underlying router has exported. Within these LSAs are + * Static Router Link Records that describe the point to point links from the + * underlying router to other nodes (represented by other SPFVertex objects) + * in the simulation topology. The combination of the arrangement of the + * SPFVertex objects in the SPF tree, along with the details of the link + * records that connect them provide the information required to construct the + * required routes. */ class SPFVertex { public: - SPFVertex(); - SPFVertex(StaticRouterLSA*); - ~SPFVertex(); - +/** + * @enum Enumeration of the possible types of SPFVertex objects. Currently + * we use VertexRouter to identify objects that represent a router in the + * simulation topology, and VertexNetwork to identify objects that represent + * a network. + */ enum VertexType { - VertexUnknown = 0, - VertexRouter, - VertexNetwork + VertexUnknown = 0, /**< Uninitialized Link Record */ + VertexRouter, /**< Vertex representing a router in the topology */ + VertexNetwork /**< Vertex representing a network in the topology */ }; - - void SetVertexType (VertexType type); +/** + * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First + * Vertex). + * + * The Vertex Type is set to VertexUnknown, the Vertex ID is set to + * 255.255.255.255, and the distance from root is set to infinity + * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to + * null as is the parent SPFVertex. The outgoing interface index is set to + * infinity, the next hop address is set to 0.0.0.0 and the list of children + * of the SPFVertex is initialized to empty. + * + * @see VertexType + */ + SPFVertex(); +/** + * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). + * + * The Vertex Type is initialized to VertexRouter and the Vertex ID is found + * from the Link State ID of the Link State Advertisement (LSA) passed as a + * parameter. The Link State ID is set to the Router ID of the advertising + * router. The referenced LSA (m_lsa) is set to the given LSA. Other than + * these members, initialization is as in the default constructor. + * of the SPFVertex is initialized to empty. + * + * @see SPFVertex::SPFVertex () + * @see VertexType + * @see StaticRouterLSA + * @param lsa The Link State Advertisement used for finding initial values. + */ + SPFVertex(StaticRouterLSA* lsa); +/** + * @brief Destroy an SPFVertex (Shortest Path First Vertex). + * + * The children vertices of the SPFVertex are recursively deleted. + * + * @see SPFVertex::SPFVertex () + */ + ~SPFVertex(); +/** + * @brief Get the Vertex Type field of a SPFVertex object. + * + * The Vertex Type describes the kind of simulation object a given SPFVertex + * represents. + * + * @see VertexType + * @returns The VertexType of the current SPFVertex object. + */ VertexType GetVertexType (void) const; - - void SetVertexId (Ipv4Address idV); +/** + * @brief Set the Vertex Type field of a SPFVertex object. + * + * The Vertex Type describes the kind of simulation object a given SPFVertex + * represents. + * + * @see VertexType + * @param The new VertexType for the current SPFVertex object. + */ + void SetVertexType (VertexType type); +/** + * @brief Get the Vertex ID field of a SPFVertex object. + * + * The Vertex ID uniquely identifies the simulation object a given SPFVertex + * represents. Typically, this is the Router ID for SPFVertex objects + * representing routers, and comes from the Link State Advertisement of a + * router aggregated to a node in the simulation. These IDs are allocated + * automatically by the routing environment and look like IP addresses + * beginning at 0.0.0.0 and monotonically increasing as new routers are + * instantiated. + * + * @returns The Ipv4Address Vertex ID of the current SPFVertex object. + */ Ipv4Address GetVertexId (void) const; - - void SetLSA (StaticRouterLSA* lsa); +/** + * @brief Set the Vertex ID field of a SPFVertex object. + * + * The Vertex ID uniquely identifies the simulation object a given SPFVertex + * represents. Typically, this is the Router ID for SPFVertex objects + * representing routers, and comes from the Link State Advertisement of a + * router aggregated to a node in the simulation. These IDs are allocated + * automatically by the routing environment and look like IP addresses + * beginning at 0.0.0.0 and monotonically increasing as new routers are + * instantiated. + * + * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. + */ + void SetVertexId (Ipv4Address id); +/** + * @brief Get the Static Router Link State Advertisement returned by the + * Static Router represented by this SPFVertex during the route discovery + * process. + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @returns A pointer to the StaticRouterLSA found by the router represented + * by this SPFVertex object. + */ StaticRouterLSA* GetLSA (void) const; - - void SetDistanceFromRoot (uint32_t distance); +/** + * @brief Set the Static Router Link State Advertisement returned by the + * Static Router represented by this SPFVertex during the route discovery + * process. + * + * @see SPFVertex::GetLSA () + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You + * must not delete the LSA after calling this method. + * @param A pointer to the StaticRouterLSA. + */ + void SetLSA (StaticRouterLSA* lsa); +/** + * @brief Get the distance from the root vertex to "this" SPFVertex object. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex to which + * a route is being calculated from the root. The distance from the root that + * we're asking for is the number of hops from the root vertex to the vertex + * in question. + * + * The distance is calculated during route discovery and is stored in a + * member variable. This method simply fetches that value. + * + * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex. + */ uint32_t GetDistanceFromRoot (void) const; - - void SetOutgoingInterfaceId (uint32_t id); +/** + * @brief Set the distance from the root vertex to "this" SPFVertex object. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex to which + * a route is being calculated from the root. The distance from the root that + * we're asking for is the number of hops from the root vertex to the vertex + * in question. + * + * @param distance The distance, in hops, from the root SPFVertex to "this" + * SPFVertex. + */ + void SetDistanceFromRoot (uint32_t distance); +/** + * @brief Get the interface ID that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The outgoing interface that we're asking for is the interface + * index on the root node that should be used to start packets along the + * path to "this" vertex. + * + * When initializing the root SPFVertex, the interface ID is determined by + * examining the Static Router Link Records of the Link State Advertisement + * generated by the root node's StaticRouter. These interfaces are used to + * forward packets off of the root's network down those links. As other + * vertices are discovered which are further away from the root, they will + * be accessible down one of the paths begun by a Static Router Link Record. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to the interface of that + * first hop. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, the root node is asking, "which of my local interfaces + * should I use to get a packet to the network or host represented by 'this' + * SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @returns The interface index to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ uint32_t GetOutgoingInterfaceId (void) const; - - void SetNextHop (Ipv4Address nextHop); +/** + * @brief Set the interface ID that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The outgoing interface that we're asking for is the interface + * index on the root node that should be used to start packets along the + * path to "this" vertex. + * + * When initializing the root SPFVertex, the interface ID is determined by + * examining the Static Router Link Records of the Link State Advertisement + * generated by the root node's StaticRouter. These interfaces are used to + * forward packets off of the root's network down those links. As other + * vertices are discovered which are further away from the root, they will + * be accessible down one of the paths begun by a Static Router Link Record. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to the interface of that + * first hop. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, we are letting the root node know which of its local + * interfaces it should use to get a packet to the network or host represented + * by "this" SPFVertex. + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @param id The interface index to use when forwarding packets to the host or + * network represented by "this" SPFVertex. + */ + void SetOutgoingInterfaceId (uint32_t id); +/** + * @brief Get the IP address that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The IP address that we're asking for is the address on the + * remote side of a link off of the root node that should be used as the + * destination for packets along the path to "this" vertex. + * + * When initializing the root SPFVertex, the IP address used when forwarding + * packets is determined by examining the Static Router Link Records of the + * Link State Advertisement generated by the root node's StaticRouter. This + * address is used to forward packets off of the root's network down those + * links. As other vertices / nodes are discovered which are further away + * from the root, they will be accessible down one of the paths via a link + * described by one of these Static Router Link Records. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to a first hop router down + * an interface. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, the root node is asking, "which router should I send a + * packet to in order to get that packet to the network or host represented + * by 'this' SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @returns The IP address to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ Ipv4Address GetNextHop (void) const; - - void SetParent (SPFVertex* parent); +/** + * @brief Set the IP address that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The IP address that we're asking for is the address on the + * remote side of a link off of the root node that should be used as the + * destination for packets along the path to "this" vertex. + * + * When initializing the root SPFVertex, the IP address used when forwarding + * packets is determined by examining the Static Router Link Records of the + * Link State Advertisement generated by the root node's StaticRouter. This + * address is used to forward packets off of the root's network down those + * links. As other vertices / nodes are discovered which are further away + * from the root, they will be accessible down one of the paths via a link + * described by one of these Static Router Link Records. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to a first hop router down + * an interface. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method we are telling the root node which router it should send + * should I send a packet to in order to get that packet to the network or + * host represented by 'this' SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @param nextHop The IP address to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + void SetNextHop (Ipv4Address nextHop); +/** + * @brief Get a pointer to the SPFVector that is the parent of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. + * + * This method returns a pointer to the parent node of "this" SPFVertex + * (both of which reside in that SPF tree). + * + * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex + * in the SPF tree. + */ SPFVertex* GetParent (void) const; - +/** + * @brief Set the pointer to the SPFVector that is the parent of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. + * + * This method sets the parent pointer of "this" SPFVertex (both of which + * reside in that SPF tree). + * + * @param parent A pointer to the SPFVertex that is the parent of "this" + * SPFVertex* in the SPF tree. + */ + void SetParent (SPFVertex* parent); +/** + * @brief Get the number of children of "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method returns the number of children of "this" SPFVertex (which + * reside in the SPF tree). + * + * @returns The number of children of "this" SPFVertex (which reside in the + * SPF tree). + */ uint32_t GetNChildren (void) const; +/** + * @brief Get a borrowed SPFVertex pointer to the specified child of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method the number of children of "this" SPFVertex (which reside in + * the SPF tree. + * + * @see SPFVertex::GetNChildren + * @param n The index (from 0 to the number of children minus 1) of the + * child SPFVertex to return. + * @warning The pointer returned by GetChild () is a borrowed pointer. You + * do not have any ownership of the underlying object and must not delete + * that object. + * @returns A pointer to the specified child SPFVertex (which resides in the + * SPF tree). + */ SPFVertex* GetChild (uint32_t n) const; - +/** + * @brief Get a borrowed SPFVertex pointer to the specified child of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method the number of children of "this" SPFVertex (which reside in + * the SPF tree. + * + * @see SPFVertex::GetNChildren + * @param n The index (from 0 to the number of children minus 1) of the + * child SPFVertex to return. + * @warning Ownership of the pointer added to the children of "this" + * SPFVertex is transferred to the "this" SPFVertex. You must not delete the + * (now) child SPFVertex after calling this method. + * @param child A pointer to the SPFVertex (which resides in the SPF tree) to + * be added to the list of children of "this" SPFVertex. + * @returns The number of children of "this" SPFVertex after the addition of + * the new child. + */ uint32_t AddChild (SPFVertex* child); private: VertexType m_vertexType; - Ipv4Address m_vertexId; // router id - StaticRouterLSA* m_lsa; // This pointer owns LSA for mem. mgmt purposes + Ipv4Address m_vertexId; + StaticRouterLSA* m_lsa; uint32_t m_distanceFromRoot; uint32_t m_rootOif; Ipv4Address m_nextHop; - - // need to keep track of current parent vertex SPFVertex* m_parent; - - // m_children lists the leaves from your SPF tree typedef std::list ListOfSPFVertex_t; ListOfSPFVertex_t m_children; /** - * The SPFVertex copy construction is disallowed. There's no need for + * @brief The SPFVertex copy construction is disallowed. There's no need for * it and a compiler provided shallow copy would be wrong. */ SPFVertex (SPFVertex& v); /** - * The SPFVertex copy assignment operator is disallowed. There's no need for - * it and a compiler provided shallow copy would be wrong. + * @brief The SPFVertex copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be wrong. */ SPFVertex& operator= (SPFVertex& v); }; /** - * \brief The Link State DataBase (LSDB) of a static router + * @brief The Link State DataBase (LSDB) of the Static Route Manager. + * + * Each node in the simulation participating in static routing has a + * StaticRouter interface. The primary job of this interface is to export + * Static Router Link State Advertisements (LSAs). These advertisements in + * turn contain a number of Static Router Link Records that describe the + * point to point links from the underlying node to other nodes (that will + * also export their own LSAs. + * + * This class implements a searchable database of LSAs gathered from every + * router in the simulation. */ class StaticRouteManagerLSDB { public: +/** + * @brief Construct an empty Static Router Manager Link State Database. + * + * The database map composing the Link State Database is initialized in + * this constructor. + */ StaticRouteManagerLSDB (); +/** + * @brief Destroy an empty Static Router Manager Link State Database. + * + * The database map is walked and all of the Link State Advertisements stored + * in the database are freed; then the database map itself is clear ()ed to + * release any remaining resources. + */ ~StaticRouteManagerLSDB (); +/** + * @brief Insert an IP address / Link State Advertisement pair into the Link + * State Database. + * + * The IPV4 address and the StaticRouterLSA given as parameters are converted + * to an STL pair and are inserted into the database map. + * + * @see StaticRouterLSA + * @see Ipv4Address + * @param addr The IP address associated with the LSA. Typically the Router + * ID. + * @param lsa A pointer to the Link State Advertisement for the router. + */ void Insert(Ipv4Address addr, StaticRouterLSA* lsa); - StaticRouterLSA* GetLSA (Ipv4Address addr); - /** - * \brief Set all LSA flags to an initialized state, for SPF computation - */ +/** + * @brief Look up the Link State Advertisement associated with the given + * IP Address. + * + * The database map is searched for the given IPV4 address and corresponding + * StaticRouterLSA is returned. + * + * @see StaticRouterLSA + * @see Ipv4Address + * @param addr The IP address associated with the LSA. Typically the Router + * ID. + * @returns A pointer to the Link State Advertisement for the router specified + * by the IP address addr. + */ + StaticRouterLSA* GetLSA (Ipv4Address addr) const; +/** + * @brief Set all LSA flags to an initialized state, for SPF computation + * + * This function walks the database and resets the status flags of all of the + * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done + * prior to each SPF calculation to reset the state of the SPFVertex structures + * that will reference the LSAs during the calculation. + * + * @see StaticRouterLSA + * @see SPFVertex + */ void Initialize (); +private: typedef std::map LSDBMap_t; typedef std::pair LSDBPair_t; + LSDBMap_t m_database; -private: /** - * StaticRouteManagerLSDB copy construction is disallowed. There's no + * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no * need for it and a compiler provided shallow copy would be hopelessly wrong. */ StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); /** - * The SPFVertex copy assignment operator is disallowed. There's no need for - * it and a compiler provided shallow copy would be wrong. + * @brief The SPFVertex copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be wrong. */ StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); }; /** - * \brief A global static router + * @brief A global static router * * This singleton object can query interface each node in the system * for a StaticRouter interface. For those nodes, it fetches one or - * more LSAs and stores them in a local database. Then, it - * can compute shortest paths on a per-node basis to all routers, and - * finally configure each of the node's forwarding tables. + * more Link State Advertisements and stores them in a local database. + * Then, it can compute shortest paths on a per-node basis to all routers, + * and finally configure each of the node's forwarding tables. * - * The design is guided by OSPFv2 RFC 2328 section 16.1.1 - * and quagga ospfd + * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. */ class StaticRouteManager : public Object { public: static const InterfaceId iid; StaticRouteManager (); - /** - * \brief Build routing database by gathering LSA from each routing node - */ +/** + * @brief Build the routing database by gathering Link State Advertisements + * from each node exporting a StaticRouter interface. + * + */ virtual void BuildStaticRoutingDatabase(); - /** - * \brief Compute routes using Dijkstra SPF computation, and populate - * per-node forwarding tables - */ +/** + * @brief Compute routes using a Dijkstra SPF computation and populate + * per-node forwarding tables + */ virtual void InitializeRoutes(); - - /** - * \brief Debugging routine; allow client code to supply a pre-built LSDB - */ +/** + * @brief Debugging routine; allow client code to supply a pre-built LSDB + */ void DebugUseLsdb (StaticRouteManagerLSDB*); - /** - * \brief Debugging routine; call the core SPF from the unit tests - */ +/** + * @brief Debugging routine; call the core SPF from the unit tests + */ void DebugSPFCalculate (Ipv4Address root); virtual ~StaticRouteManager (); @@ -174,14 +652,14 @@ protected: private: /** - * Static Route Manager copy construction is disallowed. There's no need for - * it and a compiler provided shallow copy would be hopelessly wrong. + * @brief Static Route Manager copy construction is disallowed. There's no + * need for it and a compiler provided shallow copy would be hopelessly wrong. * */ StaticRouteManager (StaticRouteManager& srm); /** - * Static Router copy assignment operator is disallowed. There's no need for - * it and a compiler provided shallow copy would be hopelessly wrong. + * @brief Static Router copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be hopelessly wrong. */ StaticRouteManager& operator= (StaticRouteManager& srm); @@ -196,7 +674,6 @@ private: StaticRouterLinkRecord* prev_link); void SPFIntraAddRouter(SPFVertex* v); uint32_t FindOutgoingInterfaceId(Ipv4Address a); - }; } // namespace ns3 diff --git a/src/routing/static-router.cc b/src/routing/static-router.cc index b70d865e1..82aa2c2e4 100644 --- a/src/routing/static-router.cc +++ b/src/routing/static-router.cc @@ -26,6 +26,12 @@ NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); namespace ns3 { +// --------------------------------------------------------------------------- +// +// StaticRouterLinkRecord Implementation +// +// --------------------------------------------------------------------------- + StaticRouterLinkRecord::StaticRouterLinkRecord () : m_linkId ("0.0.0.0"), @@ -113,6 +119,12 @@ StaticRouterLinkRecord::SetMetric (uint32_t metric) m_metric = metric; } +// --------------------------------------------------------------------------- +// +// StaticRouterLSA Implementation +// +// --------------------------------------------------------------------------- + StaticRouterLSA::StaticRouterLSA() : m_linkStateId("0.0.0.0"), @@ -297,6 +309,12 @@ std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa) return os; } +// --------------------------------------------------------------------------- +// +// StaticRouter Implementation +// +// --------------------------------------------------------------------------- + const InterfaceId StaticRouter::iid = MakeInterfaceId ("StaticRouter", Object::iid); diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 6f3f66cc6..24bceca70 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -60,7 +60,7 @@ public: */ StaticRouterLinkRecord (); /** - * Construct a fully uninitialized Static Router Link Record. + * Construct an initialized Static Router Link Record. * * @param linkType The type of link record to construct. * @param linkId The link ID for the record. @@ -89,6 +89,8 @@ public: * * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent * neighbor's IP address + * + * @returns The Ipv4Address corresponding to the Link ID field of the record. */ Ipv4Address GetLinkId(void) const; /** @@ -99,6 +101,8 @@ public: * * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent * neighbor's IP address + * + * @param An Ipv4Address to store in the Link ID field of the record. */ void SetLinkId(Ipv4Address addr); /** @@ -109,6 +113,8 @@ public: * * For an OSPF type 3 link (StubNetwork), the Link Data will be the * network mask + * + * @returns The Ipv4Address corresponding to the Link Data field of the record. */ Ipv4Address GetLinkData(void) const; /** @@ -119,6 +125,8 @@ public: * * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the * network mask + * + * @param An Ipv4Address to store in the Link Data field of the record. */ void SetLinkData(Ipv4Address addr); /** @@ -128,6 +136,7 @@ public: * values are defined by OSPF. * * @see LinkType + * @returns The LinkType of the current Static Router Link Record. */ LinkType GetLinkType(void) const; /** @@ -137,6 +146,7 @@ public: * values are defined by OSPF. * * @see LinkType + * @param linkType The new LinkType for the current Static Router Link Record. */ void SetLinkType(LinkType linkType); /** @@ -147,6 +157,8 @@ public: * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of * two hops relate to the cost of sending a packet); rather you should use * something like delay. + * + * @returns The metric field of the Static Router Link Record. */ uint32_t GetMetric(void) const; /** @@ -157,6 +169,8 @@ public: * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of * two hops relate to the cost of sending a packet); rather you should use * something like delay. + * + * @param metric The new metric for the current Static Router Link Record. */ void SetMetric(uint32_t metric); From ab93e1f56d3b9e4df08ccd1d23c591bfea49af47 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 19 Jul 2007 23:04:09 -0700 Subject: [PATCH 073/278] overlooked one --- src/routing/static-router.h | 130 +++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 24bceca70..85ec59fad 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -30,7 +30,7 @@ namespace ns3 { /** - * \brief A single link record for a link state advertisement. + * @brief A single link record for a link state advertisement. * * The StaticRouterLinkRecord is modeled after the OSPF link record field of * a Link State Advertisement. Right now we will only see two types of link @@ -40,8 +40,8 @@ class StaticRouterLinkRecord { public: /** - * Enumeration of the possible types of Static Router Link Records. These - * are defined in the OSPF spec. We currently only use PointToPoint and + * @enum Enumeration of the possible types of Static Router Link Records. + * These are defined in the OSPF spec. We currently only use PointToPoint and * StubNetwork types. */ enum LinkType { @@ -52,7 +52,7 @@ public: VirtualLink /**< Unused -- for future OSPF compatibility */ }; /** - * Construct an empty ("uninitialized") Static Router Link Record. + * @brief Construct an empty ("uninitialized") Static Router Link Record. * * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0"; * The Link Type is set to Unknown; @@ -76,7 +76,7 @@ public: Ipv4Address linkData, uint32_t metric); /** - * Destroy a Static Router Link Record. + * @brief Destroy a Static Router Link Record. * * Currently does nothing. Here as a placeholder only. */ @@ -94,7 +94,7 @@ public: */ Ipv4Address GetLinkId(void) const; /** - * Set the Link ID field of the Static Router Link Record. + * @brief Set the Link ID field of the Static Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID * of the neighboring router. @@ -106,7 +106,7 @@ public: */ void SetLinkId(Ipv4Address addr); /** - * Get the Link Data field of the Static Router Link Record. + * @brief Get the Link Data field of the Static Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP * address of the node of the local side of the link. @@ -118,7 +118,7 @@ public: */ Ipv4Address GetLinkData(void) const; /** - * Set the Link Data field of the Static Router Link Record. + * @brief Set the Link Data field of the Static Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP * address of the node of the local side of the link. @@ -130,7 +130,7 @@ public: */ void SetLinkData(Ipv4Address addr); /** - * Get the Link Type field of the Static Router Link Record. + * @brief Get the Link Type field of the Static Router Link Record. * * The Link Type describes the kind of link a given record represents. The * values are defined by OSPF. @@ -140,7 +140,7 @@ public: */ LinkType GetLinkType(void) const; /** - * Set the Link Type field of the Static Router Link Record. + * @brief Set the Link Type field of the Static Router Link Record. * * The Link Type describes the kind of link a given record represents. The * values are defined by OSPF. @@ -150,7 +150,7 @@ public: */ void SetLinkType(LinkType linkType); /** - * Get the Metric Data field of the Static Router Link Record. + * @brief Get the Metric Data field of the Static Router Link Record. * * The metric is an abstract cost associated with forwarding a packet across * a link. A sum of metrics must have a well-defined meaning. That is, you @@ -162,7 +162,7 @@ public: */ uint32_t GetMetric(void) const; /** - * Set the Metric Data field of the Static Router Link Record. + * @brief Set the Metric Data field of the Static Router Link Record. * * The metric is an abstract cost associated with forwarding a packet across * a link. A sum of metrics must have a well-defined meaning. That is, you @@ -214,7 +214,8 @@ private: }; /** - * \brief a Link State Advertisement (LSA) for a router, used in static routing + * @brief a Link State Advertisement (LSA) for a router, used in static + * routing. * * Roughly equivalent to a static incarnation of the OSPF link state header * combined with a list of Link Records. Since it's static, there's @@ -224,8 +225,8 @@ class StaticRouterLSA { public: /** - * Enumeration of the possible values of the status flag in the Router Link - * State Advertisements. + * @enum Enumeration of the possible values of the status flag in the Router + * Link State Advertisements. */ enum SPFStatus { LSA_SPF_NOT_EXPLORED = 0, /**< New vertex not yet considered */ @@ -233,14 +234,16 @@ public: LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */ }; /** - * Create a blank Static Router Link State Advertisement. On completion, - * any Ipv4Address variables initialized to 0.0.0.0 and the list of Link - * State Records is empty. + * @brief Create a blank Static Router Link State Advertisement. + * + * On completion Ipv4Address variables initialized to 0.0.0.0 and the + * list of Link State Records is empty. */ StaticRouterLSA(); /** - * Create an initialized Static Router Link State Advertisement. On - * completion the list of Link State Records is empty. + * @brief Create an initialized Static Router Link State Advertisement. + * + * On completion the list of Link State Records is empty. * * @param status The status to of the new LSA. * @param linkStateId The Ipv4Address for the link state ID field. @@ -249,7 +252,8 @@ public: StaticRouterLSA(SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr); /** - * Copy constructor for a Static Router Link State Advertisement. + * @brief Copy constructor for a Static Router Link State Advertisement. + * * Takes a piece of memory and constructs a semantically identical copy of * the given LSA. * @@ -257,12 +261,14 @@ public: */ StaticRouterLSA (StaticRouterLSA& lsa); /** - * Destroy an existing Static Router Link State Advertisement. Any Static - * router Link Records present in the list are freed. + * @brief Destroy an existing Static Router Link State Advertisement. + * + * Any Static Router Link Records present in the list are freed. */ ~StaticRouterLSA(); /** - * Assignment operator for a Static Router Link State Advertisement. + * @brief Assignment operator for a Static Router Link State Advertisement. + * * Takes an existing Static Router Link State Advertisement and overwrites * it to make a semantically identical copy of a given prototype LSA. * @@ -274,54 +280,56 @@ public: */ StaticRouterLSA& operator= (const StaticRouterLSA& lsa); /** - * Copy any Static Router Link Records in a given Static Router Link - * State Advertisement to the current LSA. Existing Link Records are not - * deleted -- this is a concatenation of Link Records. + * @brief Copy any Static Router Link Records in a given Static Router Link + * State Advertisement to the current LSA. + * + * Existing Link Records are not deleted -- this is a concatenation of Link + * Records. * * @see ClearLinkRecords () * @param lsa The LSA to copy the Link Records from. */ void CopyLinkRecords (const StaticRouterLSA& lsa); /** - * Add a given Static Router Link Record to the LSA. + * @brief Add a given Static Router Link Record to the LSA. * * @param lr The Static Router Link Record to be added. * @returns The number of link records in the list. */ uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); /** - * Return the number of Static Router Link Records in the LSA. + * @brief Return the number of Static Router Link Records in the LSA. * * @returns The number of link records in the list. */ uint32_t GetNLinkRecords (void) const; /** - * Return a pointer to the specified Static Router Link Record. + * @brief Return a pointer to the specified Static Router Link Record. * * @param n The LSA number desired. * @returns The number of link records in the list. */ StaticRouterLinkRecord* GetLinkRecord (uint32_t n) const; /** - * Release all of the Static Router Link Records present in the Static + * @brief Release all of the Static Router Link Records present in the Static * Router Link State Advertisement and make the list of link records empty. */ void ClearLinkRecords(void); /** - * Check to see of the list of Static Router Link Records present in the + * @brief Check to see if the list of Static Router Link Records present in the * Static Router Link State Advertisement is empty. * * @returns True if the list is empty, false otherwise. */ bool IsEmpty(void) const; /** - * Print the contents of the Static Router Link State Advertisement and + * @brief Print the contents of the Static Router Link State Advertisement and * any Static Router Link Records present in the list. Quite verbose. */ void Print (std::ostream &os) const; /** - * Get the Link State ID as defined by the OSPF spec. We always set it to - * the router ID of the router making the advertisement. + * @brief Get the Link State ID as defined by the OSPF spec. We always set it + * to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () * @see StaticRouter::GetRouterId () @@ -329,16 +337,16 @@ public: */ Ipv4Address GetLinkStateId (void) const; /** - * Set the Link State ID is defined by the OSPF spec. We always set it to - * the router ID of the router making the advertisement. + * @brief Set the Link State ID is defined by the OSPF spec. We always set it + * to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () * @see StaticRouter::GetRouterId () */ void SetLinkStateId (Ipv4Address addr); /** - * Get the Advertising Router as defined by the OSPF spec. We always set - * it to the router ID of the router making the advertisement. + * @brief Get the Advertising Router as defined by the OSPF spec. We always + * set it to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () * @see StaticRouter::GetRouterId () @@ -346,22 +354,22 @@ public: */ Ipv4Address GetAdvertisingRouter (void) const; /** - * Set the Advertising Router as defined by the OSPF spec. We always set - * it to the router ID of the router making the advertisement. + * @brief Set the Advertising Router as defined by the OSPF spec. We always + * set it to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () * @see StaticRouter::GetRouterId () */ void SetAdvertisingRouter (Ipv4Address rtr); /** - * Get the SPF status of the advertisement. + * @brief Get the SPF status of the advertisement. * * @see SPFStatus * @returns The SPFStatus of the LSA. */ SPFStatus GetStatus (void) const; /** - * Set the SPF status of the advertisement + * @brief Set the SPF status of the advertisement * * @see SPFStatus */ @@ -411,7 +419,7 @@ private: std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); /** - * \brief An interface aggregated to a node to provide static routing info + * @brief An interface aggregated to a node to provide static routing info * * An interface aggregated to a node that provides static routing information * to a global route manager. The presence of the interface indicates that @@ -423,29 +431,30 @@ class StaticRouter : public Object { public: /** - * The Interface ID of the Static Router interface. + * @brief The Interface ID of the Static Router interface. * * @see Object::QueryInterface () */ static const InterfaceId iid; /** - * Create a Static Router class and aggregate its interface onto the Node - * provided. + * @brief Create a Static Router class and aggregate its interface onto the + * Node provided. * * @param node The existing Node onto which this router will be aggregated. */ StaticRouter (Ptr node); /** - * Get the Router ID associated with this Static Router. The Router IDs - * are allocated in the RoutingEnvironment -- one per Router, starting at - * 0.0.0.1 and incrementing with each instantiation of a router. + * @brief Get the Router ID associated with this Static Router. + * + * The Router IDs are allocated in the RoutingEnvironment -- one per Router, + * starting at 0.0.0.1 and incrementing with each instantiation of a router. * * @see RoutingEnvironment::AllocateRouterId () * @returns The Router ID associated with the Static Router. */ Ipv4Address GetRouterId (void) const; /** - * Walk the connected channels, discover the adjacent routers and build + * @brief Walk the connected channels, discover the adjacent routers and build * the associated number of Static Router Link State Advertisements that * this router can export. * @@ -463,11 +472,12 @@ public: */ uint32_t DiscoverLSAs (void); /** - * Get the Number of Static Router Link State Advertisements that this - * router can export. To get meaningful information you must have - * previously called DiscoverLSAs. After you know how many LSAs are - * present in the router, you may call GetLSA () to retrieve the actual - * advertisement. + * @brief Get the Number of Static Router Link State Advertisements that this + * router can export. + * + * To get meaningful information you must have previously called DiscoverLSAs. + * After you know how many LSAs are present in the router, you may call + * GetLSA () to retrieve the actual advertisement. * * @see StaticRouterLSA * @see StaticRouter::DiscoverLSAs () @@ -476,8 +486,8 @@ public: */ uint32_t GetNumLSAs (void) const; /** - * Get a Static Router Link State Advertisements that this router has said - * that it can export. + * @brief Get a Static Router Link State Advertisements that this router has + * said that it can export. * * This is a fairly inexpensive expensive operation in that the hard work * was done in GetNumLSAs. We just copy the indicated Static Router Link @@ -513,11 +523,11 @@ protected: private: /** - * Static Router copy construction is disallowed. + * @brief Static Router copy construction is disallowed. */ StaticRouter (StaticRouter& sr); /** - * Static Router copy assignment operator is disallowed. + * @brief Static Router assignment operator is disallowed. */ StaticRouter& operator= (StaticRouter& sr); }; From 4d3d250d5ee6dfcfbd354628521411e662b2d9f0 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 20 Jul 2007 14:21:21 -0700 Subject: [PATCH 074/278] make static router a singleton, make implementation details private --- SConstruct | 4 +- examples/simple-static-routing.cc | 7 +- src/routing/candidate-queue.h | 2 +- src/routing/static-route-manager-impl.cc | 1382 ++++++++++++++++++++++ src/routing/static-route-manager-impl.h | 677 +++++++++++ src/routing/static-route-manager.cc | 1338 +-------------------- src/routing/static-route-manager.h | 626 +--------- 7 files changed, 2077 insertions(+), 1959 deletions(-) create mode 100644 src/routing/static-route-manager-impl.cc create mode 100644 src/routing/static-route-manager-impl.h diff --git a/SConstruct b/SConstruct index 8d8468c27..9c9a2567c 100644 --- a/SConstruct +++ b/SConstruct @@ -374,15 +374,17 @@ routing.add_sources([ 'routing-environment.cc', 'static-router.cc', 'static-route-manager.cc', + 'static-route-manager-impl.cc', 'candidate-queue.cc', ]) routing.add_headers ([ + 'candidate-queue.h', + 'static-route-manager-impl.h', ]) routing.add_inst_headers([ 'routing-environment.h', 'static-router.h', 'static-route-manager.h', - 'candidate-queue.h', ]) # utils diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 55200e7af..01848c92c 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -65,6 +65,7 @@ #include "ns3/ipv4-route.h" #include "ns3/p2p-topology.h" #include "ns3/onoff-application.h" +#include "ns3/routing-environment.h" #include "ns3/static-route-manager.h" using namespace ns3; @@ -84,6 +85,7 @@ int main (int argc, char *argv[]) DebugComponentEnable("StaticRouter"); DebugComponentEnable("StaticRouteManager"); #endif + DebugComponentEnable("StaticRouteManager"); // Set up some default values for the simulation. Use the Bind() // technique to tell the system what subclass of Queue to use, @@ -142,9 +144,8 @@ int main (int argc, char *argv[]) if (RoutingEnvironment::StaticRoutingEnabled()) { - Ptr routeManager = Create (); - routeManager->BuildStaticRoutingDatabase (); - routeManager->InitializeRoutes (); + StaticRouteManager::BuildStaticRoutingDatabase (); + StaticRouteManager::InitializeRoutes (); } // Create the OnOff application to send UDP datagrams of size diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index 5d8993f2e..27fcd01b4 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -19,7 +19,7 @@ #include #include -#include "static-route-manager.h" +#include "static-route-manager-impl.h" namespace ns3 { diff --git a/src/routing/static-route-manager-impl.cc b/src/routing/static-route-manager-impl.cc new file mode 100644 index 000000000..52f8d4b32 --- /dev/null +++ b/src/routing/static-route-manager-impl.cc @@ -0,0 +1,1382 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "ns3/assert.h" +#include "ns3/fatal-error.h" +#include "ns3/debug.h" +#include "ns3/node-list.h" +#include "ns3/ipv4.h" +#include "static-router.h" +#include "static-route-manager-impl.h" +#include "candidate-queue.h" + +NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); + +namespace ns3 { + +// --------------------------------------------------------------------------- +// +// SPFVertex Implementation +// +// --------------------------------------------------------------------------- + +SPFVertex::SPFVertex () : + m_vertexType (VertexUnknown), + m_vertexId ("255.255.255.255"), + m_lsa (0), + m_distanceFromRoot (SPF_INFINITY), + m_rootOif (SPF_INFINITY), + m_nextHop ("0.0.0.0"), + m_parent (0), + m_children () +{ +} + +SPFVertex::SPFVertex (StaticRouterLSA* lsa) : + m_vertexType (VertexRouter), + m_vertexId (lsa->GetLinkStateId ()), + m_lsa (lsa), + m_distanceFromRoot (SPF_INFINITY), + m_rootOif (SPF_INFINITY), + m_nextHop ("0.0.0.0"), + m_parent (0), + m_children () +{ +} + +SPFVertex::~SPFVertex () +{ + for ( ListOfSPFVertex_t::iterator i = m_children.begin (); + i != m_children.end (); + i++) + { + SPFVertex *p = *i; + delete p; + p = 0; + *i = 0; + } + m_children.clear (); +} + + void +SPFVertex::SetVertexType (SPFVertex::VertexType type) +{ + m_vertexType = type; +} + + SPFVertex::VertexType +SPFVertex::GetVertexType (void) const +{ + return m_vertexType; +} + + void +SPFVertex::SetVertexId (Ipv4Address id) +{ + m_vertexId = id; +} + + Ipv4Address +SPFVertex::GetVertexId (void) const +{ + return m_vertexId; +} + + void +SPFVertex::SetLSA (StaticRouterLSA* lsa) +{ + m_lsa = lsa; +} + + StaticRouterLSA* +SPFVertex::GetLSA (void) const +{ + return m_lsa; +} + + void +SPFVertex::SetDistanceFromRoot (uint32_t distance) +{ + m_distanceFromRoot = distance; +} + + uint32_t +SPFVertex::GetDistanceFromRoot (void) const +{ + return m_distanceFromRoot; +} + + void +SPFVertex::SetOutgoingInterfaceId (uint32_t id) +{ + m_rootOif = id; +} + + uint32_t +SPFVertex::GetOutgoingInterfaceId (void) const +{ + return m_rootOif; +} + + void +SPFVertex::SetNextHop (Ipv4Address nextHop) +{ + m_nextHop = nextHop; +} + + Ipv4Address +SPFVertex::GetNextHop (void) const +{ + return m_nextHop; +} + + void +SPFVertex::SetParent (SPFVertex* parent) +{ + m_parent = parent; +} + + SPFVertex* +SPFVertex::GetParent (void) const +{ + return m_parent; +} + + uint32_t +SPFVertex::GetNChildren (void) const +{ + return m_children.size (); +} + + SPFVertex* +SPFVertex::GetChild (uint32_t n) const +{ + uint32_t j = 0; + + for ( ListOfSPFVertex_t::const_iterator i = m_children.begin (); + i != m_children.end (); + i++, j++) + { + if (j == n) + { + return *i; + } + } + NS_ASSERT_MSG(false, "Index out of range."); + return 0; +} + + uint32_t +SPFVertex::AddChild (SPFVertex* child) +{ + m_children.push_back (child); + return m_children.size (); +} + +// --------------------------------------------------------------------------- +// +// StaticRouteManagerLSDB Implementation +// +// --------------------------------------------------------------------------- + +StaticRouteManagerLSDB::StaticRouteManagerLSDB () +: + m_database () +{ + NS_DEBUG ("StaticRouteManagerLSDB::StaticRouteManagerLSDB ()"); +} + +StaticRouteManagerLSDB::~StaticRouteManagerLSDB () +{ + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); + + LSDBMap_t::iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ():free LSA"); + StaticRouterLSA* temp = i->second; + delete temp; + } + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); + m_database.clear (); +} + + void +StaticRouteManagerLSDB::Initialize () +{ + NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); + + LSDBMap_t::iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + StaticRouterLSA* temp = i->second; + temp->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); + } +} + + void +StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) +{ + NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); + m_database.insert (LSDBPair_t (addr, lsa)); +} + + StaticRouterLSA* +StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const +{ + NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); +// +// Look up an LSA by its address. +// + LSDBMap_t::const_iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + if (i->first == addr) + { + return i->second; + } + } + return 0; +} + +// --------------------------------------------------------------------------- +// +// StaticRouteManagerImpl Implementation +// +// --------------------------------------------------------------------------- + +StaticRouteManagerImpl::StaticRouteManagerImpl () +: + m_spfroot (0) +{ + NS_DEBUG ("StaticRouteManagerImpl::StaticRoutemanagerImpl ()"); + m_lsdb = new StaticRouteManagerLSDB (); +} + +StaticRouteManagerImpl::~StaticRouteManagerImpl () +{ + NS_DEBUG ("StaticRouteManagerImpl::~StaticRouteManagerImpl ()"); + + if (m_lsdb) + { + delete m_lsdb; + } +} + + void +StaticRouteManagerImpl::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) +{ + NS_DEBUG ("StaticRouteManagerImpl::DebugUseLsdb ()"); + + if (m_lsdb) + { + delete m_lsdb; + } + m_lsdb = lsdb; +} + +// +// In order to build the routing database, we need to walk the list of nodes +// in the system and look for those that support the StaticRouter interface. +// These routers will export a number of Link State Advertisements (LSAs) +// that describe the links and networks that are "adjacent" (i.e., that are +// on the other side of a point-to-point link). We take these LSAs and put +// add them to the Link State DataBase (LSDB) from which the routes will +// ultimately be computed. +// + void +StaticRouteManagerImpl::BuildStaticRoutingDatabase () +{ + NS_DEBUG ("StaticRouteManagerImpl::BuildStaticRoutingDatabase()"); +// +// Walk the list of nodes looking for the StaticRouter Interface. +// + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); +// +// Ignore nodes that aren't participating in routing. +// + if (!rtr) + { + continue; + } +// +// You must call DiscoverLSAs () before trying to use any routing info or to +// update LSAs. DiscoverLSAs () drives the process of discovering routes in +// the StaticRouter. Afterward, you may use GetNumLSAs (), which is a very +// computationally inexpensive call. If you call GetNumLSAs () before calling +// DiscoverLSAs () will get zero as the number since no routes have been +// found. +// + uint32_t numLSAs = rtr->DiscoverLSAs (); + NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); + + for (uint32_t j = 0; j < numLSAs; ++j) + { + StaticRouterLSA* lsa = new StaticRouterLSA (); +// +// This is the call to actually fetch a Link State Advertisement from the +// router. +// + rtr->GetLSA (j, *lsa); + NS_DEBUG ("LSA " << j); + NS_DEBUG (*lsa); +// +// Write the newly discovered link state advertisement to the database. +// + m_lsdb->Insert (lsa->GetLinkStateId (), lsa); + } + } +} + +// +// For each node that is a static router (which is determined by the presence +// of an aggregated StaticRouter interface), run the Dijkstra SPF calculation +// on the database rooted at that router, and populate the node forwarding +// tables. +// +// This function parallels RFC2328, Section 16.1.1, and quagga ospfd +// +// This calculation yields the set of intra-area routes associated +// with an area (called hereafter Area A). A router calculates the +// shortest-path tree using itself as the root. The formation +// of the shortest path tree is done here in two stages. In the +// first stage, only links between routers and transit networks are +// considered. Using the Dijkstra algorithm, a tree is formed from +// this subset of the link state database. In the second stage, +// leaves are added to the tree by considering the links to stub +// networks. +// +// The area's link state database is represented as a directed graph. +// The graph's vertices are routers, transit networks and stub networks. +// +// The first stage of the procedure (i.e., the Dijkstra algorithm) +// can now be summarized as follows. At each iteration of the +// algorithm, there is a list of candidate vertices. Paths from +// the root to these vertices have been found, but not necessarily +// the shortest ones. However, the paths to the candidate vertex +// that is closest to the root are guaranteed to be shortest; this +// vertex is added to the shortest-path tree, removed from the +// candidate list, and its adjacent vertices are examined for +// possible addition to/modification of the candidate list. The +// algorithm then iterates again. It terminates when the candidate +// list becomes empty. +// + void +StaticRouteManagerImpl::InitializeRoutes () +{ + NS_DEBUG ("StaticRouteManagerImpl::InitializeRoutes ()"); +// +// Walk the list of nodes in the system. +// + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + { + Ptr node = *i; +// +// Look for the StaticRouter interface that indicates that the node is +// participating in routing. +// + Ptr rtr = + node->QueryInterface (StaticRouter::iid); +// +// if the node has a static router interface, then run the static routing +// algorithms. +// + if (rtr && rtr->GetNumLSAs () ) + { + SPFCalculate (rtr->GetRouterId ()); + } + } +} + +// +// This method is derived from quagga ospf_spf_next (). See RFC2328 Section +// 16.1 (2) for further details. +// +// We're passed a parameter that is a vertex which is already in the SPF +// tree. A vertex represents a router node. We also get a reference to the +// SPF candidate queue, which is a priority queue containing the shortest paths +// to the networks we know about. +// +// We examine the links in v's LSA and update the list of candidates with any +// vertices not already on the list. If a lower-cost path is found to a +// vertex already on the candidate list, store the new (lower) cost. +// + void +StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) +{ + SPFVertex* w = 0; + StaticRouterLSA* w_lsa = 0; + uint32_t distance = 0; + + NS_DEBUG ("StaticRouteManagerImpl::SPFNext ()"); +// +// Always true for now, since all our LSAs are RouterLSAs. +// + if (v->GetVertexType () == SPFVertex::VertexRouter) + { + if (true) + { + NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " << + v->GetLSA ()->GetNLinkRecords () << " link records"); +// +// Walk the list of link records in the link state advertisement associated +// with the "current" router (represented by vertex ). +// + for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) + { +// +// (a) If this is a link to a stub network, examine the next link in V's LSA. +// Links to stub networks will be considered in the second stage of the +// shortest path calculation. +// + StaticRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); + if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) + { + NS_DEBUG ("SPFNext: Found a Stub record to " << + l->GetLinkId ()); + continue; + } +// +// (b) Otherwise, W is a transit vertex (router or transit network). Look up +// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state +// database. +// + if (l->GetLinkType () == StaticRouterLinkRecord::PointToPoint) + { +// +// Lookup the link state advertisement of the new link -- we call it in +// the link state database. +// + w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); + NS_ASSERT (w_lsa); + NS_DEBUG ("SPFNext: Found a P2P record from " << + v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); +// +// (c) If vertex W is already on the shortest-path tree, examine the next +// link in the LSA. +// +// If the link is to a router that is already in the shortest path first tree +// then we have it covered -- ignore it. +// + if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_IN_SPFTREE) + { + NS_DEBUG ("SPFNext: Skipping-> LSA "<< + w_lsa->GetLinkStateId () << " already in SPF tree"); + continue; + } +// +// The link is to a router we haven't dealt with yet. +// +// (d) Calculate the link state cost D of the resulting path from the root to +// vertex W. D is equal to the sum of the link state cost of the (already +// calculated) shortest path to vertex V and the advertised cost of the link +// between vertices V and W. +// + distance = v->GetDistanceFromRoot () + l->GetMetric (); + + NS_DEBUG ("SPFNext: Considering w_lsa " << + w_lsa->GetLinkStateId ()); + + if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + { +// +// If we havent yet considered the link represented by we have to create +// a new SPFVertex to represent it. +// + w = new SPFVertex (w_lsa); +// +// We need to figure out how to actually get to the new router represented +// by . This will (among other things) find the next hop address to send +// packets destined for this network to, and also find the outbound interface +// used to forward the packets. +// + if (SPFNexthopCalculation (v, w, l, distance)) + { + w_lsa->SetStatus ( + StaticRouterLSA::LSA_SPF_CANDIDATE); +// +// Push this new vertex onto the priority queue (ordered by distance from the +// root node). +// + candidate.Push (w); + NS_DEBUG ("SPFNext: Pushing " << + w->GetVertexId () << ", parent vertexId: " << + v->GetVertexId ()); + } + } + } else if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_CANDIDATE) + { +// +// We have already considered the link represented by . What wse have to +// do now is to decide if this new router represents a route with a shorter +// distance metric. +// +// So, locate the vertex in the candidate queue and take a look at the +// distance. + w = candidate.Find (w_lsa->GetLinkStateId ()); + if (w->GetDistanceFromRoot () < distance) + { +// +// This is not a shorter path, so don't do anything. +// + continue; + } + else if (w->GetDistanceFromRoot () == distance) + { +// +// This path is one with an equal cost. Do nothing for now -- we're not doing +// equal-cost multipath cases yet. +// + } + else + { +// +// this path represents a new, lower-cost path to (the vertex we found in +// the current link record of the link state advertisement of the current root +// (vertex ) +// +// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop +// it will call spf_add_parents, which will flush the old parents +// + if (SPFNexthopCalculation (v, w, l, distance)) + { +// +// If we've changed the cost to get to the vertex represented by , we +// must reorder the priority queue keyed to that cost. +// + candidate.Reorder (); + } + } + } // point-to-point + } // for loop + } + } +} + +// +// This method is derived from quagga ospf_next_hop_calculation() 16.1.1. +// +// Calculate the next hop IP address and the outgoing interface required to +// get packets from the root through (parent) to vertex (destination), +// over a given distance. +// +// For now, this is greatly simplified from the quagga code +// + int +StaticRouteManagerImpl::SPFNexthopCalculation ( + SPFVertex* v, + SPFVertex* w, + StaticRouterLinkRecord* l, + uint32_t distance) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFNexthopCalculation ()"); +// +// The vertex m_spfroot is a distinguished vertex representing the node at +// the root of the calculations. That is, it is the node for which we are +// calculating the routes. +// +// There are two distinct cases for calculating the next hop information. +// First, if we're considering a hop from the root to an "adjacent" network +// (one that is on the other side of a point-to-point link connected to the +// root), then we need to store the information needed to forward down that +// link. The second case is if the network is not directly adjacent. In that +// case we need to use the forwarding information from the vertex on the path +// to the destination that is directly adjacent [node 1] in both cases of the +// diagram below. +// +// (1) [root] -> [point-to-point] -> [node 1] +// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2] +// +// We call the propagation of next hop information down vertices of a path +// "inheriting" the next hop information. +// +// The point-to-point link information is only useful in this calculation when +// we are examining the root node. +// + if (v == m_spfroot) + { +// +// In this case is the root node, which means it is the starting point +// for the packets forwarded by that node. This also means that the next hop +// address of packets headed for some arbitrary off-network destination must +// be the destination at the other end of one of the links off of the root +// node if this root node is a router. We then need to see if this node +// is a router. +// + if (w->GetVertexType () == SPFVertex::VertexRouter) + { +// +// In the case of point-to-point links, the link data field (m_linkData) of a +// Static Router Link Record contains the local IP address. If we look at the +// link record describing the link from the perspecive of (the remote +// node from the viewpoint of ) back to the root node, we can discover the +// IP address of the router to which is adjacent. This is a distinguished +// address -- the next hop address to get from to and all networks +// accessed through that path. +// +// SPFGetNextLink () is a little odd. used in this way it is just going to +// return the link record describing the link from to . Think of it as +// SPFGetLink. +// + StaticRouterLinkRecord *linkRemote = 0; + linkRemote = SPFGetNextLink (w, v, linkRemote); +// +// At this point, is the Static Router Link Record describing the point- +// to point link from to from the perspective of ; and +// is the Static Router Link Record describing that same link from the +// perspective of (back to ). Now we can just copy the next hop +// address from the m_linkData member variable. +// +// The next hop member variable we put in has the sense "in order to get +// from the root node to the host represented by vertex , you have to send +// the packet to the next hop address specified in w->m_nextHop. +// + w->SetNextHop(linkRemote->GetLinkData ()); +// +// Now find the outgoing interface corresponding to the point to point link +// from the perspective of -- remember that is the link "from" +// "to" . +// + w->SetOutgoingInterfaceId ( + FindOutgoingInterfaceId (l->GetLinkData ())); + + NS_DEBUG ("SPFNexthopCalculation: Next hop from " << + v->GetVertexId () << " to " << w->GetVertexId () << + " goes through next hop " << w->GetNextHop () << + " via outgoing interface " << w->GetOutgoingInterfaceId ()); + } + } + else + { +// +// If we're calculating the next hop information from a node (v) that is +// *not* the root, then we need to "inherit" the information needed to +// forward the packet from the vertex closer to the root. That is, we'll +// still send packets to the next hop address of the router adjacent to the +// root on the path toward . +// +// Above, when we were considering the root node, we calculated the next hop +// address and outgoing interface required to get off of the root network. +// At this point, we are further away from the root network along one of the +// (shortest) paths. So the next hop and outoing interface remain the same +// (are inherited). +// + w->SetNextHop (v->GetNextHop ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); + } +// +// In all cases, we need valid values for the distance metric and a parent. +// + w->SetDistanceFromRoot (distance); + w->SetParent (v); + + return 1; +} + +// +// This method is derived from quagga ospf_get_next_link () +// +// First search the Static Router Link Records of vertex for one +// representing a point-to point link to vertex . +// +// What is done depends on prev_link. Contrary to appearances, prev_link just +// acts as a flag here. If prev_link is NULL, we return the first Static +// Router Link Record we find that describes a point-to-point link from +// to . If prev_link is not NULL, we return a Static Router Link Record +// representing a possible *second* link from to . +// +// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for +// any link records after pre_link and not just after the first? +// + StaticRouterLinkRecord* +StaticRouteManagerImpl::SPFGetNextLink ( + SPFVertex* v, + SPFVertex* w, + StaticRouterLinkRecord* prev_link) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFGetNextLink ()"); + + bool skip = true; + StaticRouterLinkRecord* l; +// +// If prev_link is 0, we are really looking for the first link, not the next +// link. +// + if (prev_link == 0) + { + skip = false; + } +// +// Iterate through the Static Router Link Records advertised by the vertex +// looking for records representing the point-to-point links off of this +// vertex. +// + for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) + { + l = v->GetLSA ()->GetLinkRecord (i); + if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) + { + continue; + } +// +// The link ID of a link record representing a point-to-point link is set to +// the router ID of the neighboring router -- the router to which the link +// connects from the perspective of in this case. The vertex ID is also +// set to the router ID (using the link state advertisement of a router node). +// We're just checking to see if the link is actually the link from to +// . +// + if (l->GetLinkId () == w->GetVertexId ()) { + NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << + l->GetLinkId () << " linkData = " << l->GetLinkData ()); +// +// If skip is false, don't (not too surprisingly) skip the link found -- it's +// the one we're interested in. That's either because we didn't pass in a +// previous link, and we're interested in the first one, or because we've +// skipped a previous link and moved forward to the next (which is then the +// one we want). +// + if (skip == false) + { + NS_DEBUG ("SPFGetNextLink: Returning the found link"); + return l; + } + else + { +// +// Skip is true and we've found a link from to . We want the next one. +// Setting skip to false gets us the next point-to-point static router link +// record in the LSA from . +// + NS_DEBUG ("SPFGetNextLink: Skipping the found link"); + skip = false; + continue; + } + } + } + return 0; +} + +// +// Used for unit tests. +// + void +StaticRouteManagerImpl::DebugSPFCalculate (Ipv4Address root) +{ + NS_DEBUG ("StaticRouteManagerImpl::DebugSPFCalculate ()"); + SPFCalculate (root); +} + +// quagga ospf_spf_calculate + void +StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFCalculate (): " + "root = " << root); + + SPFVertex *v; +// +// Initialize the Link State Database. +// + m_lsdb->Initialize (); +// +// The candidate queue is a priority queue of SPFVertex objects, with the top +// of the queue being the closest vertex in terms of distance from the root +// of the tree. Initially, this queue is empty. +// + CandidateQueue candidate; + NS_ASSERT(candidate.Size () == 0); +// +// Initialize the shortest-path tree to only contain the router doing the +// calculation. Each router (and corresponding network) is a vertex in the +// shortest path first (SPF) tree. +// + v = new SPFVertex (m_lsdb->GetLSA (root)); +// +// This vertex is the root of the SPF tree and it is distance 0 from the root. +// We also mark this vertex as being in the SPF tree. +// + m_spfroot= v; + v->SetDistanceFromRoot (0); + v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); + + for (;;) + { +// +// The operations we need to do are given in the OSPF RFC which we reference +// as we go along. +// +// RFC2328 16.1. (2). +// +// We examine the Static Router Link Records in the Link State +// Advertisements of the current vertex. If there are any point-to-point +// links to unexplored adjacent vertices we add them to the tree and update +// the distance and next hop information on how to get there. We also add +// the new vertices to the candidate queue (the priority queue ordered by +// shortest path). If the new vertices represent shorter paths, we use them +// and update the path cost. +// + SPFNext (v, candidate); +// +// RFC2328 16.1. (3). +// +// If at this step the candidate list is empty, the shortest-path tree (of +// transit vertices) has been completely built and this stage of the +// procedure terminates. +// + if (candidate.Size () == 0) + { + break; + } +// +// Choose the vertex belonging to the candidate list that is closest to the +// root, and add it to the shortest-path tree (removing it from the candidate +// list in the process). +// +// Recall that in the previous step, we created SPFVertex structures for each +// of the routers found in the Static Router Link Records and added tehm to +// the candidate list. +// + v = candidate.Pop (); + NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ()); +// +// Update the status field of the vertex to indicate that it is in the SPF +// tree. +// + v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); +// +// The current vertex has a parent pointer. By calling this rather oddly +// named method (blame quagga) we add the current vertex to the list of +// children of that parent vertex. In the next hop calculation called during +// SPFNext, the parent pointer was set but the vertex has been orphaned up +// to now. +// + SPFVertexAddParent (v); +// +// Note that when there is a choice of vertices closest to the root, network +// vertices must be chosen before router vertices in order to necessarily +// find all equal-cost paths. We don't do this at this moment, we should add +// the treatment above codes. -- kunihiro. +// +// RFC2328 16.1. (4). +// +// This is the method that actually adds the routes. It'll walk the list +// of nodes in the system, looking for the node corresponding to the router +// ID of the root of the tree -- that is the router we're building the routes +// for. It looks for the Ipv4 interface of that node and remembers it. So +// we are only actually adding routes to that one node at the root of the SPF +// tree. +// +// We're going to pop of a pointer to every vertex in the tree except the +// root in order of distance from the root. For each of the vertices, we call +// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the +// point-to-point Static Router Link Records (the links to nodes adjacent to +// the node represented by the vertex). We add a route to the IP address +// specified by the m_linkData field of each of those link records. This will +// be the *local* IP address associated with the interface attached to the +// link. We use the outbound interface and next hop information present in +// the vertex which have possibly been inherited from the root. +// +// To summarize, we're going to look at the node represented by and loop +// through its point-to-point links, adding a *host* route to the local IP +// address (at the side) for each of those links. +// + SPFIntraAddRouter (v); +// +// RFC2328 16.1. (5). +// +// Iterate the algorithm by returning to Step 2 until there are no more +// candidate vertices. +// + } +// +// Second stage of SPF calculation procedure's +// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); +// +// We're all done setting the routing information for the node at the root of +// the SPF tree. Delete all of the vertices and corresponding resources. Go +// possibly do it again for the next router. +// + delete m_spfroot; + m_spfroot = 0; +} + +// +// BUGBUG FIXME: This should probably be a method on Ipv4 +// +// Return the interface index corresponding to a given IP address +// + uint32_t +StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) +{ +// +// We have an IP address and a vertex ID of the root of the SPF tree. +// The question is what interface index does this address correspond to. +// The answer is a little complicated since we have to find a pointer to +// the node corresponding to the vertex ID, find the Ipv4 interface on that +// node in order to iterate the interfaces and find the one corresponding to +// the address in question. +// + Ipv4Address routerId = m_spfroot->GetVertexId (); +// +// Walk the list of nodes in the system looking for the one corresponding to +// the node at the root of the SPF tree. This is the node for which we are +// building the routing table. +// + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); +// +// If the node doesn't have a StaticRouter interface it can't be the one +// we're interested in. +// + if (rtr == 0) + { + continue; + } + + if (rtr->GetRouterId () == routerId) + { +// +// This is the node we're building the routing table for. We're going to need +// the Ipv4 interface to look for the ipv4 interface index. Since this node +// is participating in routing IP version 4 packets, it certainly must have +// an Ipv4 interface. +// + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG (ipv4, + "StaticRouteManagerImpl::FindOutgoingInterfaceId (): " + "QI for interface failed"); +// +// Look through the interfaces on this node for one that has the IP address +// we're looking for. If we find one, return the corresponding interface +// index. +// + for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) + { + if (ipv4->GetAddress (i) == a) + { + NS_DEBUG ( + "StaticRouteManagerImpl::FindOutgoingInterfaceId (): " + "Interface match for " << a); + return i; + } + } + } + } +// +// Couldn't find it. +// + return 0; +} + +// +// This method is derived from quagga ospf_intra_add_router () +// +// This is where we are actually going to add the host routes to the routing +// tables of the individual nodes. +// +// The vertex passed as a parameter has just been added to the SPF tree. +// This vertex must have a valid m_root_oid, corresponding to the outgoing +// interface on the root router of the tree that is the first hop on the path +// to the vertex. The vertex must also have a next hop address, corresponding +// to the next hop on the path to the vertex. The vertex has an m_lsa field +// that has some number of link records. For each point to point link record, +// the m_linkData is the local IP address of the link. This corresponds to +// a destination IP address, reachable from the root, to which we add a host +// route. +// + void +StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter ()"); + + NS_ASSERT_MSG (m_spfroot, + "StaticRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set"); +// +// The root of the Shortest Path First tree is the router to which we are +// going to write the actual routing table entries. The vertex corresponding +// to this router has a vertex ID which is the router ID of that node. We're +// going to use this ID to discover which node it is that we're actually going +// to update. +// + Ipv4Address routerId = m_spfroot->GetVertexId (); + + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "Vertex ID = " << routerId); +// +// We need to walk the list of nodes looking for the one that has the router +// ID corresponding to the root vertex. This is the one we're going to write +// the routing information to. +// + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) + { + Ptr node = *i; +// +// The router ID is accessible through the StaticRouter interface, so we need +// to QI for that interface. If there's no StaticRouter interface, the node +// in question cannot be the router we want, so we continue. +// + Ptr rtr = + node->QueryInterface (StaticRouter::iid); + + if (rtr == 0) + { + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "No StaticRouter interface on node " << node->GetId ()); + continue; + } +// +// If the router ID of the current node is equal to the router ID of the +// root of the SPF tree, then this node is the one for which we need to +// write the routing tables. +// + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "Considering router " << rtr->GetRouterId ()); + + if (rtr->GetRouterId () == routerId) + { + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "setting routes for node " << node->GetId ()); +// +// Routing information is updated using the Ipv4 interface. We need to QI +// for that interface. If the node is acting as an IP version 4 router, it +// should absolutely have an Ipv4 interface. +// + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG (ipv4, + "StaticRouteManagerImpl::SPFIntraAddRouter (): " + "QI for interface failed"); +// +// Get the Static Router Link State Advertisement from the vertex we're +// adding the routes to. The LSA will have a number of attached Static Router +// Link Records corresponding to links off of that vertex / node. We're going +// to be interested in the records corresponding to point-to-point links. +// + StaticRouterLSA *lsa = v->GetLSA (); + NS_ASSERT_MSG (lsa, + "StaticRouteManagerImpl::SPFIntraAddRouter (): " + "Expected valid LSA in SPFVertex* v"); + + uint32_t nLinkRecords = lsa->GetNLinkRecords (); +// +// Iterate through the link records on the vertex to which we're going to add +// routes. To make sure we're being clear, we're going to add routing table +// entries to the tables on the node corresping to the root of the SPF tree. +// These entries will have routes to the IP addresses we find from looking at +// the local side of the point-to-point links found on the node described by +// the vertex . +// + for (uint32_t j = 0; j < nLinkRecords; j += 2) + { +// +// We are only concerned about point-to-point links +// + StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); + if (lr->GetLinkType () != StaticRouterLinkRecord::PointToPoint) + { + continue; + } + + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + " Node " << node->GetId () << + " add route to " << lr->GetLinkData () << + " using next hop " << v->GetNextHop () << + " via interface " << v->GetOutgoingInterfaceId ()); +// +// Here's why we did all of that work. We're going to add a host route to the +// host address found in the m_linkData field of the point-to-point link +// record. In the case of a point-to-point link, this is the local IP address +// of the node connected to the link. Each of these point-to-point links +// will correspond to a local interface that has an IP address to which +// the node at the root of the SPF tree can send packets. The vertex +// (corresponding to the node that has these links and interfaces) has +// an m_nextHop address precalculated for us that is the address to which the +// root node should send packets to be forwarded to these IP addresses. +// Similarly, the vertex has an m_rootOif (outbound interface index) to +// which the packets should be send for forwarding. +// + ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (), + v->GetOutgoingInterfaceId ()); + } +// +// Done adding the routes for the selected node. +// + return; + } + } +} + +// Derived from quagga ospf_vertex_add_parents () +// +// This is a somewhat oddly named method (blame quagga). Although you might +// expect it to add a parent *to* something, it actually adds a vertex +// to the list of children *in* each of its parents. +// +// Given a pointer to a vertex, it links back to the vertex's parent that it +// already has set and adds itself to that vertex's list of children. +// +// For now, only one parent (not doing equal-cost multipath) +// + void +StaticRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) +{ + v->GetParent ()->AddChild (v); +} + +} // namespace ns3 + +#ifdef RUN_SELF_TESTS + +// --------------------------------------------------------------------------- +// +// Unit Tests +// +// --------------------------------------------------------------------------- + +#include "ns3/test.h" + +namespace ns3 { + +class StaticRouterTestNode : public Node +{ +public: + StaticRouterTestNode (); + +private: + virtual void DoAddDevice (Ptr device) const {}; + virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); +}; + +StaticRouterTestNode::StaticRouterTestNode () +{ +// Ptr ipv4 = Create (this); +} + + TraceResolver* +StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) +{ + return 0; +} + +class StaticRouteManagerImplTest : public Test { +public: + StaticRouteManagerImplTest (); + virtual ~StaticRouteManagerImplTest (); + virtual bool RunTests (void); +}; + +StaticRouteManagerImplTest::StaticRouteManagerImplTest () + : Test ("StaticRouteManagerImpl") +{ +} + +StaticRouteManagerImplTest::~StaticRouteManagerImplTest () +{} + + bool +StaticRouteManagerImplTest::RunTests (void) +{ + bool ok = true; + + CandidateQueue candidate; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = new SPFVertex; + v->SetDistanceFromRoot (rand () % 100); + candidate.Push (v); + } + + uint32_t lastDistance = 0; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = candidate.Pop (); + if (v->GetDistanceFromRoot () < lastDistance) + { + ok = false; + } + lastDistance = v->GetDistanceFromRoot (); + delete v; + v = 0; + } + + // Build fake link state database; four routers (0-3), 3 point-to-point + // links + // + // n0 + // \ link 0 + // \ link 2 + // n2 -------------------------n3 + // / + // / link 1 + // n1 + // + // link0: 10.1.1.1/30, 10.1.1.2/30 + // link1: 10.1.2.1/30, 10.1.2.2/30 + // link2: 10.1.3.1/30, 10.1.3.2/30 + // + // Router 0 + StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", // router ID 0.0.0.2 + "10.1.1.1", // local ID + 1); // metric + + StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.1.1", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa0 = new StaticRouterLSA (); + lsa0->SetLinkStateId ("0.0.0.0"); + lsa0->SetAdvertisingRouter ("0.0.0.0"); + lsa0->AddLinkRecord (lr0); + lsa0->AddLinkRecord (lr1); + + // Router 1 + StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + + StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa1 = new StaticRouterLSA (); + lsa1->SetLinkStateId ("0.0.0.1"); + lsa1->SetAdvertisingRouter ("0.0.0.1"); + lsa1->AddLinkRecord (lr2); + lsa1->AddLinkRecord (lr3); + + // Router 2 + StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.0", + "10.1.1.2", + 1); + + StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.1.2", + "255.255.255.252", + 1); + + StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.1", + "10.1.2.2", + 1); + + StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.2", + "255.255.255.252", + 1); + + StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.3", + "10.1.3.2", + 1); + + StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.3.2", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa2 = new StaticRouterLSA (); + lsa2->SetLinkStateId ("0.0.0.2"); + lsa2->SetAdvertisingRouter ("0.0.0.2"); + lsa2->AddLinkRecord (lr4); + lsa2->AddLinkRecord (lr5); + lsa2->AddLinkRecord (lr6); + lsa2->AddLinkRecord (lr7); + lsa2->AddLinkRecord (lr8); + lsa2->AddLinkRecord (lr9); + + // Router 3 + StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + + StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa3 = new StaticRouterLSA (); + lsa3->SetLinkStateId ("0.0.0.3"); + lsa3->SetAdvertisingRouter ("0.0.0.3"); + lsa3->AddLinkRecord (lr10); + lsa3->AddLinkRecord (lr11); + + // Test the database + StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); + srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0); + srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1); + srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2); + srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3); + NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); + + // XXX next, calculate routes based on the manually created LSDB + StaticRouteManagerImpl* srm = new StaticRouteManagerImpl (); + srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB + // Note-- this will succeed without any nodes in the topology + // because the NodeList is empty + srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 + + // This delete clears the srm, which deletes the LSDB, which clears + // all of the LSAs, which each destroys the attached LinkRecords. + delete srm; + + return ok; +} + +// Instantiate this class for the unit tests +static StaticRouteManagerImplTest g_staticRouteManagerTest; + +} // namespace ns3 + +#endif diff --git a/src/routing/static-route-manager-impl.h b/src/routing/static-route-manager-impl.h new file mode 100644 index 000000000..a4d97db77 --- /dev/null +++ b/src/routing/static-route-manager-impl.h @@ -0,0 +1,677 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef STATIC_ROUTE_MANAGER_IMPL_H +#define STATIC_ROUTE_MANAGER_IMPL_H + +#include +#include +#include +#include +#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" +#include "static-router.h" + +namespace ns3 { + +const uint32_t SPF_INFINITY = 0xffffffff; + +class CandidateQueue; + +/** + * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328, + * Section 16. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is the SPFVertex representing the router that is having + * its routing tables set. The SPFVertex objects representing other routers + * or networks in the simulation are arranged in the SPF tree. It is this + * tree that represents the Shortest Paths to the other networks. + * + * Each SPFVertex has a pointer to the Static Router Link State Advertisement + * (LSA) that its underlying router has exported. Within these LSAs are + * Static Router Link Records that describe the point to point links from the + * underlying router to other nodes (represented by other SPFVertex objects) + * in the simulation topology. The combination of the arrangement of the + * SPFVertex objects in the SPF tree, along with the details of the link + * records that connect them provide the information required to construct the + * required routes. + */ +class SPFVertex +{ +public: +/** + * @enum Enumeration of the possible types of SPFVertex objects. Currently + * we use VertexRouter to identify objects that represent a router in the + * simulation topology, and VertexNetwork to identify objects that represent + * a network. + */ + enum VertexType { + VertexUnknown = 0, /**< Uninitialized Link Record */ + VertexRouter, /**< Vertex representing a router in the topology */ + VertexNetwork /**< Vertex representing a network in the topology */ + }; +/** + * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First + * Vertex). + * + * The Vertex Type is set to VertexUnknown, the Vertex ID is set to + * 255.255.255.255, and the distance from root is set to infinity + * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to + * null as is the parent SPFVertex. The outgoing interface index is set to + * infinity, the next hop address is set to 0.0.0.0 and the list of children + * of the SPFVertex is initialized to empty. + * + * @see VertexType + */ + SPFVertex(); +/** + * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). + * + * The Vertex Type is initialized to VertexRouter and the Vertex ID is found + * from the Link State ID of the Link State Advertisement (LSA) passed as a + * parameter. The Link State ID is set to the Router ID of the advertising + * router. The referenced LSA (m_lsa) is set to the given LSA. Other than + * these members, initialization is as in the default constructor. + * of the SPFVertex is initialized to empty. + * + * @see SPFVertex::SPFVertex () + * @see VertexType + * @see StaticRouterLSA + * @param lsa The Link State Advertisement used for finding initial values. + */ + SPFVertex(StaticRouterLSA* lsa); +/** + * @brief Destroy an SPFVertex (Shortest Path First Vertex). + * + * The children vertices of the SPFVertex are recursively deleted. + * + * @see SPFVertex::SPFVertex () + */ + ~SPFVertex(); +/** + * @brief Get the Vertex Type field of a SPFVertex object. + * + * The Vertex Type describes the kind of simulation object a given SPFVertex + * represents. + * + * @see VertexType + * @returns The VertexType of the current SPFVertex object. + */ + VertexType GetVertexType (void) const; +/** + * @brief Set the Vertex Type field of a SPFVertex object. + * + * The Vertex Type describes the kind of simulation object a given SPFVertex + * represents. + * + * @see VertexType + * @param The new VertexType for the current SPFVertex object. + */ + void SetVertexType (VertexType type); +/** + * @brief Get the Vertex ID field of a SPFVertex object. + * + * The Vertex ID uniquely identifies the simulation object a given SPFVertex + * represents. Typically, this is the Router ID for SPFVertex objects + * representing routers, and comes from the Link State Advertisement of a + * router aggregated to a node in the simulation. These IDs are allocated + * automatically by the routing environment and look like IP addresses + * beginning at 0.0.0.0 and monotonically increasing as new routers are + * instantiated. + * + * @returns The Ipv4Address Vertex ID of the current SPFVertex object. + */ + Ipv4Address GetVertexId (void) const; +/** + * @brief Set the Vertex ID field of a SPFVertex object. + * + * The Vertex ID uniquely identifies the simulation object a given SPFVertex + * represents. Typically, this is the Router ID for SPFVertex objects + * representing routers, and comes from the Link State Advertisement of a + * router aggregated to a node in the simulation. These IDs are allocated + * automatically by the routing environment and look like IP addresses + * beginning at 0.0.0.0 and monotonically increasing as new routers are + * instantiated. + * + * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. + */ + void SetVertexId (Ipv4Address id); +/** + * @brief Get the Static Router Link State Advertisement returned by the + * Static Router represented by this SPFVertex during the route discovery + * process. + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @returns A pointer to the StaticRouterLSA found by the router represented + * by this SPFVertex object. + */ + StaticRouterLSA* GetLSA (void) const; +/** + * @brief Set the Static Router Link State Advertisement returned by the + * Static Router represented by this SPFVertex during the route discovery + * process. + * + * @see SPFVertex::GetLSA () + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You + * must not delete the LSA after calling this method. + * @param A pointer to the StaticRouterLSA. + */ + void SetLSA (StaticRouterLSA* lsa); +/** + * @brief Get the distance from the root vertex to "this" SPFVertex object. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex to which + * a route is being calculated from the root. The distance from the root that + * we're asking for is the number of hops from the root vertex to the vertex + * in question. + * + * The distance is calculated during route discovery and is stored in a + * member variable. This method simply fetches that value. + * + * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex. + */ + uint32_t GetDistanceFromRoot (void) const; +/** + * @brief Set the distance from the root vertex to "this" SPFVertex object. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex to which + * a route is being calculated from the root. The distance from the root that + * we're asking for is the number of hops from the root vertex to the vertex + * in question. + * + * @param distance The distance, in hops, from the root SPFVertex to "this" + * SPFVertex. + */ + void SetDistanceFromRoot (uint32_t distance); +/** + * @brief Get the interface ID that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The outgoing interface that we're asking for is the interface + * index on the root node that should be used to start packets along the + * path to "this" vertex. + * + * When initializing the root SPFVertex, the interface ID is determined by + * examining the Static Router Link Records of the Link State Advertisement + * generated by the root node's StaticRouter. These interfaces are used to + * forward packets off of the root's network down those links. As other + * vertices are discovered which are further away from the root, they will + * be accessible down one of the paths begun by a Static Router Link Record. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to the interface of that + * first hop. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, the root node is asking, "which of my local interfaces + * should I use to get a packet to the network or host represented by 'this' + * SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @returns The interface index to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + uint32_t GetOutgoingInterfaceId (void) const; +/** + * @brief Set the interface ID that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The outgoing interface that we're asking for is the interface + * index on the root node that should be used to start packets along the + * path to "this" vertex. + * + * When initializing the root SPFVertex, the interface ID is determined by + * examining the Static Router Link Records of the Link State Advertisement + * generated by the root node's StaticRouter. These interfaces are used to + * forward packets off of the root's network down those links. As other + * vertices are discovered which are further away from the root, they will + * be accessible down one of the paths begun by a Static Router Link Record. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to the interface of that + * first hop. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, we are letting the root node know which of its local + * interfaces it should use to get a packet to the network or host represented + * by "this" SPFVertex. + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @param id The interface index to use when forwarding packets to the host or + * network represented by "this" SPFVertex. + */ + void SetOutgoingInterfaceId (uint32_t id); +/** + * @brief Get the IP address that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The IP address that we're asking for is the address on the + * remote side of a link off of the root node that should be used as the + * destination for packets along the path to "this" vertex. + * + * When initializing the root SPFVertex, the IP address used when forwarding + * packets is determined by examining the Static Router Link Records of the + * Link State Advertisement generated by the root node's StaticRouter. This + * address is used to forward packets off of the root's network down those + * links. As other vertices / nodes are discovered which are further away + * from the root, they will be accessible down one of the paths via a link + * described by one of these Static Router Link Records. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to a first hop router down + * an interface. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, the root node is asking, "which router should I send a + * packet to in order to get that packet to the network or host represented + * by 'this' SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @returns The IP address to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + Ipv4Address GetNextHop (void) const; +/** + * @brief Set the IP address that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The IP address that we're asking for is the address on the + * remote side of a link off of the root node that should be used as the + * destination for packets along the path to "this" vertex. + * + * When initializing the root SPFVertex, the IP address used when forwarding + * packets is determined by examining the Static Router Link Records of the + * Link State Advertisement generated by the root node's StaticRouter. This + * address is used to forward packets off of the root's network down those + * links. As other vertices / nodes are discovered which are further away + * from the root, they will be accessible down one of the paths via a link + * described by one of these Static Router Link Records. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to a first hop router down + * an interface. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method we are telling the root node which router it should send + * should I send a packet to in order to get that packet to the network or + * host represented by 'this' SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @param nextHop The IP address to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + void SetNextHop (Ipv4Address nextHop); +/** + * @brief Get a pointer to the SPFVector that is the parent of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. + * + * This method returns a pointer to the parent node of "this" SPFVertex + * (both of which reside in that SPF tree). + * + * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex + * in the SPF tree. + */ + SPFVertex* GetParent (void) const; +/** + * @brief Set the pointer to the SPFVector that is the parent of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. + * + * This method sets the parent pointer of "this" SPFVertex (both of which + * reside in that SPF tree). + * + * @param parent A pointer to the SPFVertex that is the parent of "this" + * SPFVertex* in the SPF tree. + */ + void SetParent (SPFVertex* parent); +/** + * @brief Get the number of children of "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method returns the number of children of "this" SPFVertex (which + * reside in the SPF tree). + * + * @returns The number of children of "this" SPFVertex (which reside in the + * SPF tree). + */ + uint32_t GetNChildren (void) const; +/** + * @brief Get a borrowed SPFVertex pointer to the specified child of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method the number of children of "this" SPFVertex (which reside in + * the SPF tree. + * + * @see SPFVertex::GetNChildren + * @param n The index (from 0 to the number of children minus 1) of the + * child SPFVertex to return. + * @warning The pointer returned by GetChild () is a borrowed pointer. You + * do not have any ownership of the underlying object and must not delete + * that object. + * @returns A pointer to the specified child SPFVertex (which resides in the + * SPF tree). + */ + SPFVertex* GetChild (uint32_t n) const; +/** + * @brief Get a borrowed SPFVertex pointer to the specified child of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method the number of children of "this" SPFVertex (which reside in + * the SPF tree. + * + * @see SPFVertex::GetNChildren + * @param n The index (from 0 to the number of children minus 1) of the + * child SPFVertex to return. + * @warning Ownership of the pointer added to the children of "this" + * SPFVertex is transferred to the "this" SPFVertex. You must not delete the + * (now) child SPFVertex after calling this method. + * @param child A pointer to the SPFVertex (which resides in the SPF tree) to + * be added to the list of children of "this" SPFVertex. + * @returns The number of children of "this" SPFVertex after the addition of + * the new child. + */ + uint32_t AddChild (SPFVertex* child); + +private: + VertexType m_vertexType; + Ipv4Address m_vertexId; + StaticRouterLSA* m_lsa; + uint32_t m_distanceFromRoot; + uint32_t m_rootOif; + Ipv4Address m_nextHop; + SPFVertex* m_parent; + typedef std::list ListOfSPFVertex_t; + ListOfSPFVertex_t m_children; +/** + * @brief The SPFVertex copy construction is disallowed. There's no need for + * it and a compiler provided shallow copy would be wrong. + */ + SPFVertex (SPFVertex& v); +/** + * @brief The SPFVertex copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be wrong. + */ + SPFVertex& operator= (SPFVertex& v); +}; + +/** + * @brief The Link State DataBase (LSDB) of the Static Route Manager. + * + * Each node in the simulation participating in static routing has a + * StaticRouter interface. The primary job of this interface is to export + * Static Router Link State Advertisements (LSAs). These advertisements in + * turn contain a number of Static Router Link Records that describe the + * point to point links from the underlying node to other nodes (that will + * also export their own LSAs. + * + * This class implements a searchable database of LSAs gathered from every + * router in the simulation. + */ +class StaticRouteManagerLSDB +{ +public: +/** + * @brief Construct an empty Static Router Manager Link State Database. + * + * The database map composing the Link State Database is initialized in + * this constructor. + */ + StaticRouteManagerLSDB (); +/** + * @brief Destroy an empty Static Router Manager Link State Database. + * + * The database map is walked and all of the Link State Advertisements stored + * in the database are freed; then the database map itself is clear ()ed to + * release any remaining resources. + */ + ~StaticRouteManagerLSDB (); +/** + * @brief Insert an IP address / Link State Advertisement pair into the Link + * State Database. + * + * The IPV4 address and the StaticRouterLSA given as parameters are converted + * to an STL pair and are inserted into the database map. + * + * @see StaticRouterLSA + * @see Ipv4Address + * @param addr The IP address associated with the LSA. Typically the Router + * ID. + * @param lsa A pointer to the Link State Advertisement for the router. + */ + void Insert(Ipv4Address addr, StaticRouterLSA* lsa); +/** + * @brief Look up the Link State Advertisement associated with the given + * IP Address. + * + * The database map is searched for the given IPV4 address and corresponding + * StaticRouterLSA is returned. + * + * @see StaticRouterLSA + * @see Ipv4Address + * @param addr The IP address associated with the LSA. Typically the Router + * ID. + * @returns A pointer to the Link State Advertisement for the router specified + * by the IP address addr. + */ + StaticRouterLSA* GetLSA (Ipv4Address addr) const; +/** + * @brief Set all LSA flags to an initialized state, for SPF computation + * + * This function walks the database and resets the status flags of all of the + * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done + * prior to each SPF calculation to reset the state of the SPFVertex structures + * that will reference the LSAs during the calculation. + * + * @see StaticRouterLSA + * @see SPFVertex + */ + void Initialize (); + +private: + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; + + LSDBMap_t m_database; +/** + * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no + * need for it and a compiler provided shallow copy would be hopelessly wrong. + */ + StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); +/** + * @brief The SPFVertex copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be wrong. + */ + StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); +}; + +/** + * @brief A global static router + * + * This singleton object can query interface each node in the system + * for a StaticRouter interface. For those nodes, it fetches one or + * more Link State Advertisements and stores them in a local database. + * Then, it can compute shortest paths on a per-node basis to all routers, + * and finally configure each of the node's forwarding tables. + * + * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. + */ +class StaticRouteManagerImpl +{ +public: + StaticRouteManagerImpl (); + virtual ~StaticRouteManagerImpl (); +/** + * @brief Build the routing database by gathering Link State Advertisements + * from each node exporting a StaticRouter interface. + * + */ + virtual void BuildStaticRoutingDatabase(); +/** + * @brief Compute routes using a Dijkstra SPF computation and populate + * per-node forwarding tables + */ + virtual void InitializeRoutes(); +/** + * @brief Debugging routine; allow client code to supply a pre-built LSDB + */ + void DebugUseLsdb (StaticRouteManagerLSDB*); +/** + * @brief Debugging routine; call the core SPF from the unit tests + */ + void DebugSPFCalculate (Ipv4Address root); +private: +/** + * @brief Static Route Manager Implementation copy construction is disallowed. + * There's no need for it and a compiler provided shallow copy would be + * hopelessly wrong. + */ + StaticRouteManagerImpl (StaticRouteManagerImpl& srmi); +/** + * @brief Static Route Manager Implementation assignment operator is + * disallowed. There's no need for it and a compiler provided shallow copy + * would be hopelessly wrong. + */ + StaticRouteManagerImpl& operator= (StaticRouteManagerImpl& srmi); + + SPFVertex* m_spfroot; + StaticRouteManagerLSDB* m_lsdb; + void SPFCalculate (Ipv4Address root); + void SPFNext (SPFVertex*, CandidateQueue&); + int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* l, uint32_t distance); + void SPFVertexAddParent(SPFVertex* v); + StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* prev_link); + void SPFIntraAddRouter(SPFVertex* v); + uint32_t FindOutgoingInterfaceId(Ipv4Address a); +}; + +} // namespace ns3 + +#endif /* STATIC_ROUTE_MANAGER_IMPL_H */ diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 02948ac9c..09ced494f 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -14,1358 +14,32 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include #include "ns3/assert.h" -#include "ns3/fatal-error.h" #include "ns3/debug.h" -#include "ns3/node-list.h" -#include "ns3/ipv4.h" -#include "static-router.h" +#include "ns3/simulation-singleton.h" #include "static-route-manager.h" -#include "candidate-queue.h" - -NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); +#include "static-route-manager-impl.h" namespace ns3 { -// --------------------------------------------------------------------------- -// -// SPFVertex Implementation -// -// --------------------------------------------------------------------------- - -SPFVertex::SPFVertex () : - m_vertexType (VertexUnknown), - m_vertexId ("255.255.255.255"), - m_lsa (0), - m_distanceFromRoot (SPF_INFINITY), - m_rootOif (SPF_INFINITY), - m_nextHop ("0.0.0.0"), - m_parent (0), - m_children () -{ -} - -SPFVertex::SPFVertex (StaticRouterLSA* lsa) : - m_vertexType (VertexRouter), - m_vertexId (lsa->GetLinkStateId ()), - m_lsa (lsa), - m_distanceFromRoot (SPF_INFINITY), - m_rootOif (SPF_INFINITY), - m_nextHop ("0.0.0.0"), - m_parent (0), - m_children () -{ -} - -SPFVertex::~SPFVertex () -{ - for ( ListOfSPFVertex_t::iterator i = m_children.begin (); - i != m_children.end (); - i++) - { - SPFVertex *p = *i; - delete p; - p = 0; - *i = 0; - } - m_children.clear (); -} - - void -SPFVertex::SetVertexType (SPFVertex::VertexType type) -{ - m_vertexType = type; -} - - SPFVertex::VertexType -SPFVertex::GetVertexType (void) const -{ - return m_vertexType; -} - - void -SPFVertex::SetVertexId (Ipv4Address id) -{ - m_vertexId = id; -} - - Ipv4Address -SPFVertex::GetVertexId (void) const -{ - return m_vertexId; -} - - void -SPFVertex::SetLSA (StaticRouterLSA* lsa) -{ - m_lsa = lsa; -} - - StaticRouterLSA* -SPFVertex::GetLSA (void) const -{ - return m_lsa; -} - - void -SPFVertex::SetDistanceFromRoot (uint32_t distance) -{ - m_distanceFromRoot = distance; -} - - uint32_t -SPFVertex::GetDistanceFromRoot (void) const -{ - return m_distanceFromRoot; -} - - void -SPFVertex::SetOutgoingInterfaceId (uint32_t id) -{ - m_rootOif = id; -} - - uint32_t -SPFVertex::GetOutgoingInterfaceId (void) const -{ - return m_rootOif; -} - - void -SPFVertex::SetNextHop (Ipv4Address nextHop) -{ - m_nextHop = nextHop; -} - - Ipv4Address -SPFVertex::GetNextHop (void) const -{ - return m_nextHop; -} - - void -SPFVertex::SetParent (SPFVertex* parent) -{ - m_parent = parent; -} - - SPFVertex* -SPFVertex::GetParent (void) const -{ - return m_parent; -} - - uint32_t -SPFVertex::GetNChildren (void) const -{ - return m_children.size (); -} - - SPFVertex* -SPFVertex::GetChild (uint32_t n) const -{ - uint32_t j = 0; - - for ( ListOfSPFVertex_t::const_iterator i = m_children.begin (); - i != m_children.end (); - i++, j++) - { - if (j == n) - { - return *i; - } - } - NS_ASSERT_MSG(false, "Index out of range."); - return 0; -} - - uint32_t -SPFVertex::AddChild (SPFVertex* child) -{ - m_children.push_back (child); - return m_children.size (); -} - -// --------------------------------------------------------------------------- -// -// StaticRouteManagerLSDB Implementation -// -// --------------------------------------------------------------------------- - -StaticRouteManagerLSDB::StaticRouteManagerLSDB () -: - m_database () -{ - NS_DEBUG ("StaticRouteManagerLSDB::StaticRouteManagerLSDB ()"); -} - -StaticRouteManagerLSDB::~StaticRouteManagerLSDB () -{ - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); - - LSDBMap_t::iterator i; - for (i= m_database.begin (); i!= m_database.end (); i++) - { - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ():free LSA"); - StaticRouterLSA* temp = i->second; - delete temp; - } - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); - m_database.clear (); -} - - void -StaticRouteManagerLSDB::Initialize () -{ - NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); - - LSDBMap_t::iterator i; - for (i= m_database.begin (); i!= m_database.end (); i++) - { - StaticRouterLSA* temp = i->second; - temp->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); - } -} - - void -StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) -{ - NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); - m_database.insert (LSDBPair_t (addr, lsa)); -} - - StaticRouterLSA* -StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const -{ - NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); -// -// Look up an LSA by its address. -// - LSDBMap_t::const_iterator i; - for (i= m_database.begin (); i!= m_database.end (); i++) - { - if (i->first == addr) - { - return i->second; - } - } - return 0; -} - // --------------------------------------------------------------------------- // // StaticRouteManager Implementation // // --------------------------------------------------------------------------- -StaticRouteManager::StaticRouteManager () -: - m_spfroot (0) -{ - m_lsdb = new StaticRouteManagerLSDB (); -} - -StaticRouteManager::~StaticRouteManager () -{ - NS_DEBUG ("StaticRouteManager::~StaticRouteManager ()"); - - if (m_lsdb) - { - delete m_lsdb; - } -} - - void -StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) -{ - if (m_lsdb) - delete m_lsdb; - m_lsdb = lsdb; -} - -// -// In order to build the routing database, we need to walk the list of nodes -// in the system and look for those that support the StaticRouter interface. -// These routers will export a number of Link State Advertisements (LSAs) -// that describe the links and networks that are "adjacent" (i.e., that are -// on the other side of a point-to-point link). We take these LSAs and put -// add them to the Link State DataBase (LSDB) from which the routes will -// ultimately be computed. -// void StaticRouteManager::BuildStaticRoutingDatabase () { - NS_DEBUG ("StaticRouteManager::BuildStaticRoutingDatabase()"); -// -// Walk the list of nodes looking for the StaticRouter Interface. -// - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) - { - Ptr node = *i; - - Ptr rtr = - node->QueryInterface (StaticRouter::iid); -// -// Ignore nodes that aren't participating in routing. -// - if (!rtr) - { - continue; - } -// -// You must call DiscoverLSAs () before trying to use any routing info or to -// update LSAs. DiscoverLSAs () drives the process of discovering routes in -// the StaticRouter. Afterward, you may use GetNumLSAs (), which is a very -// computationally inexpensive call. If you call GetNumLSAs () before calling -// DiscoverLSAs () will get zero as the number since no routes have been -// found. -// - uint32_t numLSAs = rtr->DiscoverLSAs (); - NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); - - for (uint32_t j = 0; j < numLSAs; ++j) - { - StaticRouterLSA* lsa = new StaticRouterLSA (); -// -// This is the call to actually fetch a Link State Advertisement from the -// router. -// - rtr->GetLSA (j, *lsa); - NS_DEBUG ("LSA " << j); - NS_DEBUG (*lsa); -// -// Write the newly discovered link state advertisement to the database. -// - m_lsdb->Insert (lsa->GetLinkStateId (), lsa); - } - } + return SimulationSingleton::Get ()-> + BuildStaticRoutingDatabase (); } -// -// For each node that is a static router (which is determined by the presence -// of an aggregated StaticRouter interface), run the Dijkstra SPF calculation -// on the database rooted at that router, and populate the node forwarding -// tables. -// -// This function parallels RFC2328, Section 16.1.1, and quagga ospfd -// -// This calculation yields the set of intra-area routes associated -// with an area (called hereafter Area A). A router calculates the -// shortest-path tree using itself as the root. The formation -// of the shortest path tree is done here in two stages. In the -// first stage, only links between routers and transit networks are -// considered. Using the Dijkstra algorithm, a tree is formed from -// this subset of the link state database. In the second stage, -// leaves are added to the tree by considering the links to stub -// networks. -// -// The area's link state database is represented as a directed graph. -// The graph's vertices are routers, transit networks and stub networks. -// -// The first stage of the procedure (i.e., the Dijkstra algorithm) -// can now be summarized as follows. At each iteration of the -// algorithm, there is a list of candidate vertices. Paths from -// the root to these vertices have been found, but not necessarily -// the shortest ones. However, the paths to the candidate vertex -// that is closest to the root are guaranteed to be shortest; this -// vertex is added to the shortest-path tree, removed from the -// candidate list, and its adjacent vertices are examined for -// possible addition to/modification of the candidate list. The -// algorithm then iterates again. It terminates when the candidate -// list becomes empty. -// void StaticRouteManager::InitializeRoutes () { - NS_DEBUG ("StaticRouteManager::InitializeRoutes ()"); -// -// Walk the list of nodes in the system. -// - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) - { - Ptr node = *i; -// -// Look for the StaticRouter interface that indicates that the node is -// participating in routing. -// - Ptr rtr = - node->QueryInterface (StaticRouter::iid); -// -// if the node has a static router interface, then run the static routing -// algorithms. -// - if (rtr && rtr->GetNumLSAs () ) - { - SPFCalculate (rtr->GetRouterId ()); - } - } -} - -// -// This method is derived from quagga ospf_spf_next (). See RFC2328 Section -// 16.1 (2) for further details. -// -// We're passed a parameter that is a vertex which is already in the SPF -// tree. A vertex represents a router node. We also get a reference to the -// SPF candidate queue, which is a priority queue containing the shortest paths -// to the networks we know about. -// -// We examine the links in v's LSA and update the list of candidates with any -// vertices not already on the list. If a lower-cost path is found to a -// vertex already on the candidate list, store the new (lower) cost. -// - void -StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) -{ - SPFVertex* w = 0; - StaticRouterLSA* w_lsa = 0; - uint32_t distance = 0; - - NS_DEBUG ("StaticRouteManager::SPFNext ()"); -// -// Always true for now, since all our LSAs are RouterLSAs. -// - if (v->GetVertexType () == SPFVertex::VertexRouter) - { - if (true) - { - NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " << - v->GetLSA ()->GetNLinkRecords () << " link records"); -// -// Walk the list of link records in the link state advertisement associated -// with the "current" router (represented by vertex ). -// - for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) - { -// -// (a) If this is a link to a stub network, examine the next link in V's LSA. -// Links to stub networks will be considered in the second stage of the -// shortest path calculation. -// - StaticRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) - { - NS_DEBUG ("SPFNext: Found a Stub record to " << - l->GetLinkId ()); - continue; - } -// -// (b) Otherwise, W is a transit vertex (router or transit network). Look up -// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state -// database. -// - if (l->GetLinkType () == StaticRouterLinkRecord::PointToPoint) - { -// -// Lookup the link state advertisement of the new link -- we call it in -// the link state database. -// - w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); - NS_ASSERT (w_lsa); - NS_DEBUG ("SPFNext: Found a P2P record from " << - v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); -// -// (c) If vertex W is already on the shortest-path tree, examine the next -// link in the LSA. -// -// If the link is to a router that is already in the shortest path first tree -// then we have it covered -- ignore it. -// - if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_IN_SPFTREE) - { - NS_DEBUG ("SPFNext: Skipping-> LSA "<< - w_lsa->GetLinkStateId () << " already in SPF tree"); - continue; - } -// -// The link is to a router we haven't dealt with yet. -// -// (d) Calculate the link state cost D of the resulting path from the root to -// vertex W. D is equal to the sum of the link state cost of the (already -// calculated) shortest path to vertex V and the advertised cost of the link -// between vertices V and W. -// - distance = v->GetDistanceFromRoot () + l->GetMetric (); - - NS_DEBUG ("SPFNext: Considering w_lsa " << - w_lsa->GetLinkStateId ()); - - if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_NOT_EXPLORED) - { -// -// If we havent yet considered the link represented by we have to create -// a new SPFVertex to represent it. -// - w = new SPFVertex (w_lsa); -// -// We need to figure out how to actually get to the new router represented -// by . This will (among other things) find the next hop address to send -// packets destined for this network to, and also find the outbound interface -// used to forward the packets. -// - if (SPFNexthopCalculation (v, w, l, distance)) - { - w_lsa->SetStatus ( - StaticRouterLSA::LSA_SPF_CANDIDATE); -// -// Push this new vertex onto the priority queue (ordered by distance from the -// root node). -// - candidate.Push (w); - NS_DEBUG ("SPFNext: Pushing " << - w->GetVertexId () << ", parent vertexId: " << - v->GetVertexId ()); - } - } - } else if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_CANDIDATE) - { -// -// We have already considered the link represented by . What wse have to -// do now is to decide if this new router represents a route with a shorter -// distance metric. -// -// So, locate the vertex in the candidate queue and take a look at the -// distance. - w = candidate.Find (w_lsa->GetLinkStateId ()); - if (w->GetDistanceFromRoot () < distance) - { -// -// This is not a shorter path, so don't do anything. -// - continue; - } - else if (w->GetDistanceFromRoot () == distance) - { -// -// This path is one with an equal cost. Do nothing for now -- we're not doing -// equal-cost multipath cases yet. -// - } - else - { -// -// this path represents a new, lower-cost path to (the vertex we found in -// the current link record of the link state advertisement of the current root -// (vertex ) -// -// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop -// it will call spf_add_parents, which will flush the old parents -// - if (SPFNexthopCalculation (v, w, l, distance)) - { -// -// If we've changed the cost to get to the vertex represented by , we -// must reorder the priority queue keyed to that cost. -// - candidate.Reorder (); - } - } - } // point-to-point - } // for loop - } - } -} - -// -// This method is derived from quagga ospf_next_hop_calculation() 16.1.1. -// -// Calculate the next hop IP address and the outgoing interface required to -// get packets from the root through (parent) to vertex (destination), -// over a given distance. -// -// For now, this is greatly simplified from the quagga code -// - int -StaticRouteManager::SPFNexthopCalculation ( - SPFVertex* v, - SPFVertex* w, - StaticRouterLinkRecord* l, - uint32_t distance) -{ - NS_DEBUG ("StaticRouteManager::SPFNexthopCalculation ()"); -// -// The vertex m_spfroot is a distinguished vertex representing the node at -// the root of the calculations. That is, it is the node for which we are -// calculating the routes. -// -// There are two distinct cases for calculating the next hop information. -// First, if we're considering a hop from the root to an "adjacent" network -// (one that is on the other side of a point-to-point link connected to the -// root), then we need to store the information needed to forward down that -// link. The second case is if the network is not directly adjacent. In that -// case we need to use the forwarding information from the vertex on the path -// to the destination that is directly adjacent [node 1] in both cases of the -// diagram below. -// -// (1) [root] -> [point-to-point] -> [node 1] -// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2] -// -// We call the propagation of next hop information down vertices of a path -// "inheriting" the next hop information. -// -// The point-to-point link information is only useful in this calculation when -// we are examining the root node. -// - if (v == m_spfroot) - { -// -// In this case is the root node, which means it is the starting point -// for the packets forwarded by that node. This also means that the next hop -// address of packets headed for some arbitrary off-network destination must -// be the destination at the other end of one of the links off of the root -// node if this root node is a router. We then need to see if this node -// is a router. -// - if (w->GetVertexType () == SPFVertex::VertexRouter) - { -// -// In the case of point-to-point links, the link data field (m_linkData) of a -// Static Router Link Record contains the local IP address. If we look at the -// link record describing the link from the perspecive of (the remote -// node from the viewpoint of ) back to the root node, we can discover the -// IP address of the router to which is adjacent. This is a distinguished -// address -- the next hop address to get from to and all networks -// accessed through that path. -// -// SPFGetNextLink () is a little odd. used in this way it is just going to -// return the link record describing the link from to . Think of it as -// SPFGetLink. -// - StaticRouterLinkRecord *linkRemote = 0; - linkRemote = SPFGetNextLink (w, v, linkRemote); -// -// At this point, is the Static Router Link Record describing the point- -// to point link from to from the perspective of ; and -// is the Static Router Link Record describing that same link from the -// perspective of (back to ). Now we can just copy the next hop -// address from the m_linkData member variable. -// -// The next hop member variable we put in has the sense "in order to get -// from the root node to the host represented by vertex , you have to send -// the packet to the next hop address specified in w->m_nextHop. -// - w->SetNextHop(linkRemote->GetLinkData ()); -// -// Now find the outgoing interface corresponding to the point to point link -// from the perspective of -- remember that is the link "from" -// "to" . -// - w->SetOutgoingInterfaceId ( - FindOutgoingInterfaceId (l->GetLinkData ())); - - NS_DEBUG ("SPFNexthopCalculation: Next hop from " << - v->GetVertexId () << " to " << w->GetVertexId () << - " goes through next hop " << w->GetNextHop () << - " via outgoing interface " << w->GetOutgoingInterfaceId ()); - } - } - else - { -// -// If we're calculating the next hop information from a node (v) that is -// *not* the root, then we need to "inherit" the information needed to -// forward the packet from the vertex closer to the root. That is, we'll -// still send packets to the next hop address of the router adjacent to the -// root on the path toward . -// -// Above, when we were considering the root node, we calculated the next hop -// address and outgoing interface required to get off of the root network. -// At this point, we are further away from the root network along one of the -// (shortest) paths. So the next hop and outoing interface remain the same -// (are inherited). -// - w->SetNextHop (v->GetNextHop ()); - w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); - } -// -// In all cases, we need valid values for the distance metric and a parent. -// - w->SetDistanceFromRoot (distance); - w->SetParent (v); - - return 1; -} - -// -// This method is derived from quagga ospf_get_next_link () -// -// First search the Static Router Link Records of vertex for one -// representing a point-to point link to vertex . -// -// What is done depends on prev_link. Contrary to appearances, prev_link just -// acts as a flag here. If prev_link is NULL, we return the first Static -// Router Link Record we find that describes a point-to-point link from -// to . If prev_link is not NULL, we return a Static Router Link Record -// representing a possible *second* link from to . -// -// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for -// any link records after pre_link and not just after the first? -// - StaticRouterLinkRecord* -StaticRouteManager::SPFGetNextLink ( - SPFVertex* v, - SPFVertex* w, - StaticRouterLinkRecord* prev_link) -{ - NS_DEBUG ("StaticRouteManager::SPFGetNextLink ()"); - - bool skip = true; - StaticRouterLinkRecord* l; -// -// If prev_link is 0, we are really looking for the first link, not the next -// link. -// - if (prev_link == 0) - { - skip = false; - } -// -// Iterate through the Static Router Link Records advertised by the vertex -// looking for records representing the point-to-point links off of this -// vertex. -// - for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) - { - l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) - { - continue; - } -// -// The link ID of a link record representing a point-to-point link is set to -// the router ID of the neighboring router -- the router to which the link -// connects from the perspective of in this case. The vertex ID is also -// set to the router ID (using the link state advertisement of a router node). -// We're just checking to see if the link is actually the link from to -// . -// - if (l->GetLinkId () == w->GetVertexId ()) { - NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << - l->GetLinkId () << " linkData = " << l->GetLinkData ()); -// -// If skip is false, don't (not too surprisingly) skip the link found -- it's -// the one we're interested in. That's either because we didn't pass in a -// previous link, and we're interested in the first one, or because we've -// skipped a previous link and moved forward to the next (which is then the -// one we want). -// - if (skip == false) - { - NS_DEBUG ("SPFGetNextLink: Returning the found link"); - return l; - } - else - { -// -// Skip is true and we've found a link from to . We want the next one. -// Setting skip to false gets us the next point-to-point static router link -// record in the LSA from . -// - NS_DEBUG ("SPFGetNextLink: Skipping the found link"); - skip = false; - continue; - } - } - } - return 0; -} - -// -// Used for unit tests. -// - void -StaticRouteManager::DebugSPFCalculate (Ipv4Address root) -{ - SPFCalculate (root); -} - -// quagga ospf_spf_calculate - void -StaticRouteManager::SPFCalculate (Ipv4Address root) -{ - NS_DEBUG ("StaticRouteManager::SPFCalculate (): " - "root = " << root); - - SPFVertex *v; -// -// Initialize the Link State Database. -// - m_lsdb->Initialize (); -// -// The candidate queue is a priority queue of SPFVertex objects, with the top -// of the queue being the closest vertex in terms of distance from the root -// of the tree. Initially, this queue is empty. -// - CandidateQueue candidate; - NS_ASSERT(candidate.Size () == 0); -// -// Initialize the shortest-path tree to only contain the router doing the -// calculation. Each router (and corresponding network) is a vertex in the -// shortest path first (SPF) tree. -// - v = new SPFVertex (m_lsdb->GetLSA (root)); -// -// This vertex is the root of the SPF tree and it is distance 0 from the root. -// We also mark this vertex as being in the SPF tree. -// - m_spfroot= v; - v->SetDistanceFromRoot (0); - v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); - - for (;;) - { -// -// The operations we need to do are given in the OSPF RFC which we reference -// as we go along. -// -// RFC2328 16.1. (2). -// -// We examine the Static Router Link Records in the Link State -// Advertisements of the current vertex. If there are any point-to-point -// links to unexplored adjacent vertices we add them to the tree and update -// the distance and next hop information on how to get there. We also add -// the new vertices to the candidate queue (the priority queue ordered by -// shortest path). If the new vertices represent shorter paths, we use them -// and update the path cost. -// - SPFNext (v, candidate); -// -// RFC2328 16.1. (3). -// -// If at this step the candidate list is empty, the shortest-path tree (of -// transit vertices) has been completely built and this stage of the -// procedure terminates. -// - if (candidate.Size () == 0) - { - break; - } -// -// Choose the vertex belonging to the candidate list that is closest to the -// root, and add it to the shortest-path tree (removing it from the candidate -// list in the process). -// -// Recall that in the previous step, we created SPFVertex structures for each -// of the routers found in the Static Router Link Records and added tehm to -// the candidate list. -// - v = candidate.Pop (); - NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ()); -// -// Update the status field of the vertex to indicate that it is in the SPF -// tree. -// - v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); -// -// The current vertex has a parent pointer. By calling this rather oddly -// named method (blame quagga) we add the current vertex to the list of -// children of that parent vertex. In the next hop calculation called during -// SPFNext, the parent pointer was set but the vertex has been orphaned up -// to now. -// - SPFVertexAddParent (v); -// -// Note that when there is a choice of vertices closest to the root, network -// vertices must be chosen before router vertices in order to necessarily -// find all equal-cost paths. We don't do this at this moment, we should add -// the treatment above codes. -- kunihiro. -// -// RFC2328 16.1. (4). -// -// This is the method that actually adds the routes. It'll walk the list -// of nodes in the system, looking for the node corresponding to the router -// ID of the root of the tree -- that is the router we're building the routes -// for. It looks for the Ipv4 interface of that node and remembers it. So -// we are only actually adding routes to that one node at the root of the SPF -// tree. -// -// We're going to pop of a pointer to every vertex in the tree except the -// root in order of distance from the root. For each of the vertices, we call -// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the -// point-to-point Static Router Link Records (the links to nodes adjacent to -// the node represented by the vertex). We add a route to the IP address -// specified by the m_linkData field of each of those link records. This will -// be the *local* IP address associated with the interface attached to the -// link. We use the outbound interface and next hop information present in -// the vertex which have possibly been inherited from the root. -// -// To summarize, we're going to look at the node represented by and loop -// through its point-to-point links, adding a *host* route to the local IP -// address (at the side) for each of those links. -// - SPFIntraAddRouter (v); -// -// RFC2328 16.1. (5). -// -// Iterate the algorithm by returning to Step 2 until there are no more -// candidate vertices. -// - } -// -// Second stage of SPF calculation procedure's -// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); -// -// We're all done setting the routing information for the node at the root of -// the SPF tree. Delete all of the vertices and corresponding resources. Go -// possibly do it again for the next router. -// - delete m_spfroot; - m_spfroot = 0; -} - -// -// BUGBUG FIXME: This should probably be a method on Ipv4 -// -// Return the interface index corresponding to a given IP address -// - uint32_t -StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) -{ -// -// We have an IP address and a vertex ID of the root of the SPF tree. -// The question is what interface index does this address correspond to. -// The answer is a little complicated since we have to find a pointer to -// the node corresponding to the vertex ID, find the Ipv4 interface on that -// node in order to iterate the interfaces and find the one corresponding to -// the address in question. -// - Ipv4Address routerId = m_spfroot->GetVertexId (); -// -// Walk the list of nodes in the system looking for the one corresponding to -// the node at the root of the SPF tree. This is the node for which we are -// building the routing table. -// - std::vector >::iterator i = NodeList::Begin (); - for (; i != NodeList::End (); i++) - { - Ptr node = *i; - - Ptr rtr = - node->QueryInterface (StaticRouter::iid); -// -// If the node doesn't have a StaticRouter interface it can't be the one -// we're interested in. -// - if (rtr == 0) - { - continue; - } - - if (rtr->GetRouterId () == routerId) - { -// -// This is the node we're building the routing table for. We're going to need -// the Ipv4 interface to look for the ipv4 interface index. Since this node -// is participating in routing IP version 4 packets, it certainly must have -// an Ipv4 interface. -// - Ptr ipv4 = node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG (ipv4, - "StaticRouteManager::FindOutgoingInterfaceId (): " - "QI for interface failed"); -// -// Look through the interfaces on this node for one that has the IP address -// we're looking for. If we find one, return the corresponding interface -// index. -// - for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) - { - if (ipv4->GetAddress (i) == a) - { - NS_DEBUG ("StaticRouteManager::FindOutgoingInterfaceId (): " - "Interface match for " << a); - return i; - } - } - } - } -// -// Couldn't find it. -// - return 0; -} - -// -// This method is derived from quagga ospf_intra_add_router () -// -// This is where we are actually going to add the host routes to the routing -// tables of the individual nodes. -// -// The vertex passed as a parameter has just been added to the SPF tree. -// This vertex must have a valid m_root_oid, corresponding to the outgoing -// interface on the root router of the tree that is the first hop on the path -// to the vertex. The vertex must also have a next hop address, corresponding -// to the next hop on the path to the vertex. The vertex has an m_lsa field -// that has some number of link records. For each point to point link record, -// the m_linkData is the local IP address of the link. This corresponds to -// a destination IP address, reachable from the root, to which we add a host -// route. -// - void -StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) -{ - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ()"); - - NS_ASSERT_MSG (m_spfroot, - "StaticRouteManager::SPFIntraAddRouter (): Root pointer not set"); -// -// The root of the Shortest Path First tree is the router to which we are -// going to write the actual routing table entries. The vertex corresponding -// to this router has a vertex ID which is the router ID of that node. We're -// going to use this ID to discover which node it is that we're actually going -// to update. -// - Ipv4Address routerId = m_spfroot->GetVertexId (); - - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ():" - "Vertex ID = " << routerId); -// -// We need to walk the list of nodes looking for the one that has the router -// ID corresponding to the root vertex. This is the one we're going to write -// the routing information to. -// - std::vector >::iterator i = NodeList::Begin (); - for (; i != NodeList::End (); i++) - { - Ptr node = *i; -// -// The router ID is accessible through the StaticRouter interface, so we need -// to QI for that interface. If there's no StaticRouter interface, the node -// in question cannot be the router we want, so we continue. -// - Ptr rtr = - node->QueryInterface (StaticRouter::iid); - - if (rtr == 0) - { - continue; - } -// -// If the router ID of the current node is equal to the router ID of the -// root of the SPF tree, then this node is the one for which we need to -// write the routing tables. -// - if (rtr->GetRouterId () == routerId) - { - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " - "setting routes for node " << node->GetId ()); -// -// Routing information is updated using the Ipv4 interface. We need to QI -// for that interface. If the node is acting as an IP version 4 router, it -// should absolutely have an Ipv4 interface. -// - Ptr ipv4 = node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG (ipv4, - "StaticRouteManager::SPFIntraAddRouter (): " - "QI for interface failed"); -// -// Get the Static Router Link State Advertisement from the vertex we're -// adding the routes to. The LSA will have a number of attached Static Router -// Link Records corresponding to links off of that vertex / node. We're going -// to be interested in the records corresponding to point-to-point links. -// - StaticRouterLSA *lsa = v->GetLSA (); - NS_ASSERT_MSG (lsa, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected valid LSA in SPFVertex* v"); - - uint32_t nLinkRecords = lsa->GetNLinkRecords (); -// -// Iterate through the link records on the vertex to which we're going to add -// routes. To make sure we're being clear, we're going to add routing table -// entries to the tables on the node corresping to the root of the SPF tree. -// These entries will have routes to the IP addresses we find from looking at -// the local side of the point-to-point links found on the node described by -// the vertex . -// - for (uint32_t j = 0; j < nLinkRecords; j += 2) - { -// -// We are only concerned about point-to-point links -// - StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); - if (lr->GetLinkType () != StaticRouterLinkRecord::PointToPoint) - { - continue; - } - - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " - " Node " << node->GetId () << - " add route to " << lr->GetLinkData () << - " using next hop " << v->GetNextHop () << - " via interface " << v->GetOutgoingInterfaceId ()); -// -// Here's why we did all of that work. We're going to add a host route to the -// host address found in the m_linkData field of the point-to-point link -// record. In the case of a point-to-point link, this is the local IP address -// of the node connected to the link. Each of these point-to-point links -// will correspond to a local interface that has an IP address to which -// the node at the root of the SPF tree can send packets. The vertex -// (corresponding to the node that has these links and interfaces) has -// an m_nextHop address precalculated for us that is the address to which the -// root node should send packets to be forwarded to these IP addresses. -// Similarly, the vertex has an m_rootOif (outbound interface index) to -// which the packets should be send for forwarding. -// - ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (), - v->GetOutgoingInterfaceId ()); - } - } -// -// We've found the node and added the routes. Don't need to search forward -// for another node we'll never find. -// - return; - } -} - -// Derived from quagga ospf_vertex_add_parents () -// -// This is a somewhat oddly named method (blame quagga). Although you might -// expect it to add a parent *to* something, it actually adds a vertex -// to the list of children *in* each of its parents. -// -// Given a pointer to a vertex, it links back to the vertex's parent that it -// already has set and adds itself to that vertex's list of children. -// -// For now, only one parent (not doing equal-cost multipath) -// - void -StaticRouteManager::SPFVertexAddParent (SPFVertex* v) -{ - v->GetParent ()->AddChild (v); + return SimulationSingleton::Get ()-> + InitializeRoutes (); } } // namespace ns3 - -#ifdef RUN_SELF_TESTS - -// --------------------------------------------------------------------------- -// -// Unit Tests -// -// --------------------------------------------------------------------------- - -#include "ns3/test.h" - -namespace ns3 { - -class StaticRouterTestNode : public Node -{ -public: - StaticRouterTestNode (); - -private: - virtual void DoAddDevice (Ptr device) const {}; - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); -}; - -StaticRouterTestNode::StaticRouterTestNode () -{ -// Ptr ipv4 = Create (this); -} - - TraceResolver* -StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) -{ - return 0; -} - -class StaticRouteManagerTest : public Test { -public: - StaticRouteManagerTest (); - virtual ~StaticRouteManagerTest (); - virtual bool RunTests (void); -}; - -StaticRouteManagerTest::StaticRouteManagerTest () - : Test ("StaticRouteManager") -{ -} - -StaticRouteManagerTest::~StaticRouteManagerTest () -{} - - bool -StaticRouteManagerTest::RunTests (void) -{ - bool ok = true; - - CandidateQueue candidate; - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = new SPFVertex; - v->SetDistanceFromRoot (rand () % 100); - candidate.Push (v); - } - - uint32_t lastDistance = 0; - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = candidate.Pop (); - if (v->GetDistanceFromRoot () < lastDistance) - { - ok = false; - } - lastDistance = v->GetDistanceFromRoot (); - delete v; - v = 0; - } - - // Build fake link state database; four routers (0-3), 3 point-to-point - // links - // - // n0 - // \ link 0 - // \ link 2 - // n2 -------------------------n3 - // / - // / link 1 - // n1 - // - // link0: 10.1.1.1/30, 10.1.1.2/30 - // link1: 10.1.2.1/30, 10.1.2.2/30 - // link2: 10.1.3.1/30, 10.1.3.2/30 - // - // Router 0 - StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.2", // router ID 0.0.0.2 - "10.1.1.1", // local ID - 1); // metric - - StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.1.1", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa0 = new StaticRouterLSA (); - lsa0->SetLinkStateId ("0.0.0.0"); - lsa0->SetAdvertisingRouter ("0.0.0.0"); - lsa0->AddLinkRecord (lr0); - lsa0->AddLinkRecord (lr1); - - // Router 1 - StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.2", - "10.1.2.1", - 1); - - StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.2.1", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa1 = new StaticRouterLSA (); - lsa1->SetLinkStateId ("0.0.0.1"); - lsa1->SetAdvertisingRouter ("0.0.0.1"); - lsa1->AddLinkRecord (lr2); - lsa1->AddLinkRecord (lr3); - - // Router 2 - StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.0", - "10.1.1.2", - 1); - - StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.1.2", - "255.255.255.252", - 1); - - StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.1", - "10.1.2.2", - 1); - - StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.2.2", - "255.255.255.252", - 1); - - StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.3", - "10.1.3.2", - 1); - - StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.3.2", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa2 = new StaticRouterLSA (); - lsa2->SetLinkStateId ("0.0.0.2"); - lsa2->SetAdvertisingRouter ("0.0.0.2"); - lsa2->AddLinkRecord (lr4); - lsa2->AddLinkRecord (lr5); - lsa2->AddLinkRecord (lr6); - lsa2->AddLinkRecord (lr7); - lsa2->AddLinkRecord (lr8); - lsa2->AddLinkRecord (lr9); - - // Router 3 - StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.2", - "10.1.2.1", - 1); - - StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.2.1", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa3 = new StaticRouterLSA (); - lsa3->SetLinkStateId ("0.0.0.3"); - lsa3->SetAdvertisingRouter ("0.0.0.3"); - lsa3->AddLinkRecord (lr10); - lsa3->AddLinkRecord (lr11); - - // Test the database - StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); - srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0); - srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1); - srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2); - srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3); - NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); - - // XXX next, calculate routes based on the manually created LSDB - StaticRouteManager* srm = new StaticRouteManager (); - srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB - // Note-- this will succeed without any nodes in the topology - // because the NodeList is empty - srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 - - // This delete clears the srm, which deletes the LSDB, which clears - // all of the LSAs, which each destroys the attached LinkRecords. - delete srm; - - return ok; -} - -// Instantiate this class for the unit tests -static StaticRouteManagerTest g_staticRouteManagerTest; - -} // namespace ns3 - -#endif diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 67e120da4..e8616d573 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -13,603 +13,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef STATIC_ROUTE_MANAGER_H #define STATIC_ROUTE_MANAGER_H -#include -#include -#include -#include -#include "ns3/object.h" -#include "ns3/ptr.h" -#include "ns3/ipv4-address.h" -#include "static-router.h" - namespace ns3 { -const uint32_t SPF_INFINITY = 0xffffffff; - -class CandidateQueue; - -/** - * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328, - * Section 16. - * - * Each router in the simulation is associated with an SPFVertex object. When - * calculating routes, each of these routers is, in turn, chosen as the "root" - * of the calculation and routes to all of the other routers are eventually - * saved in the routing tables of each of the chosen nodes. Each of these - * routers in the calculation has an associated SPFVertex. - * - * The "Root" vertex is the SPFVertex representing the router that is having - * its routing tables set. The SPFVertex objects representing other routers - * or networks in the simulation are arranged in the SPF tree. It is this - * tree that represents the Shortest Paths to the other networks. - * - * Each SPFVertex has a pointer to the Static Router Link State Advertisement - * (LSA) that its underlying router has exported. Within these LSAs are - * Static Router Link Records that describe the point to point links from the - * underlying router to other nodes (represented by other SPFVertex objects) - * in the simulation topology. The combination of the arrangement of the - * SPFVertex objects in the SPF tree, along with the details of the link - * records that connect them provide the information required to construct the - * required routes. - */ -class SPFVertex -{ -public: -/** - * @enum Enumeration of the possible types of SPFVertex objects. Currently - * we use VertexRouter to identify objects that represent a router in the - * simulation topology, and VertexNetwork to identify objects that represent - * a network. - */ - enum VertexType { - VertexUnknown = 0, /**< Uninitialized Link Record */ - VertexRouter, /**< Vertex representing a router in the topology */ - VertexNetwork /**< Vertex representing a network in the topology */ - }; -/** - * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First - * Vertex). - * - * The Vertex Type is set to VertexUnknown, the Vertex ID is set to - * 255.255.255.255, and the distance from root is set to infinity - * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to - * null as is the parent SPFVertex. The outgoing interface index is set to - * infinity, the next hop address is set to 0.0.0.0 and the list of children - * of the SPFVertex is initialized to empty. - * - * @see VertexType - */ - SPFVertex(); -/** - * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). - * - * The Vertex Type is initialized to VertexRouter and the Vertex ID is found - * from the Link State ID of the Link State Advertisement (LSA) passed as a - * parameter. The Link State ID is set to the Router ID of the advertising - * router. The referenced LSA (m_lsa) is set to the given LSA. Other than - * these members, initialization is as in the default constructor. - * of the SPFVertex is initialized to empty. - * - * @see SPFVertex::SPFVertex () - * @see VertexType - * @see StaticRouterLSA - * @param lsa The Link State Advertisement used for finding initial values. - */ - SPFVertex(StaticRouterLSA* lsa); -/** - * @brief Destroy an SPFVertex (Shortest Path First Vertex). - * - * The children vertices of the SPFVertex are recursively deleted. - * - * @see SPFVertex::SPFVertex () - */ - ~SPFVertex(); -/** - * @brief Get the Vertex Type field of a SPFVertex object. - * - * The Vertex Type describes the kind of simulation object a given SPFVertex - * represents. - * - * @see VertexType - * @returns The VertexType of the current SPFVertex object. - */ - VertexType GetVertexType (void) const; -/** - * @brief Set the Vertex Type field of a SPFVertex object. - * - * The Vertex Type describes the kind of simulation object a given SPFVertex - * represents. - * - * @see VertexType - * @param The new VertexType for the current SPFVertex object. - */ - void SetVertexType (VertexType type); -/** - * @brief Get the Vertex ID field of a SPFVertex object. - * - * The Vertex ID uniquely identifies the simulation object a given SPFVertex - * represents. Typically, this is the Router ID for SPFVertex objects - * representing routers, and comes from the Link State Advertisement of a - * router aggregated to a node in the simulation. These IDs are allocated - * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increasing as new routers are - * instantiated. - * - * @returns The Ipv4Address Vertex ID of the current SPFVertex object. - */ - Ipv4Address GetVertexId (void) const; -/** - * @brief Set the Vertex ID field of a SPFVertex object. - * - * The Vertex ID uniquely identifies the simulation object a given SPFVertex - * represents. Typically, this is the Router ID for SPFVertex objects - * representing routers, and comes from the Link State Advertisement of a - * router aggregated to a node in the simulation. These IDs are allocated - * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increasing as new routers are - * instantiated. - * - * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. - */ - void SetVertexId (Ipv4Address id); -/** - * @brief Get the Static Router Link State Advertisement returned by the - * Static Router represented by this SPFVertex during the route discovery - * process. - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @returns A pointer to the StaticRouterLSA found by the router represented - * by this SPFVertex object. - */ - StaticRouterLSA* GetLSA (void) const; -/** - * @brief Set the Static Router Link State Advertisement returned by the - * Static Router represented by this SPFVertex during the route discovery - * process. - * - * @see SPFVertex::GetLSA () - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You - * must not delete the LSA after calling this method. - * @param A pointer to the StaticRouterLSA. - */ - void SetLSA (StaticRouterLSA* lsa); -/** - * @brief Get the distance from the root vertex to "this" SPFVertex object. - * - * Each router in the simulation is associated with an SPFVertex object. When - * calculating routes, each of these routers is, in turn, chosen as the "root" - * of the calculation and routes to all of the other routers are eventually - * saved in the routing tables of each of the chosen nodes. Each of these - * routers in the calculation has an associated SPFVertex. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex to which - * a route is being calculated from the root. The distance from the root that - * we're asking for is the number of hops from the root vertex to the vertex - * in question. - * - * The distance is calculated during route discovery and is stored in a - * member variable. This method simply fetches that value. - * - * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex. - */ - uint32_t GetDistanceFromRoot (void) const; -/** - * @brief Set the distance from the root vertex to "this" SPFVertex object. - * - * Each router in the simulation is associated with an SPFVertex object. When - * calculating routes, each of these routers is, in turn, chosen as the "root" - * of the calculation and routes to all of the other routers are eventually - * saved in the routing tables of each of the chosen nodes. Each of these - * routers in the calculation has an associated SPFVertex. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex to which - * a route is being calculated from the root. The distance from the root that - * we're asking for is the number of hops from the root vertex to the vertex - * in question. - * - * @param distance The distance, in hops, from the root SPFVertex to "this" - * SPFVertex. - */ - void SetDistanceFromRoot (uint32_t distance); -/** - * @brief Get the interface ID that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The outgoing interface that we're asking for is the interface - * index on the root node that should be used to start packets along the - * path to "this" vertex. - * - * When initializing the root SPFVertex, the interface ID is determined by - * examining the Static Router Link Records of the Link State Advertisement - * generated by the root node's StaticRouter. These interfaces are used to - * forward packets off of the root's network down those links. As other - * vertices are discovered which are further away from the root, they will - * be accessible down one of the paths begun by a Static Router Link Record. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to the interface of that - * first hop. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method, the root node is asking, "which of my local interfaces - * should I use to get a packet to the network or host represented by 'this' - * SPFVertex." - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @returns The interface index to use when forwarding packets to the host - * or network represented by "this" SPFVertex. - */ - uint32_t GetOutgoingInterfaceId (void) const; -/** - * @brief Set the interface ID that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The outgoing interface that we're asking for is the interface - * index on the root node that should be used to start packets along the - * path to "this" vertex. - * - * When initializing the root SPFVertex, the interface ID is determined by - * examining the Static Router Link Records of the Link State Advertisement - * generated by the root node's StaticRouter. These interfaces are used to - * forward packets off of the root's network down those links. As other - * vertices are discovered which are further away from the root, they will - * be accessible down one of the paths begun by a Static Router Link Record. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to the interface of that - * first hop. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method, we are letting the root node know which of its local - * interfaces it should use to get a packet to the network or host represented - * by "this" SPFVertex. - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @param id The interface index to use when forwarding packets to the host or - * network represented by "this" SPFVertex. - */ - void SetOutgoingInterfaceId (uint32_t id); -/** - * @brief Get the IP address that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The IP address that we're asking for is the address on the - * remote side of a link off of the root node that should be used as the - * destination for packets along the path to "this" vertex. - * - * When initializing the root SPFVertex, the IP address used when forwarding - * packets is determined by examining the Static Router Link Records of the - * Link State Advertisement generated by the root node's StaticRouter. This - * address is used to forward packets off of the root's network down those - * links. As other vertices / nodes are discovered which are further away - * from the root, they will be accessible down one of the paths via a link - * described by one of these Static Router Link Records. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to a first hop router down - * an interface. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method, the root node is asking, "which router should I send a - * packet to in order to get that packet to the network or host represented - * by 'this' SPFVertex." - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @returns The IP address to use when forwarding packets to the host - * or network represented by "this" SPFVertex. - */ - Ipv4Address GetNextHop (void) const; -/** - * @brief Set the IP address that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The IP address that we're asking for is the address on the - * remote side of a link off of the root node that should be used as the - * destination for packets along the path to "this" vertex. - * - * When initializing the root SPFVertex, the IP address used when forwarding - * packets is determined by examining the Static Router Link Records of the - * Link State Advertisement generated by the root node's StaticRouter. This - * address is used to forward packets off of the root's network down those - * links. As other vertices / nodes are discovered which are further away - * from the root, they will be accessible down one of the paths via a link - * described by one of these Static Router Link Records. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to a first hop router down - * an interface. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method we are telling the root node which router it should send - * should I send a packet to in order to get that packet to the network or - * host represented by 'this' SPFVertex." - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @param nextHop The IP address to use when forwarding packets to the host - * or network represented by "this" SPFVertex. - */ - void SetNextHop (Ipv4Address nextHop); -/** - * @brief Get a pointer to the SPFVector that is the parent of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. - * - * This method returns a pointer to the parent node of "this" SPFVertex - * (both of which reside in that SPF tree). - * - * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex - * in the SPF tree. - */ - SPFVertex* GetParent (void) const; -/** - * @brief Set the pointer to the SPFVector that is the parent of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. - * - * This method sets the parent pointer of "this" SPFVertex (both of which - * reside in that SPF tree). - * - * @param parent A pointer to the SPFVertex that is the parent of "this" - * SPFVertex* in the SPF tree. - */ - void SetParent (SPFVertex* parent); -/** - * @brief Get the number of children of "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. Each vertex - * in the SPF tree can have a number of children that represent host or - * network routes available via that vertex. - * - * This method returns the number of children of "this" SPFVertex (which - * reside in the SPF tree). - * - * @returns The number of children of "this" SPFVertex (which reside in the - * SPF tree). - */ - uint32_t GetNChildren (void) const; -/** - * @brief Get a borrowed SPFVertex pointer to the specified child of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. Each vertex - * in the SPF tree can have a number of children that represent host or - * network routes available via that vertex. - * - * This method the number of children of "this" SPFVertex (which reside in - * the SPF tree. - * - * @see SPFVertex::GetNChildren - * @param n The index (from 0 to the number of children minus 1) of the - * child SPFVertex to return. - * @warning The pointer returned by GetChild () is a borrowed pointer. You - * do not have any ownership of the underlying object and must not delete - * that object. - * @returns A pointer to the specified child SPFVertex (which resides in the - * SPF tree). - */ - SPFVertex* GetChild (uint32_t n) const; -/** - * @brief Get a borrowed SPFVertex pointer to the specified child of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. Each vertex - * in the SPF tree can have a number of children that represent host or - * network routes available via that vertex. - * - * This method the number of children of "this" SPFVertex (which reside in - * the SPF tree. - * - * @see SPFVertex::GetNChildren - * @param n The index (from 0 to the number of children minus 1) of the - * child SPFVertex to return. - * @warning Ownership of the pointer added to the children of "this" - * SPFVertex is transferred to the "this" SPFVertex. You must not delete the - * (now) child SPFVertex after calling this method. - * @param child A pointer to the SPFVertex (which resides in the SPF tree) to - * be added to the list of children of "this" SPFVertex. - * @returns The number of children of "this" SPFVertex after the addition of - * the new child. - */ - uint32_t AddChild (SPFVertex* child); - -private: - VertexType m_vertexType; - Ipv4Address m_vertexId; - StaticRouterLSA* m_lsa; - uint32_t m_distanceFromRoot; - uint32_t m_rootOif; - Ipv4Address m_nextHop; - SPFVertex* m_parent; - typedef std::list ListOfSPFVertex_t; - ListOfSPFVertex_t m_children; -/** - * @brief The SPFVertex copy construction is disallowed. There's no need for - * it and a compiler provided shallow copy would be wrong. - */ - SPFVertex (SPFVertex& v); -/** - * @brief The SPFVertex copy assignment operator is disallowed. There's no - * need for it and a compiler provided shallow copy would be wrong. - */ - SPFVertex& operator= (SPFVertex& v); -}; - -/** - * @brief The Link State DataBase (LSDB) of the Static Route Manager. - * - * Each node in the simulation participating in static routing has a - * StaticRouter interface. The primary job of this interface is to export - * Static Router Link State Advertisements (LSAs). These advertisements in - * turn contain a number of Static Router Link Records that describe the - * point to point links from the underlying node to other nodes (that will - * also export their own LSAs. - * - * This class implements a searchable database of LSAs gathered from every - * router in the simulation. - */ -class StaticRouteManagerLSDB -{ -public: -/** - * @brief Construct an empty Static Router Manager Link State Database. - * - * The database map composing the Link State Database is initialized in - * this constructor. - */ - StaticRouteManagerLSDB (); -/** - * @brief Destroy an empty Static Router Manager Link State Database. - * - * The database map is walked and all of the Link State Advertisements stored - * in the database are freed; then the database map itself is clear ()ed to - * release any remaining resources. - */ - ~StaticRouteManagerLSDB (); -/** - * @brief Insert an IP address / Link State Advertisement pair into the Link - * State Database. - * - * The IPV4 address and the StaticRouterLSA given as parameters are converted - * to an STL pair and are inserted into the database map. - * - * @see StaticRouterLSA - * @see Ipv4Address - * @param addr The IP address associated with the LSA. Typically the Router - * ID. - * @param lsa A pointer to the Link State Advertisement for the router. - */ - void Insert(Ipv4Address addr, StaticRouterLSA* lsa); -/** - * @brief Look up the Link State Advertisement associated with the given - * IP Address. - * - * The database map is searched for the given IPV4 address and corresponding - * StaticRouterLSA is returned. - * - * @see StaticRouterLSA - * @see Ipv4Address - * @param addr The IP address associated with the LSA. Typically the Router - * ID. - * @returns A pointer to the Link State Advertisement for the router specified - * by the IP address addr. - */ - StaticRouterLSA* GetLSA (Ipv4Address addr) const; -/** - * @brief Set all LSA flags to an initialized state, for SPF computation - * - * This function walks the database and resets the status flags of all of the - * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done - * prior to each SPF calculation to reset the state of the SPFVertex structures - * that will reference the LSAs during the calculation. - * - * @see StaticRouterLSA - * @see SPFVertex - */ - void Initialize (); - -private: - typedef std::map LSDBMap_t; - typedef std::pair LSDBPair_t; - - LSDBMap_t m_database; -/** - * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no - * need for it and a compiler provided shallow copy would be hopelessly wrong. - */ - StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); -/** - * @brief The SPFVertex copy assignment operator is disallowed. There's no - * need for it and a compiler provided shallow copy would be wrong. - */ - StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); -}; - /** * @brief A global static router * @@ -621,35 +30,20 @@ private: * * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. */ -class StaticRouteManager : public Object +class StaticRouteManager { public: - static const InterfaceId iid; - StaticRouteManager (); /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a StaticRouter interface. * */ - virtual void BuildStaticRoutingDatabase(); + static void BuildStaticRoutingDatabase(); /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables */ - virtual void InitializeRoutes(); -/** - * @brief Debugging routine; allow client code to supply a pre-built LSDB - */ - void DebugUseLsdb (StaticRouteManagerLSDB*); -/** - * @brief Debugging routine; call the core SPF from the unit tests - */ - void DebugSPFCalculate (Ipv4Address root); - - virtual ~StaticRouteManager (); - -protected: - + static void InitializeRoutes(); private: /** * @brief Static Route Manager copy construction is disallowed. There's no @@ -662,18 +56,6 @@ private: * need for it and a compiler provided shallow copy would be hopelessly wrong. */ StaticRouteManager& operator= (StaticRouteManager& srm); - - SPFVertex* m_spfroot; - StaticRouteManagerLSDB* m_lsdb; - void SPFCalculate (Ipv4Address root); - void SPFNext (SPFVertex*, CandidateQueue&); - int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* l, uint32_t distance); - void SPFVertexAddParent(SPFVertex* v); - StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* prev_link); - void SPFIntraAddRouter(SPFVertex* v); - uint32_t FindOutgoingInterfaceId(Ipv4Address a); }; } // namespace ns3 From c9b7590dd95575b768a7975256d76ad020d2f4a3 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 20 Jul 2007 14:22:46 -0700 Subject: [PATCH 075/278] turn off debug flag --- examples/simple-static-routing.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 01848c92c..fb6568f96 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -85,7 +85,6 @@ int main (int argc, char *argv[]) DebugComponentEnable("StaticRouter"); DebugComponentEnable("StaticRouteManager"); #endif - DebugComponentEnable("StaticRouteManager"); // Set up some default values for the simulation. Use the Bind() // technique to tell the system what subclass of Queue to use, From 897a5187506161568000a96e786372f870a0d418 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 20 Jul 2007 14:28:18 -0700 Subject: [PATCH 076/278] parenthesis police were here --- examples/simple-static-routing.cc | 60 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index fb6568f96..544e68721 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -76,17 +76,17 @@ int main (int argc, char *argv[]) // Users may find it convenient to turn on explicit debugging // for selected modules; the below lines suggest how to do this #if 0 - DebugComponentEnable("Object"); - DebugComponentEnable("Queue"); - DebugComponentEnable("DropTailQueue"); - DebugComponentEnable("Channel"); - DebugComponentEnable("PointToPointChannel"); - DebugComponentEnable("PointToPointNetDevice"); - DebugComponentEnable("StaticRouter"); - DebugComponentEnable("StaticRouteManager"); + DebugComponentEnable ("Object"); + DebugComponentEnable ("Queue"); + DebugComponentEnable ("DropTailQueue"); + DebugComponentEnable ("Channel"); + DebugComponentEnable ("PointToPointChannel"); + DebugComponentEnable ("PointToPointNetDevice"); + DebugComponentEnable ("StaticRouter"); + DebugComponentEnable ("StaticRouteManager"); #endif - // Set up some default values for the simulation. Use the Bind() + // Set up some default values for the simulation. Use the Bind () // technique to tell the system what subclass of Queue to use, // and what the queue limit is @@ -105,7 +105,7 @@ int main (int argc, char *argv[]) //Bind ("DropTailQueue::m_maxPackets", 30); // Allow the user to override any of the defaults and the above - // Bind()s at run-time, via command-line arguments + // Bind ()s at run-time, via command-line arguments CommandLine::Parse (argc, argv); // Here, we will explicitly create four nodes. In more sophisticated @@ -118,30 +118,30 @@ int main (int argc, char *argv[]) // We create the channels first without any IP addressing information Ptr channel0 = PointToPointTopology::AddPointToPointLink ( - n0, n2, DataRate(5000000), MilliSeconds(2)); + n0, n2, DataRate (5000000), MilliSeconds (2)); Ptr channel1 = PointToPointTopology::AddPointToPointLink ( - n1, n2, DataRate(5000000), MilliSeconds(2)); + n1, n2, DataRate (5000000), MilliSeconds (2)); Ptr channel2 = PointToPointTopology::AddPointToPointLink ( - n2, n3, DataRate(1500000), MilliSeconds(10)); + n2, n3, DataRate (1500000), MilliSeconds (10)); // Later, we add IP addresses. PointToPointTopology::AddIpv4Addresses ( - channel0, n0, Ipv4Address("10.1.1.1"), - n2, Ipv4Address("10.1.1.2")); + channel0, n0, Ipv4Address ("10.1.1.1"), + n2, Ipv4Address ("10.1.1.2")); PointToPointTopology::AddIpv4Addresses ( - channel1, n1, Ipv4Address("10.1.2.1"), - n2, Ipv4Address("10.1.2.2")); + channel1, n1, Ipv4Address ("10.1.2.1"), + n2, Ipv4Address ("10.1.2.2")); PointToPointTopology::AddIpv4Addresses ( - channel2, n2, Ipv4Address("10.1.3.1"), - n3, Ipv4Address("10.1.3.2")); + channel2, n2, Ipv4Address ("10.1.3.1"), + n3, Ipv4Address ("10.1.3.2")); - if (RoutingEnvironment::StaticRoutingEnabled()) + if (RoutingEnvironment::StaticRoutingEnabled ()) { StaticRouteManager::BuildStaticRoutingDatabase (); StaticRouteManager::InitializeRoutes (); @@ -151,26 +151,26 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - Ipv4Address("10.1.3.2"), + Ipv4Address ("10.1.3.2"), 80, "Udp", - ConstantVariable(1), - ConstantVariable(0)); + ConstantVariable (1), + ConstantVariable (0)); // Start the application - ooff->Start(Seconds(1.0)); - ooff->Stop (Seconds(10.0)); + ooff->Start (Seconds (1.0)); + ooff->Stop (Seconds (10.0)); // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - Ipv4Address("10.1.2.1"), + Ipv4Address ("10.1.2.1"), 80, "Udp", - ConstantVariable(1), - ConstantVariable(0)); + ConstantVariable (1), + ConstantVariable (0)); // Start the application - ooff->Start(Seconds(1.1)); - ooff->Stop (Seconds(10.0)); + ooff->Start (Seconds (1.1)); + ooff->Stop (Seconds (10.0)); // Here, finish off packet routing configuration // This will likely set by some global StaticRouting object in the future From bb8c8e5fa82cfda7abfd62615cf679655e0653aa Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 23 Jul 2007 14:31:24 -0700 Subject: [PATCH 077/278] remove doxygen warnings, make waf work --- src/routing/static-route-manager-impl.h | 15 +++++++-------- src/routing/static-router.h | 17 ++++++++++------- src/routing/wscript | 1 + 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/routing/static-route-manager-impl.h b/src/routing/static-route-manager-impl.h index a4d97db77..ec886fccb 100644 --- a/src/routing/static-route-manager-impl.h +++ b/src/routing/static-route-manager-impl.h @@ -59,10 +59,11 @@ class SPFVertex { public: /** - * @enum Enumeration of the possible types of SPFVertex objects. Currently - * we use VertexRouter to identify objects that represent a router in the - * simulation topology, and VertexNetwork to identify objects that represent - * a network. + * @brief Enumeration of the possible types of SPFVertex objects. + * + * Currently we use VertexRouter to identify objects that represent a router + * in the simulation topology, and VertexNetwork to identify objects that + * represent a network. */ enum VertexType { VertexUnknown = 0, /**< Uninitialized Link Record */ @@ -124,7 +125,7 @@ public: * represents. * * @see VertexType - * @param The new VertexType for the current SPFVertex object. + * @param type The new VertexType for the current SPFVertex object. */ void SetVertexType (VertexType type); /** @@ -178,7 +179,7 @@ public: * @see StaticRouter::DiscoverLSAs () * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You * must not delete the LSA after calling this method. - * @param A pointer to the StaticRouterLSA. + * @param lsa A pointer to the StaticRouterLSA. */ void SetLSA (StaticRouterLSA* lsa); /** @@ -486,8 +487,6 @@ public: * the SPF tree. * * @see SPFVertex::GetNChildren - * @param n The index (from 0 to the number of children minus 1) of the - * child SPFVertex to return. * @warning Ownership of the pointer added to the children of "this" * SPFVertex is transferred to the "this" SPFVertex. You must not delete the * (now) child SPFVertex after calling this method. diff --git a/src/routing/static-router.h b/src/routing/static-router.h index 85ec59fad..9465c1319 100644 --- a/src/routing/static-router.h +++ b/src/routing/static-router.h @@ -40,9 +40,11 @@ class StaticRouterLinkRecord { public: /** - * @enum Enumeration of the possible types of Static Router Link Records. - * These are defined in the OSPF spec. We currently only use PointToPoint and - * StubNetwork types. + * @enum LinkType + * @brief Enumeration of the possible types of Static Router Link Records. + * + * These values are defined in the OSPF spec. We currently only use + * PointToPoint and StubNetwork types. */ enum LinkType { Unknown = 0, /**< Uninitialized Link Record */ @@ -102,7 +104,7 @@ public: * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent * neighbor's IP address * - * @param An Ipv4Address to store in the Link ID field of the record. + * @param addr An Ipv4Address to store in the Link ID field of the record. */ void SetLinkId(Ipv4Address addr); /** @@ -126,7 +128,7 @@ public: * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the * network mask * - * @param An Ipv4Address to store in the Link Data field of the record. + * @param addr An Ipv4Address to store in the Link Data field of the record. */ void SetLinkData(Ipv4Address addr); /** @@ -225,7 +227,8 @@ class StaticRouterLSA { public: /** - * @enum Enumeration of the possible values of the status flag in the Router + * @enum SPFStatus + * @brief Enumeration of the possible values of the status flag in the Router * Link State Advertisements. */ enum SPFStatus { @@ -247,7 +250,7 @@ public: * * @param status The status to of the new LSA. * @param linkStateId The Ipv4Address for the link state ID field. - * @param advertisingRouter The Ipv4Address for the advertising router field. + * @param advertisingRtr The Ipv4Address for the advertising router field. */ StaticRouterLSA(SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr); diff --git a/src/routing/wscript b/src/routing/wscript index 79f8c2b21..8cdee7644 100644 --- a/src/routing/wscript +++ b/src/routing/wscript @@ -13,6 +13,7 @@ def build(bld): 'routing-environment.cc', 'static-router.cc', 'static-route-manager.cc', + 'static-route-manager-impl.cc', 'candidate-queue.cc', ] From 2f682ca9f8d424dfb70c9ad1ef77693c74b7b16a Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 23 Jul 2007 15:53:37 -0700 Subject: [PATCH 078/278] single populate call --- examples/simple-static-routing.cc | 3 +-- src/routing/static-route-manager.cc | 7 +++++++ src/routing/static-route-manager.h | 19 ++++++++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 544e68721..02efaa407 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -143,8 +143,7 @@ int main (int argc, char *argv[]) if (RoutingEnvironment::StaticRoutingEnabled ()) { - StaticRouteManager::BuildStaticRoutingDatabase (); - StaticRouteManager::InitializeRoutes (); + StaticRouteManager::PopulateRoutingTables (); } // Create the OnOff application to send UDP datagrams of size diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 09ced494f..b3a0cb6ff 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -28,6 +28,13 @@ namespace ns3 { // // --------------------------------------------------------------------------- + void +StaticRouteManager::PopulateRoutingTables () +{ + BuildStaticRoutingDatabase (); + InitializeRoutes (); +} + void StaticRouteManager::BuildStaticRoutingDatabase () { diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index e8616d573..4f1cdc8ae 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -33,18 +33,31 @@ namespace ns3 { class StaticRouteManager { public: +/** + * @brief Build a routing database and initialize the routing tables of + * the nodes in the simulation. + * + * All this function does is call BuildStaticRoutingDatabase () and + * InitializeRoutes (). There's no reason to export the two-step process + * since a high-level caller has no need to know how we're implementing the + * process. + * + * @see BuildStaticRoutingDatabase (); + * @see InitializeRoutes (); + */ + static void PopulateRoutingTables (); +private: /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a StaticRouter interface. * */ - static void BuildStaticRoutingDatabase(); + static void BuildStaticRoutingDatabase (); /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables */ - static void InitializeRoutes(); -private: + static void InitializeRoutes (); /** * @brief Static Route Manager copy construction is disallowed. There's no * need for it and a compiler provided shallow copy would be hopelessly wrong. From bc634975d4bb48987d78fa504ad5e6a8c9f9524e Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 23 Jul 2007 19:02:55 -0700 Subject: [PATCH 079/278] remove old routing code --- examples/simple-static-routing.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 02efaa407..9a7d66dcf 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -171,14 +171,6 @@ int main (int argc, char *argv[]) ooff->Start (Seconds (1.1)); ooff->Stop (Seconds (10.0)); - // Here, finish off packet routing configuration - // This will likely set by some global StaticRouting object in the future - Ptr ipv4; - ipv4 = n0->QueryInterface (Ipv4::iid); - ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); - ipv4 = n3->QueryInterface (Ipv4::iid); - ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); - // Configure tracing of all enqueue, dequeue, and NetDevice receive events // Trace output will be sent to the simple-static-routing.tr file AsciiTrace asciitrace ("simple-static-routing.tr"); From bdf28a79fc9e376b723ff5bcd04623f363db8a7e Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 23 Jul 2007 19:27:01 -0700 Subject: [PATCH 080/278] revise README --- README.routing | 125 +++++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 46 deletions(-) diff --git a/README.routing b/README.routing index 7b5166f5c..2d8e0f88a 100644 --- a/README.routing +++ b/README.routing @@ -1,31 +1,52 @@ -Routing overview, mid-July - -This is a proposal to add global static routing to ns-3 - -The previously announced roadmap: -* July 15: Support IPv4 static routing with PointToPoint numbered links -* August 15: Extend IPv4 static routing to Ethernet (shared links), add static multicast forwarding over Ethernet and PointToPoint -* Sept 15: Add static multicast forwarding over wireless interface - -This would provide the first bullet above. - -Note: This is orthogonal to Gustavo's OLSR code, but could also exist -as a static routing protocol in the framework that he proposes; right now, -this just writes directly into the existing Ipv4 routing API - -1. Code: - -- source code is in a routing module src/routing/ -- an example script is in examples/simple-static-routing.cc -- StaticRouteManager is added in the run-tests unit tests - -2. Approach +Static routing overview +--------------- +This is brief documentation of a proposal to add global static routing to ns-3 Static routing is used to automatically populate the forwarding tables in a topology without running a dynamic routing protocol or asking the user to manually enter routes themselves. -A single object (StaticRouteManager) is responsible for populating +The previously announced roadmap: +* July 15: Support IPv4 static routing with PointToPoint numbered links +* August 15: Extend IPv4 static routing to Ethernet (shared links), +add static multicast forwarding over Ethernet and PointToPoint +* Sept 15: Add static multicast forwarding over wireless interface + +This code would provide the first bullet above. + +Note: This is orthogonal to Gustavo's OLSR code, but could also exist +as a static routing protocol in the framework that he proposes; right now, +this code just writes directly into the existing Ipv4 routing API + +1. Code: + +- source code is in a routing module src/routing/ +- an example script is in examples/simple-static-routing.cc. It produces the +same output as simple-p2p.cc +- StaticRouteManager is added in the run-tests unit tests + +2. API: + +The public API is very minimal. + +- user scripts include the following: +#include "ns3/routing-environment.h" +#include "ns3/static-route-manager.h" + +- A single default value (default false) enables static routing + Bind ("DoStaticRouting", "true"); + +- The call to build the static routes themselves is a single method, +called after the topology has been addressed: + + if (RoutingEnvironment::StaticRoutingEnabled ()) + { + StaticRouteManager::PopulateRoutingTables (); + } + +3. Approach: + +A singleton object (StaticRouteManager) is responsible for populating the static routes on each node, using the public Ipv4 API of that node. It queries each node in the topology for a "staticRouter" interface. If found, it uses the API of that interface to obtain a "link state @@ -38,13 +59,6 @@ the StaticRouteManager executes the OSPF shortest path first (SPF) computation on the database, and populates the routing tables on each node. -This computation is initiated during the pre-simulation phase (after -topology and IP addressing has been done) with the following lines of code, -presently: - Ptr routeManager = Create (); - routeManager->BuildStaticRoutingDatabase (); - routeManager->InitializeRoutes (); - The quagga (http://www.quagga.net) OSPF implementation was used as the basis for the routing computation logic. One benefit of following an existing OSPF SPF implementation is that @@ -60,34 +74,53 @@ straightforward now that the underlying OSPF SPF framework is in place. Presently, we can handle IPv4 point-to-point, numbered links, and we do not do equal-cost multipath. -3. Bootstrapping - -Static routing can be enabled using a DoStaticRouting flag in the -default value system: - Bind ("DoStaticRouting", "true"); -This bind tells the system to use global static routing. It results in -a StaticRouter interface being aggregated to the internet nodes and the -creation of a Route Manager component to oversee the route generation. - -If this flag is true, when an InternetNode is created, it will aggregate -a routing interface to it. +The support for this relies on the node object supporting a StaticRouter +interface. This can be manually added to each node, or alternatively, +we have modified InternetNode::Construct() as follows: if (RoutingEnvironment::StaticRoutingEnabled()) { Ptr staticRouter = Create (this); Object::AddInterface (staticRouter); } -this flag is also tested before creating a StaticRouteManager object. 4. Some open issues +- trying to enable this with the default value framework raised some +questions. Access to an underlying default variable is required +across compilation units. The routing environment was designed +to put everything in one compilation unit. Whether this is good +practice or just overly paranoid is for further discussion. An +alternative may be to define some kind of test with the same default +value system such as +if (IsBound("DoStaticRouting", "true")) ... + +- along the same lines, Bind() is kind of an oddball in the present +system. We do NodeList::Begin (), Simulator::Run (), +CommandLine::Parse (); but simply Bind (). This isn't very consistent. + +(note: the choice of "bind()" was due to ns-2's methods of the same name) + +Perhaps it would be better to do something like, + +Configurator::Set ("DoStaticRouting", "true"); + +if (Configurator::IsEqual ("DoStaticRouting", "true")) + { + } + - how transparent vs. explicit the enabling of static routing should be (e.g., if we have a higher layer Inversion-of-Control framework, do these static routing functions exist in some kind of Init() or Presimulate() -method?) +method?). Presently, it is explicitly enabled. + - whether to add some kind of flag in an InternetNode that is equivalent to /proc/sys/net/ipv4/ip_forward , so that every InternetNode is not necessarily a router. + - whether to continue to write to the existing IPv4 API or load a static -router component into the node like Gustavo's OLSR -- whether to make a single global forwarding table instead of distributing -it among all the routers +router component into the node such as Gustavo's OLSR code does + +- what to name this. Gustavo had suggestions to pick another name for +the StaticRouteManager. One possibility I would be fine with is to call +it GlobalRouteManager (although I would still argue it adds static routes +into the nodes in any case). From b16efc8c0b574ef40605f8828474048002eda5e7 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 23 Jul 2007 20:06:00 -0700 Subject: [PATCH 081/278] a few edits on the doxygen --- README.routing | 9 ++++++++- src/routing/routing-environment.h | 11 ++++++++++- src/routing/static-route-manager-impl.cc | 11 +++++------ src/routing/static-route-manager-impl.h | 23 ++++++++++++----------- src/routing/static-route-manager.h | 8 +++----- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/README.routing b/README.routing index 2d8e0f88a..f787371be 100644 --- a/README.routing +++ b/README.routing @@ -72,7 +72,8 @@ Therefore, we think that enabling these other link types will be more straightforward now that the underlying OSPF SPF framework is in place. Presently, we can handle IPv4 point-to-point, numbered links, and we do -not do equal-cost multipath. +not do equal-cost multipath. We also do not allow for non-unit-cost +links, although it should be trivially extensible to do so. The support for this relies on the node object supporting a StaticRouter interface. This can be manually added to each node, or alternatively, @@ -124,3 +125,9 @@ router component into the node such as Gustavo's OLSR code does the StaticRouteManager. One possibility I would be fine with is to call it GlobalRouteManager (although I would still argue it adds static routes into the nodes in any case). + +- this method probably belongs in the Ipv4 (find InterfaceId corresponding +to the provided address) + uint32_t +StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) + diff --git a/src/routing/routing-environment.h b/src/routing/routing-environment.h index 51ee61f2b..b233c821a 100644 --- a/src/routing/routing-environment.h +++ b/src/routing/routing-environment.h @@ -23,8 +23,17 @@ namespace ns3 { namespace RoutingEnvironment { - + +/** + * @brief This function tests the value of the global default value + * "DoStaticRouting". This approach puts everything in one compilation + * unit, as opposed to explicitly testing the value of the underlying + * static variable. + */ bool StaticRoutingEnabled(void); +/** + * @brief Allocate a 32-bit router ID from monotonically increasing counter. + */ uint32_t AllocateRouterId(void); } // namespace RoutingEnvironment diff --git a/src/routing/static-route-manager-impl.cc b/src/routing/static-route-manager-impl.cc index 52f8d4b32..0b2a61ddb 100644 --- a/src/routing/static-route-manager-impl.cc +++ b/src/routing/static-route-manager-impl.cc @@ -505,7 +505,7 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) StaticRouterLSA::LSA_SPF_NOT_EXPLORED) { // -// If we havent yet considered the link represented by we have to create +// If we haven't yet considered the link represented by we have to create // a new SPFVertex to represent it. // w = new SPFVertex (w_lsa); @@ -710,9 +710,6 @@ StaticRouteManagerImpl::SPFNexthopCalculation ( // Router Link Record we find that describes a point-to-point link from // to . If prev_link is not NULL, we return a Static Router Link Record // representing a possible *second* link from to . -// -// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for -// any link records after pre_link and not just after the first? // StaticRouterLinkRecord* StaticRouteManagerImpl::SPFGetNextLink ( @@ -928,7 +925,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) } // -// BUGBUG FIXME: This should probably be a method on Ipv4 +// XXX This should probably be a method on Ipv4 // // Return the interface index corresponding to a given IP address // @@ -1360,12 +1357,14 @@ StaticRouteManagerImplTest::RunTests (void) srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3); NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); - // XXX next, calculate routes based on the manually created LSDB + // next, calculate routes based on the manually created LSDB StaticRouteManagerImpl* srm = new StaticRouteManagerImpl (); srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB // Note-- this will succeed without any nodes in the topology // because the NodeList is empty srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 + + // XXX here we should do some verification of the routes built // This delete clears the srm, which deletes the LSDB, which clears // all of the LSAs, which each destroys the attached LinkRecords. diff --git a/src/routing/static-route-manager-impl.h b/src/routing/static-route-manager-impl.h index ec886fccb..776904818 100644 --- a/src/routing/static-route-manager-impl.h +++ b/src/routing/static-route-manager-impl.h @@ -136,7 +136,7 @@ public: * representing routers, and comes from the Link State Advertisement of a * router aggregated to a node in the simulation. These IDs are allocated * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increasing as new routers are + * beginning at 0.0.0.0 and monotonically increase as new routers are * instantiated. * * @returns The Ipv4Address Vertex ID of the current SPFVertex object. @@ -150,8 +150,9 @@ public: * representing routers, and comes from the Link State Advertisement of a * router aggregated to a node in the simulation. These IDs are allocated * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increasing as new routers are - * instantiated. + * beginning at 0.0.0.0 and monotonically increase as new routers are + * instantiated. This method is an explicit override of the automatically + * generated value. * * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. */ @@ -520,7 +521,7 @@ private: }; /** - * @brief The Link State DataBase (LSDB) of the Static Route Manager. + * @brief The Link State DataBase (LSDB) of the StaticRouteManager. * * Each node in the simulation participating in static routing has a * StaticRouter interface. The primary job of this interface is to export @@ -536,14 +537,14 @@ class StaticRouteManagerLSDB { public: /** - * @brief Construct an empty Static Router Manager Link State Database. + * @brief Construct an empty StaticRoutingManager Link State Database. * * The database map composing the Link State Database is initialized in * this constructor. */ StaticRouteManagerLSDB (); /** - * @brief Destroy an empty Static Router Manager Link State Database. + * @brief Destroy an empty StaticRoutingManager Link State Database. * * The database map is walked and all of the Link State Advertisements stored * in the database are freed; then the database map itself is clear ()ed to @@ -599,7 +600,7 @@ private: LSDBMap_t m_database; /** * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no - * need for it and a compiler provided shallow copy would be hopelessly wrong. + * need for it and a compiler provided shallow copy would be wrong. */ StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); /** @@ -646,15 +647,15 @@ public: void DebugSPFCalculate (Ipv4Address root); private: /** - * @brief Static Route Manager Implementation copy construction is disallowed. + * @brief StaticRouteManager Implementation copy construction is disallowed. * There's no need for it and a compiler provided shallow copy would be - * hopelessly wrong. + * wrong. */ StaticRouteManagerImpl (StaticRouteManagerImpl& srmi); /** - * @brief Static Route Manager Implementation assignment operator is + * @brief StaticRouteManager Implementation assignment operator is * disallowed. There's no need for it and a compiler provided shallow copy - * would be hopelessly wrong. + * would be wrong. */ StaticRouteManagerImpl& operator= (StaticRouteManagerImpl& srmi); diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 4f1cdc8ae..11c6ec718 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -38,9 +38,7 @@ public: * the nodes in the simulation. * * All this function does is call BuildStaticRoutingDatabase () and - * InitializeRoutes (). There's no reason to export the two-step process - * since a high-level caller has no need to know how we're implementing the - * process. + * InitializeRoutes (). * * @see BuildStaticRoutingDatabase (); * @see InitializeRoutes (); @@ -60,13 +58,13 @@ private: static void InitializeRoutes (); /** * @brief Static Route Manager copy construction is disallowed. There's no - * need for it and a compiler provided shallow copy would be hopelessly wrong. + * need for it and a compiler provided shallow copy would be wrong. * */ StaticRouteManager (StaticRouteManager& srm); /** * @brief Static Router copy assignment operator is disallowed. There's no - * need for it and a compiler provided shallow copy would be hopelessly wrong. + * need for it and a compiler provided shallow copy would be wrong. */ StaticRouteManager& operator= (StaticRouteManager& srm); }; From 073e685b0d8518336ca29d23d3d8e3e054f6672b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 26 Jul 2007 14:03:41 +0200 Subject: [PATCH 082/278] new address types --- src/node/address.cc | 113 +++++++++++++++++++++++++++++ src/node/address.h | 43 +++++++++++ src/node/eui48-address.cc | 83 +++++++++++++++++++++ src/node/eui48-address.h | 25 +++++++ src/node/ipv4-address.cc | 41 ++++++++++- src/node/ipv4-address.h | 13 ++++ src/node/ipv4-transport-address.cc | 67 +++++++++++++++++ src/node/ipv4-transport-address.h | 33 +++++++++ src/node/wscript | 6 ++ 9 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 src/node/address.cc create mode 100644 src/node/address.h create mode 100644 src/node/eui48-address.cc create mode 100644 src/node/eui48-address.h create mode 100644 src/node/ipv4-transport-address.cc create mode 100644 src/node/ipv4-transport-address.h diff --git a/src/node/address.cc b/src/node/address.cc new file mode 100644 index 000000000..a09129019 --- /dev/null +++ b/src/node/address.cc @@ -0,0 +1,113 @@ +#include "ns3/assert.h" +#include "address.h" +#include +#include + +namespace ns3 { + +Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len) + : m_type (type), + m_len (len) +{ + NS_ASSERT (m_len <= MAX_SIZE); + memset (m_data, 0, m_len); + memcpy (m_data, buffer, m_len); +} +Address::Address (const Address & address) + : m_type (address.m_type), + m_len (address.m_len) +{ + NS_ASSERT (m_len <= MAX_SIZE); + memset (m_data, 0, m_len); + memcpy (m_data, address.m_data, m_len); +} +Address & +Address::operator = (const Address &address) +{ + NS_ASSERT (m_len <= MAX_SIZE); + m_type = address.m_type; + m_len = address.m_len; + NS_ASSERT (m_len <= MAX_SIZE); + memset (m_data, 0, m_len); + memcpy (m_data, address.m_data, m_len); + return *this; +} + +uint8_t +Address::GetLength (void) const +{ + NS_ASSERT (m_len <= MAX_SIZE); + return m_len; +} +void +Address::CopyTo (uint8_t *buffer) const +{ + NS_ASSERT (m_len <= MAX_SIZE); + memcpy (buffer, m_data, m_len); +} +uint8_t +Address::GetType (void) const +{ + NS_ASSERT (m_len <= MAX_SIZE); + return m_type; +} + +uint8_t +Address::Register (void) +{ + static uint8_t type = 1; + type++; + return type; +} + +bool operator == (const Address &a, const Address &b) +{ + NS_ASSERT (a.GetType () == b.GetType ()); + NS_ASSERT (a.GetLength() == b.GetLength()); + return memcmp (a.m_data, b.m_data, a.m_len) == 0; +} +bool operator != (const Address &a, const Address &b) +{ + return !(a == b); +} +bool operator < (const Address &a, const Address &b) +{ + NS_ASSERT (a.GetType () == b.GetType ()); + NS_ASSERT (a.GetLength() == b.GetLength()); + for (uint8_t i = 0; i < a.GetLength(); i++) + { + if (a.m_data[i] < b.m_data[i]) + { + return true; + } + else if (a.m_data[i] > b.m_data[i]) + { + return false; + } + } + return false; +} + +std::ostream& operator<< (std::ostream& os, const Address & address) +{ + if (address.m_len == 0) + { + os << "NULL-ADDRESS"; + return os; + } + os.setf (std::ios::hex, std::ios::basefield); + std::cout.fill('0'); + for (uint8_t i=0; i < (address.m_len-1); i++) + { + os << std::setw(2) << (uint32_t)address.m_data[i] << ":"; + } + // Final byte not suffixed by ":" + os << std::setw(2) << (uint32_t)address.m_data[address.m_len-1]; + os.setf (std::ios::dec, std::ios::basefield); + std::cout.fill(' '); + return os; +} + + + +} // namespace ns3 diff --git a/src/node/address.h b/src/node/address.h new file mode 100644 index 000000000..39551550d --- /dev/null +++ b/src/node/address.h @@ -0,0 +1,43 @@ +#ifndef ADDRESS_H +#define ADDRESS_H + +#include +#include + +namespace ns3 { + +class Address +{ +public: + Address (uint8_t type, const uint8_t *buffer, uint8_t len); + Address (const Address & address); + Address &operator = (const Address &address); + + uint8_t GetLength (void) const; + void CopyTo (uint8_t *buffer) const; + uint8_t GetType (void) const; + + static uint8_t Register (void); +private: + friend bool operator == (const Address &a, const Address &b); + friend bool operator < (const Address &a, const Address &b); + friend std::ostream& operator<< (std::ostream& os, const Address & address); + + Address (); + enum { + MAX_SIZE = 14 + }; + uint8_t m_type; + uint8_t m_len; + uint8_t m_data[MAX_SIZE]; +}; + +bool operator == (const Address &a, const Address &b); +bool operator != (const Address &a, const Address &b); +bool operator < (const Address &a, const Address &b); +std::ostream& operator<< (std::ostream& os, const Address & address); + +} // namespace ns3 + + +#endif /* ADDRESS_H */ diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc new file mode 100644 index 000000000..6f9e86879 --- /dev/null +++ b/src/node/eui48-address.cc @@ -0,0 +1,83 @@ +#include "eui48-address.h" +#include "address.h" +#include "ns3/assert.h" + +namespace ns3 { + +#define ASCII_a (0x41) +#define ASCII_z (0x5a) +#define ASCII_A (0x61) +#define ASCII_Z (0x7a) +#define ASCII_COLON (0x3a) +#define ASCII_ZERO (0x30) + +static char +AsciiToLowCase (char c) +{ + if (c >= ASCII_a && c <= ASCII_z) { + return c; + } else if (c >= ASCII_A && c <= ASCII_Z) { + return c + (ASCII_a - ASCII_A); + } else { + return c; + } +} + + +Eui48Address::Eui48Address () +{ + memset (m_address, 0, 6); +} +Eui48Address::Eui48Address (const char *str) +{ + int i = 0; + while (*str != 0 && i < 6) + { + uint8_t byte = 0; + while (*str != ASCII_COLON && *str != 0) + { + byte <<= 4; + char low = AsciiToLowCase (*str); + if (low >= ASCII_a) + { + byte |= low - ASCII_a + 10; + } + else + { + byte |= low - ASCII_ZERO; + } + str++; + } + m_address[i] = byte; + i++; + if (*str == 0) + { + break; + } + str++; + } + NS_ASSERT (i == 6); +} +Address +Eui48Address::ConvertTo (void) const +{ + return Address (GetType (), m_address, 6); +} +Eui48Address +Eui48Address::ConvertFrom (const Address &address) +{ + NS_ASSERT (address.GetType () == GetType ()); + NS_ASSERT (address.GetLength () == 6); + Eui48Address retval; + address.CopyTo (retval.m_address); + return retval; +} +uint8_t +Eui48Address::GetType (void) +{ + static uint8_t type = Address::Register (); + return type; +} + + +} // namespace ns3 diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h new file mode 100644 index 000000000..5f57971de --- /dev/null +++ b/src/node/eui48-address.h @@ -0,0 +1,25 @@ +#ifndef EUI48_ADDRESS_H +#define EUI48_ADDRESS_H + +#include + +namespace ns3 { + +class Address; + +class Eui48Address +{ +public: + Eui48Address (); + Eui48Address (const char *str); + Address ConvertTo (void) const; + static Eui48Address ConvertFrom (const Address &address); +private: + static uint8_t GetType (void); + uint8_t m_address[6]; + +}; + +} // namespace ns3 + +#endif /* EUI48_ADDRESS_H */ diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index f8ff9f7a6..70b0ff486 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -19,11 +19,11 @@ * Author: Mathieu Lacage */ #include "ns3/debug.h" +#include "ipv4-address.h" +#include "ns3/assert.h" NS_DEBUG_COMPONENT_DEFINE("Ipv4Address"); -#include "ipv4-address.h" - namespace ns3 { @@ -170,6 +170,20 @@ Ipv4Address::Serialize (uint8_t buf[4]) const buf[2] = (m_address >> 8) & 0xff; buf[3] = (m_address >> 0) & 0xff; } +Ipv4Address +Ipv4Address::Deserialize (const uint8_t buf[4]) +{ + Ipv4Address ipv4; + ipv4.m_address = 0; + ipv4.m_address |= buf[0]; + ipv4.m_address <<= 8; + ipv4.m_address |= buf[1]; + ipv4.m_address <<= 8; + ipv4.m_address |= buf[2]; + ipv4.m_address <<= 8; + ipv4.m_address |= buf[3]; + return ipv4; +} void Ipv4Address::Print (std::ostream &os) const @@ -180,7 +194,30 @@ Ipv4Address::Print (std::ostream &os) const << ((m_address >> 0) & 0xff); } +Address +Ipv4Address::ConvertTo (void) const +{ + uint8_t buf[4]; + Serialize (buf); + return Address (GetType (), buf, 4); +} +Ipv4Address +Ipv4Address::ConvertFrom (const Address &address) +{ + NS_ASSERT (address.GetType () == GetType ()); + NS_ASSERT (address.GetLength () == 4); + uint8_t buf[4]; + address.CopyTo (buf); + return Deserialize (buf); +} + +uint8_t +Ipv4Address::GetType (void) +{ + static uint8_t type = Address::Register (); + return type; +} Ipv4Address Ipv4Address::GetZero (void) diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index dc834052a..2012d2f78 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -24,6 +24,7 @@ #include #include +#include "address.h" namespace ns3 { @@ -68,10 +69,18 @@ public: void SetHostOrder (uint32_t ip); /** * Serialize this address to a 4-byte buffer + * * \param buf output buffer to which this address gets overwritten with this * Ipv4Address */ void Serialize (uint8_t buf[4]) const; + /** + * \param buf buffer to read address from + * \returns an Ipv4Address + * + * The input address is expected to be in network byte order format. + */ + static Ipv4Address Deserialize (const uint8_t buf[4]); /** * \brief Print this address to the given output stream * @@ -83,11 +92,15 @@ public: bool IsBroadcast (void); bool IsMulticast (void); + Address ConvertTo (void) const; + static Ipv4Address ConvertFrom (const Address &address); + static Ipv4Address GetZero (void); static Ipv4Address GetAny (void); static Ipv4Address GetBroadcast (void); static Ipv4Address GetLoopback (void); private: + static uint8_t GetType (void); uint32_t m_address; }; diff --git a/src/node/ipv4-transport-address.cc b/src/node/ipv4-transport-address.cc new file mode 100644 index 000000000..b088a1017 --- /dev/null +++ b/src/node/ipv4-transport-address.cc @@ -0,0 +1,67 @@ +#include "ipv4-transport-address.h" +#include "ns3/assert.h" + +namespace ns3 { + +Ipv4TransportAddress::Ipv4TransportAddress (Ipv4Address ipv4, uint16_t port) + : m_ipv4 (ipv4), + m_port (port) +{} +Ipv4TransportAddress::Ipv4TransportAddress (Ipv4Address ipv4) + : m_ipv4 (ipv4), + m_port (0) +{} +Ipv4TransportAddress::Ipv4TransportAddress (uint16_t port) + : m_ipv4 (Ipv4Address::GetAny ()), + m_port (port) +{} +uint16_t +Ipv4TransportAddress::GetPort (void) const +{ + return m_port; +} +Ipv4Address +Ipv4TransportAddress::GetIpv4 (void) const +{ + return m_ipv4; +} + +void +Ipv4TransportAddress::SetPort (uint16_t port) +{ + m_port = port; +} +void +Ipv4TransportAddress::SetIpv4 (Ipv4Address address) +{ + m_ipv4 = address; +} + +Address +Ipv4TransportAddress::ConvertTo (void) const +{ + uint8_t buf[6]; + m_ipv4.Serialize (buf); + buf[4] = m_port & 0xff; + buf[5] = (m_port >> 8) & 0xff; + return Address (GetType (), buf, 6); +} +Ipv4TransportAddress +Ipv4TransportAddress::ConvertFrom (const Address &address) +{ + NS_ASSERT (address.GetType () == GetType ()); + NS_ASSERT (address.GetLength () == 6); + uint8_t buf[6]; + address.CopyTo (buf); + Ipv4Address ipv4 = Ipv4Address::Deserialize (buf); + uint16_t port = buf[0] | (buf[1] << 8); + return Ipv4TransportAddress (ipv4, port); +} +uint8_t +Ipv4TransportAddress::GetType (void) +{ + static uint8_t type = Address::Register (); + return type; +} + +} // namespace ns3 diff --git a/src/node/ipv4-transport-address.h b/src/node/ipv4-transport-address.h new file mode 100644 index 000000000..e73ca8d3d --- /dev/null +++ b/src/node/ipv4-transport-address.h @@ -0,0 +1,33 @@ +#ifndef IPV4_TRANSPORT_ADDRESS_H +#define IPV4_TRANSPORT_ADDRESS_H + +#include "address.h" +#include "ipv4-address.h" +#include + +namespace ns3 { + +class Ipv4TransportAddress +{ +public: + Ipv4TransportAddress (Ipv4Address ipv4, uint16_t port); + Ipv4TransportAddress (Ipv4Address ipv4); + Ipv4TransportAddress (uint16_t post); + uint16_t GetPort (void) const; + Ipv4Address GetIpv4 (void) const; + + void SetPort (uint16_t post); + void SetIpv4 (Ipv4Address address); + + Address ConvertTo (void) const; + static Ipv4TransportAddress ConvertFrom (const Address &address); +private: + static uint8_t GetType (void); + Ipv4Address m_ipv4; + uint16_t m_port; +}; + +} // namespace ns3 + + +#endif /* IPV4_TRANSPORT_ADDRESS_H */ diff --git a/src/node/wscript b/src/node/wscript index 0a5c64aa9..e11cd8eac 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -6,6 +6,9 @@ def build(bld): node.target = node.name node.uselib_local = ['ns3-core', 'ns3-common', 'ns3-simulator'] node.source = [ + 'address.cc', + 'eui48-address.cc', + 'ipv4-transport-address.cc', 'node.cc', 'ipv4-address.cc', 'net-device.cc', @@ -26,6 +29,9 @@ def build(bld): headers = bld.create_obj('ns3header') headers.source = [ + 'address.h', + 'eui48-address.h', + 'ipv4-transport-address.h', 'node.h', 'ipv4-address.h', 'net-device.h', From 8a5f927d8dfbb69edd666800b8c297a0f7bce5dd Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 26 Jul 2007 14:47:05 +0200 Subject: [PATCH 083/278] improve type checking --- src/node/address.cc | 28 ++++++++++++++++++++++------ src/node/address.h | 13 ++++++++----- src/node/eui48-address.cc | 3 +-- src/node/ipv4-address.cc | 3 +-- src/node/ipv4-transport-address.cc | 3 +-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/node/address.cc b/src/node/address.cc index a09129019..408a152e6 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -5,6 +5,13 @@ namespace ns3 { +Address::Address () + : m_type (0), + m_len (0) +{ + memset (m_data, 0, m_len); +} + Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len) : m_type (type), m_len (len) @@ -45,11 +52,16 @@ Address::CopyTo (uint8_t *buffer) const NS_ASSERT (m_len <= MAX_SIZE); memcpy (buffer, m_data, m_len); } -uint8_t -Address::GetType (void) const +void +Address::CopyFrom (uint8_t *buffer, uint8_t len) { - NS_ASSERT (m_len <= MAX_SIZE); - return m_type; + NS_ASSERT (len == m_len); + memcpy (m_data, buffer, len); +} +bool +Address::CheckCompatible (uint8_t type, uint8_t len) const +{ + return m_len == len && (m_type == type || m_type == 0); } uint8_t @@ -62,7 +74,9 @@ Address::Register (void) bool operator == (const Address &a, const Address &b) { - NS_ASSERT (a.GetType () == b.GetType ()); + NS_ASSERT (a.m_type == b.m_type || + a.m_type == 0 || + b.m_type == 0); NS_ASSERT (a.GetLength() == b.GetLength()); return memcmp (a.m_data, b.m_data, a.m_len) == 0; } @@ -72,7 +86,9 @@ bool operator != (const Address &a, const Address &b) } bool operator < (const Address &a, const Address &b) { - NS_ASSERT (a.GetType () == b.GetType ()); + NS_ASSERT (a.m_type == b.m_type || + a.m_type == 0 || + b.m_type == 0); NS_ASSERT (a.GetLength() == b.GetLength()); for (uint8_t i = 0; i < a.GetLength(); i++) { diff --git a/src/node/address.h b/src/node/address.h index 39551550d..417bdce0a 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -9,13 +9,20 @@ namespace ns3 { class Address { public: + enum { + MAX_SIZE = 14 + }; + + Address (); Address (uint8_t type, const uint8_t *buffer, uint8_t len); Address (const Address & address); Address &operator = (const Address &address); uint8_t GetLength (void) const; void CopyTo (uint8_t *buffer) const; - uint8_t GetType (void) const; + void CopyFrom (uint8_t *buffer, uint8_t len); + bool CheckCompatible (uint8_t type, uint8_t len) const; + static uint8_t Register (void); private: @@ -23,10 +30,6 @@ private: friend bool operator < (const Address &a, const Address &b); friend std::ostream& operator<< (std::ostream& os, const Address & address); - Address (); - enum { - MAX_SIZE = 14 - }; uint8_t m_type; uint8_t m_len; uint8_t m_data[MAX_SIZE]; diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 6f9e86879..622ec3142 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -66,8 +66,7 @@ Eui48Address::ConvertTo (void) const Eui48Address Eui48Address::ConvertFrom (const Address &address) { - NS_ASSERT (address.GetType () == GetType ()); - NS_ASSERT (address.GetLength () == 6); + NS_ASSERT (address.CheckCompatible (GetType (), 6)); Eui48Address retval; address.CopyTo (retval.m_address); return retval; diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 70b0ff486..5c923f06f 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -205,8 +205,7 @@ Ipv4Address::ConvertTo (void) const Ipv4Address Ipv4Address::ConvertFrom (const Address &address) { - NS_ASSERT (address.GetType () == GetType ()); - NS_ASSERT (address.GetLength () == 4); + NS_ASSERT (address.CheckCompatible (GetType (), 4)); uint8_t buf[4]; address.CopyTo (buf); return Deserialize (buf); diff --git a/src/node/ipv4-transport-address.cc b/src/node/ipv4-transport-address.cc index b088a1017..9330737c8 100644 --- a/src/node/ipv4-transport-address.cc +++ b/src/node/ipv4-transport-address.cc @@ -49,8 +49,7 @@ Ipv4TransportAddress::ConvertTo (void) const Ipv4TransportAddress Ipv4TransportAddress::ConvertFrom (const Address &address) { - NS_ASSERT (address.GetType () == GetType ()); - NS_ASSERT (address.GetLength () == 6); + NS_ASSERT (address.CheckCompatible (GetType (), 6)); uint8_t buf[6]; address.CopyTo (buf); Ipv4Address ipv4 = Ipv4Address::Deserialize (buf); From db6a90d956737d0dc4096d271084a0ffdf0c5876 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 26 Jul 2007 17:36:53 +0200 Subject: [PATCH 084/278] replace MacAddress by Address --- examples/simple-p2p.cc | 1 - src/devices/p2p/p2p-net-device.cc | 11 +- src/devices/p2p/p2p-net-device.h | 6 +- src/internet-node/arp-cache.cc | 4 +- src/internet-node/arp-cache.h | 8 +- src/internet-node/arp-header.cc | 12 +- src/internet-node/arp-header.h | 18 +- src/internet-node/arp-ipv4-interface.cc | 3 +- src/internet-node/arp-l3-protocol.cc | 10 +- src/internet-node/arp-l3-protocol.h | 6 +- src/internet-node/arp-private.cc | 2 +- src/internet-node/arp-private.h | 4 +- src/internet-node/header-utils.cc | 12 +- src/internet-node/header-utils.h | 6 +- src/node/eui48-address.cc | 14 ++ src/node/eui48-address.h | 1 + src/node/mac-address.cc | 210 ------------------------ src/node/mac-address.h | 128 --------------- src/node/net-device.cc | 10 +- src/node/net-device.h | 22 +-- src/node/wscript | 2 - 21 files changed, 83 insertions(+), 407 deletions(-) delete mode 100644 src/node/mac-address.cc delete mode 100644 src/node/mac-address.h diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index 9ad235b5e..ac98440c8 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -56,7 +56,6 @@ #include "ns3/internet-node.h" #include "ns3/p2p-channel.h" #include "ns3/p2p-net-device.h" -#include "ns3/mac-address.h" #include "ns3/ipv4-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc index 13d352889..3e0596d48 100644 --- a/src/devices/p2p/p2p-net-device.cc +++ b/src/devices/p2p/p2p-net-device.cc @@ -26,6 +26,7 @@ #include "ns3/queue.h" #include "ns3/simulator.h" #include "ns3/composite-trace-resolver.h" +#include "ns3/eui48-address.h" #include "p2p-net-device.h" #include "p2p-channel.h" @@ -38,10 +39,10 @@ DataRateDefaultValue PointToPointNetDevice::g_defaultRate( "The default data rate for point to point links", DataRate ("10Mb/s")); - PointToPointNetDevice::PointToPointNetDevice (Ptr node, - const DataRate& rate) +PointToPointNetDevice::PointToPointNetDevice (Ptr node, + const DataRate& rate) : - NetDevice(node, MacAddress (6)), + NetDevice(node, Eui48Address::Allocate ().ConvertTo ()), m_txMachineState (READY), m_bps (rate), m_tInterframeGap (Seconds(0)), @@ -54,7 +55,7 @@ DataRateDefaultValue PointToPointNetDevice::g_defaultRate( // BUGBUG FIXME // // You _must_ support broadcast to get any sort of packet from the ARP layer. - EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff")); + EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff").ConvertTo ()); EnableMulticast(); EnablePointToPoint(); } @@ -82,7 +83,7 @@ void PointToPointNetDevice::SetInterframeGap(const Time& t) m_tInterframeGap = t; } -bool PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) +bool PointToPointNetDevice::SendTo (Packet& p, const Address& dest) { NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h index a4bc3be00..474a6383c 100644 --- a/src/devices/p2p/p2p-net-device.h +++ b/src/devices/p2p/p2p-net-device.h @@ -22,7 +22,7 @@ #define POINT_TO_POINT_NET_DEVICE_H #include -#include "ns3/mac-address.h" +#include "ns3/address.h" #include "ns3/node.h" #include "ns3/net-device.h" #include "ns3/callback.h" @@ -201,10 +201,10 @@ private: * * @see NetDevice * @param p a reference to the packet to send - * @param dest a reference to the MacAddress of the destination device + * @param dest a reference to the Address of the destination device * @returns true if success, false on failure */ - virtual bool SendTo (Packet& p, const MacAddress& dest); + virtual bool SendTo (Packet& p, const Address& dest); /** * Start Sending a Packet Down the Wire. * diff --git a/src/internet-node/arp-cache.cc b/src/internet-node/arp-cache.cc index e9f48561d..4b166c99b 100644 --- a/src/internet-node/arp-cache.cc +++ b/src/internet-node/arp-cache.cc @@ -146,7 +146,7 @@ ArpCache::Entry::MarkDead (void) UpdateSeen (); } Packet -ArpCache::Entry::MarkAlive (MacAddress macAddress) +ArpCache::Entry::MarkAlive (Address macAddress) { NS_ASSERT (m_state == WAIT_REPLY); //NS_ASSERT (m_waiting != 0); @@ -180,7 +180,7 @@ ArpCache::Entry::MarkWaitReply (Packet waiting) UpdateSeen (); } -MacAddress +Address ArpCache::Entry::GetMacAddress (void) { NS_ASSERT (m_state == ALIVE); diff --git a/src/internet-node/arp-cache.h b/src/internet-node/arp-cache.h index 436d44eba..2cd88c85f 100644 --- a/src/internet-node/arp-cache.h +++ b/src/internet-node/arp-cache.h @@ -26,7 +26,7 @@ #include "ns3/nstime.h" #include "ns3/net-device.h" #include "ns3/ipv4-address.h" -#include "ns3/mac-address.h" +#include "ns3/address.h" #include "ns3/ptr.h" #include "sgi-hashmap.h" @@ -101,7 +101,7 @@ public: * \param macAddress * \return */ - Packet MarkAlive (MacAddress macAddress); + Packet MarkAlive (Address macAddress); /** * \param waiting */ @@ -127,7 +127,7 @@ public: /** * \return The MacAddress of this entry */ - MacAddress GetMacAddress (void); + Address GetMacAddress (void); /** * \return True if this entry has timedout; false otherwise. */ @@ -143,7 +143,7 @@ public: ArpCache *m_arp; ArpCacheEntryState_e m_state; Time m_lastSeen; - MacAddress m_macAddress; + Address m_macAddress; Packet m_waiting; }; diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index e340404f4..dc8cd3f7a 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -29,9 +29,9 @@ ArpHeader::~ArpHeader () {} void -ArpHeader::SetRequest (MacAddress sourceHardwareAddress, +ArpHeader::SetRequest (Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, - MacAddress destinationHardwareAddress, + Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress) { m_type = ARP_TYPE_REQUEST; @@ -41,9 +41,9 @@ ArpHeader::SetRequest (MacAddress sourceHardwareAddress, m_ipv4Dest = destinationProtocolAddress; } void -ArpHeader::SetReply (MacAddress sourceHardwareAddress, +ArpHeader::SetReply (Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, - MacAddress destinationHardwareAddress, + Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress) { m_type = ARP_TYPE_REPLY; @@ -62,12 +62,12 @@ ArpHeader::IsReply (void) const { return (m_type == ARP_TYPE_REPLY)?true:false; } -MacAddress +Address ArpHeader::GetSourceHardwareAddress (void) { return m_macSource; } -MacAddress +Address ArpHeader::GetDestinationHardwareAddress (void) { return m_macDest; diff --git a/src/internet-node/arp-header.h b/src/internet-node/arp-header.h index 9f85579f5..5affcf84f 100644 --- a/src/internet-node/arp-header.h +++ b/src/internet-node/arp-header.h @@ -23,7 +23,7 @@ #define ARP_HEADER_H #include "ns3/header.h" -#include "ns3/mac-address.h" +#include "ns3/address.h" #include "ns3/ipv4-address.h" namespace ns3 { @@ -34,18 +34,18 @@ class ArpHeader : public Header { public: virtual ~ArpHeader (); - void SetRequest (MacAddress sourceHardwareAddress, + void SetRequest (Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, - MacAddress destinationHardwareAddress, + Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress); - void SetReply (MacAddress sourceHardwareAddress, + void SetReply (Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, - MacAddress destinationHardwareAddress, + Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress); bool IsRequest (void) const; bool IsReply (void) const; - MacAddress GetSourceHardwareAddress (void); - MacAddress GetDestinationHardwareAddress (void); + Address GetSourceHardwareAddress (void); + Address GetDestinationHardwareAddress (void); Ipv4Address GetSourceIpv4Address (void); Ipv4Address GetDestinationIpv4Address (void); @@ -74,8 +74,8 @@ private: ARP_TYPE_REPLY = 2 }; uint16_t m_type; - MacAddress m_macSource; - MacAddress m_macDest; + Address m_macSource; + Address m_macDest; Ipv4Address m_ipv4Source; Ipv4Address m_ipv4Dest; }; diff --git a/src/internet-node/arp-ipv4-interface.cc b/src/internet-node/arp-ipv4-interface.cc index 42d6af238..9319929c2 100644 --- a/src/internet-node/arp-ipv4-interface.cc +++ b/src/internet-node/arp-ipv4-interface.cc @@ -24,6 +24,7 @@ #include "ns3/composite-trace-resolver.h" #include "ns3/node.h" #include "ns3/net-device.h" +#include "ns3/address.h" #include "arp-ipv4-interface.h" #include "arp-private.h" @@ -59,7 +60,7 @@ ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest) if (GetDevice ()->NeedsArp ()) { Ptr arp = m_node->QueryInterface (ArpPrivate::iid); - MacAddress hardwareDestination; + Address hardwareDestination; bool found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination); if (found) { diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index f04a6aa25..583b4e574 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -97,7 +97,7 @@ ArpL3Protocol::Receive(Packet& packet, Ptr device) } else if (arp.IsReply () && arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress ()) && - arp.GetDestinationHardwareAddress ().IsEqual (device->GetAddress ())) + arp.GetDestinationHardwareAddress () == device->GetAddress ()) { Ipv4Address from = arp.GetSourceIpv4Address (); ArpCache::Entry *entry = cache->Lookup (from); @@ -108,7 +108,7 @@ ArpL3Protocol::Receive(Packet& packet, Ptr device) NS_DEBUG ("node="<GetId ()<<", got reply from " << arp.GetSourceIpv4Address () << " for waiting entry -- flush"); - MacAddress from_mac = arp.GetSourceHardwareAddress (); + Address from_mac = arp.GetSourceHardwareAddress (); Packet waiting = entry->MarkAlive (from_mac); cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ()); } @@ -131,8 +131,8 @@ ArpL3Protocol::Receive(Packet& packet, Ptr device) } bool ArpL3Protocol::Lookup (Packet &packet, Ipv4Address destination, - Ptr device, - MacAddress *hardwareDestination) + Ptr device, + Address *hardwareDestination) { ArpCache *cache = FindCache (device); ArpCache::Entry *entry = cache->Lookup (destination); @@ -213,7 +213,7 @@ ArpL3Protocol::SendArpRequest (ArpCache const *cache, Ipv4Address to) } void -ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac) +ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac) { ArpHeader arp; arp.SetReply (cache->GetDevice ()->GetAddress (), diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index d27d2dba2..082bbebb5 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -23,7 +23,7 @@ #include #include "ns3/ipv4-address.h" -#include "ns3/mac-address.h" +#include "ns3/address.h" #include "ns3/ptr.h" #include "l3-protocol.h" @@ -64,14 +64,14 @@ public: */ bool Lookup (Packet &p, Ipv4Address destination, Ptr device, - MacAddress *hardwareDestination); + Address *hardwareDestination); protected: virtual void DoDispose (void); private: typedef std::list CacheList; ArpCache *FindCache (Ptr device); void SendArpRequest (ArpCache const *cache, Ipv4Address to); - void SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac); + void SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac); CacheList m_cacheList; Ptr m_node; }; diff --git a/src/internet-node/arp-private.cc b/src/internet-node/arp-private.cc index 10a86b3e3..4f60dac99 100644 --- a/src/internet-node/arp-private.cc +++ b/src/internet-node/arp-private.cc @@ -40,7 +40,7 @@ ArpPrivate::~ArpPrivate () bool ArpPrivate::Lookup (Packet &p, Ipv4Address destination, Ptr device, - MacAddress *hardwareDestination) + Address *hardwareDestination) { return m_arp->Lookup (p, destination, device, hardwareDestination); } diff --git a/src/internet-node/arp-private.h b/src/internet-node/arp-private.h index 6e238ade0..af0b8b7a3 100644 --- a/src/internet-node/arp-private.h +++ b/src/internet-node/arp-private.h @@ -27,7 +27,7 @@ namespace ns3 { class NetDevice; -class MacAddress; +class Address; class Packet; class ArpL3Protocol; @@ -39,7 +39,7 @@ public: virtual ~ArpPrivate (); bool Lookup (Packet &p, Ipv4Address destination, Ptr device, - MacAddress *hardwareDestination); + Address *hardwareDestination); protected: virtual void DoDispose (void); private: diff --git a/src/internet-node/header-utils.cc b/src/internet-node/header-utils.cc index b3da88cfa..64bb29285 100644 --- a/src/internet-node/header-utils.cc +++ b/src/internet-node/header-utils.cc @@ -26,10 +26,10 @@ void WriteTo (Buffer::Iterator &i, Ipv4Address ad) { i.WriteHtonU32 (ad.GetHostOrder ()); } -void WriteTo (Buffer::Iterator &i, MacAddress ad) +void WriteTo (Buffer::Iterator &i, Address ad) { - uint8_t mac[MacAddress::MAX_LEN]; - ad.Peek (mac); + uint8_t mac[Address::MAX_SIZE]; + ad.CopyTo (mac); i.Write (mac, ad.GetLength ()); } @@ -37,11 +37,11 @@ void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad) { ad.SetHostOrder (i.ReadNtohU32 ()); } -void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len) +void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len) { - uint8_t mac[MacAddress::MAX_LEN]; + uint8_t mac[Address::MAX_SIZE]; i.Read (mac, len); - ad.Set (mac, len); + ad.CopyFrom (mac, len); } diff --git a/src/internet-node/header-utils.h b/src/internet-node/header-utils.h index e65e7533c..88d3dfe10 100644 --- a/src/internet-node/header-utils.h +++ b/src/internet-node/header-utils.h @@ -23,15 +23,15 @@ #include "ns3/buffer.h" #include "ns3/ipv4-address.h" -#include "ns3/mac-address.h" +#include "ns3/address.h" namespace ns3 { void WriteTo (Buffer::Iterator &i, Ipv4Address ad); -void WriteTo (Buffer::Iterator &i, MacAddress ad); +void WriteTo (Buffer::Iterator &i, Address ad); void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad); -void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len); +void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len); }; diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 622ec3142..a3ed8fd4e 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -71,6 +71,20 @@ Eui48Address::ConvertFrom (const Address &address) address.CopyTo (retval.m_address); return retval; } +Eui48Address +Eui48Address::Allocate (void) +{ + static uint64_t id = 0; + id++; + Eui48Address address; + address.m_address[0] = (id >> 48) & 0xff; + address.m_address[1] = (id >> 32) & 0xff; + address.m_address[2] = (id >> 24) & 0xff; + address.m_address[3] = (id >> 16) & 0xff; + address.m_address[4] = (id >> 8) & 0xff; + address.m_address[5] = (id >> 0) & 0xff; + return address; +} uint8_t Eui48Address::GetType (void) { diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h index 5f57971de..b051b4c31 100644 --- a/src/node/eui48-address.h +++ b/src/node/eui48-address.h @@ -14,6 +14,7 @@ public: Eui48Address (const char *str); Address ConvertTo (void) const; static Eui48Address ConvertFrom (const Address &address); + static Eui48Address Allocate (void); private: static uint8_t GetType (void); uint8_t m_address[6]; diff --git a/src/node/mac-address.cc b/src/node/mac-address.cc deleted file mode 100644 index 9dcf9bdd6..000000000 --- a/src/node/mac-address.cc +++ /dev/null @@ -1,210 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2005 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ - -#include -#include -#include "ns3/assert.h" -#include "mac-address.h" - -#define ASCII_a (0x41) -#define ASCII_z (0x5a) -#define ASCII_A (0x61) -#define ASCII_Z (0x7a) -#define ASCII_COLON (0x3a) -#define ASCII_ZERO (0x30) - -namespace ns3 { - -// Static variables -uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN]; - -static char -AsciiToLowCase (char c) -{ - if (c >= ASCII_a && c <= ASCII_z) { - return c; - } else if (c >= ASCII_A && c <= ASCII_Z) { - return c + (ASCII_a - ASCII_A); - } else { - return c; - } -} - - -MacAddress::MacAddress () : m_len(0) -{ - for (int i=0; i < MacAddress::MAX_LEN; i++) - { - m_address[i] = 0; - } -} - -MacAddress::MacAddress(uint8_t len) : m_len(len) -{ - NS_ASSERT (len <= MacAddress::MAX_LEN); - AdvanceAddress(); - memcpy(m_address, g_nextAddress, len); -} - -MacAddress::MacAddress (uint8_t const *address, uint8_t len) -{ - NS_ASSERT (len <= MacAddress::MAX_LEN); - for (int i=0; i < len; i++) - { - m_address[i] = address[i]; - } - for (int i=len; i < MacAddress::MAX_LEN; i++) - { - m_address[i] = 0; - } - m_len = len; -} - -MacAddress::MacAddress (char const *str) -{ - int i = 0; - while (*str != 0 && i < MacAddress::MAX_LEN) { - uint8_t byte = 0; - while (*str != ASCII_COLON && *str != 0) { - byte <<= 4; - char low = AsciiToLowCase (*str); - if (low >= ASCII_a) { - byte |= low - ASCII_a + 10; - } else { - byte |= low - ASCII_ZERO; - } - str++; - } - m_address[i] = byte; - i++; - if (*str == 0) { - break; - } - str++; - } - m_len = i; -} - -MacAddress::~MacAddress () -{} - -bool -MacAddress::IsEqual (MacAddress other) const -{ - if (memcmp(other.m_address, m_address, m_len)) - { - return false; - } - else - { - return true; - } -} - -void -MacAddress::Print (std::ostream &os) const -{ - int i; - if (m_len == 0) - { - os << "NULL-ADDRESS"; - return; - } - os.setf (std::ios::hex, std::ios::basefield); - std::cout.fill('0'); - for (i=0; i< (m_len-1); i++) - { - os << std::setw(2) << (uint32_t)m_address[i] << ":"; - } - // Final byte not suffixed by ":" - os << std::setw(2) << (uint32_t)m_address[i]; - os.setf (std::ios::dec, std::ios::basefield); - std::cout.fill(' '); -} - -uint8_t -MacAddress::GetLength () const -{ - return m_len; -} - -void -MacAddress::Peek (uint8_t ad[MacAddress::MAX_LEN]) const -{ - memcpy (ad, m_address, MacAddress::MAX_LEN); -} -void -MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len) -{ - memcpy (m_address, ad, MacAddress::MAX_LEN); - m_len = len; -} - -// Static methods -void MacAddress::AdvanceAddress() - { - // Advance to next address, little end first - for(size_t i = 0; i < MAX_LEN; ++i) - { - if (++g_nextAddress[i] != 0) break; - } - } - -// Non-member operators -bool operator == (MacAddress const&a, MacAddress const&b) -{ - return a.IsEqual (b); -} - -bool operator != (MacAddress const&a, MacAddress const&b) -{ - return !a.IsEqual (b); -} - -bool operator < (MacAddress const&a, MacAddress const&b) -{ - uint8_t a_p[MacAddress::MAX_LEN]; - uint8_t b_p[MacAddress::MAX_LEN]; - a.Peek (a_p); - b.Peek (b_p); - NS_ASSERT (a.GetLength() == b.GetLength()); - for (uint8_t i = 0; i < a.GetLength(); i++) - { - if (a_p[i] < b_p[i]) - { - return true; - } - else if (a_p[i] > b_p[i]) - { - return false; - } - } - return false; -} - -std::ostream& operator<< (std::ostream& os, MacAddress const& address) -{ - address.Print (os); - return os; -} - - -}; // namespace ns3 diff --git a/src/node/mac-address.h b/src/node/mac-address.h deleted file mode 100644 index 76c5a6ae0..000000000 --- a/src/node/mac-address.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2005 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ - -#ifndef MAC_ADDRESS_H -#define MAC_ADDRESS_H - -#include -#include - -namespace ns3 { - -/** - * \brief base class for Network Device addresses - * - * This class is a base class for different types of Network - * Device addresses. It generically stores an address of - * MAX_ADDR_LEN bytes, and provides methods to compare, print, and set - * the address. - */ -class MacAddress { -public: - enum { - MAX_LEN = 32 - }; - /** - * \brief Construct a null MacAddress - * - * This MacAddress has length of zero, and is internally all zeros - */ - MacAddress (void); - /** - * \brief Construct a MacAddress using the next available - * address. - * \see MacAddres::Next - * \param len length, in bytes, of the desired address - */ - MacAddress(uint8_t len); - /** - * \brief Construct a MacAddress from a byte-array - * - * low byte should be first. - * \param address a byte array indicating the address - * \param len length, in bytes, of the address points to - */ - MacAddress (uint8_t const *address, uint8_t len); - /** - * \brief Construct a MacAddress from a C-string - * - * The string should look like this: - * hh:xx:xx:xx:xx:ll - * where hh is the high byte and ll is - * the low byte. - * \param address the C-string representation of the address - */ - MacAddress (char const *address); - ~MacAddress (); - - /** - * \brief Comparison operation between MacAddresses - * \param other The address against which to compare this one - * \return True if they are equal, false otherwise. - */ - bool IsEqual (MacAddress other) const; - /** - * \brief Print this MacAddress to a stream - * - * The format is colon seperated groups of two hexadecimal digits - * \param os The output stream desired - */ - void Print (std::ostream &os) const; - - /** - * \return The length in bytes of this MacAddress - */ - uint8_t GetLength() const; - /** - * \brief Copy routine to peek the contents of the MacAddress - * - * \param ad Output parameter which holds a copy of this MacAddress - */ - void Peek (uint8_t ad[MAX_LEN]) const; - /** - * \brief Sets this MacAddress to a specific value - * \param ad byte buffer to set the MacAddress to - * \param len the length of the buffer - */ - void Set (uint8_t const ad[MAX_LEN], uint8_t len); - - // Static methods/members - /** - * - * Advance the global to the next available mac address. - */ - static void AdvanceAddress(); - static uint8_t g_nextAddress[MAX_LEN]; - -private: - uint8_t m_address[MAX_LEN]; - uint8_t m_len; -}; - -bool operator == (MacAddress const&a, MacAddress const&b); -bool operator != (MacAddress const&a, MacAddress const&b); -bool operator < (MacAddress const&a, MacAddress const&b); - -std::ostream& operator<< (std::ostream& os, MacAddress const& address); - -}; // namespace ns3 - -#endif /* MAC_ADDRESS_H */ diff --git a/src/node/net-device.cc b/src/node/net-device.cc index 5774abeac..1a9163aad 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -32,7 +32,7 @@ namespace ns3 { const InterfaceId NetDevice::iid = MakeInterfaceId ("NetDevice", Object::iid); -NetDevice::NetDevice(Ptr node, const MacAddress& addr) : +NetDevice::NetDevice(Ptr node, const Address& addr) : m_node (node), m_name(""), m_ifIndex (0), @@ -50,7 +50,7 @@ NetDevice::NetDevice(Ptr node, const MacAddress& addr) : NetDevice::~NetDevice () {} -MacAddress +Address NetDevice::GetAddress (void) const { return m_address; @@ -110,7 +110,7 @@ NetDevice::IsBroadcast (void) const { return m_isBroadcast; } -MacAddress const & +Address const & NetDevice::GetBroadcast (void) const { NS_ASSERT (m_isBroadcast); @@ -118,7 +118,7 @@ NetDevice::GetBroadcast (void) const } void -NetDevice::EnableBroadcast (MacAddress broadcast) +NetDevice::EnableBroadcast (Address broadcast) { m_isBroadcast = true; m_broadcast = broadcast; @@ -168,7 +168,7 @@ NetDevice::DisablePointToPoint (void) // Receive packet from above bool -NetDevice::Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber) +NetDevice::Send(Packet& p, const Address& dest, uint16_t protocolNumber) { if (m_isUp) { diff --git a/src/node/net-device.h b/src/node/net-device.h index 522b1ed41..9dace11e5 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -27,7 +27,7 @@ #include "ns3/packet.h" #include "ns3/object.h" #include "ns3/ptr.h" -#include "mac-address.h" +#include "address.h" namespace ns3 { @@ -78,9 +78,9 @@ public: Ptr GetChannel (void) const; /** - * \return the current MacAddress of this interface. + * \return the current Address of this interface. */ - MacAddress GetAddress (void) const; + Address GetAddress (void) const; /** * \param mtu MTU value, in bytes, to set for the device * \return whether the MTU value was within legal bounds @@ -136,7 +136,7 @@ public: * Calling this method is invalid if IsBroadcast returns * not true. */ - MacAddress const &GetBroadcast (void) const; + Address const &GetBroadcast (void) const; /** * \return value of m_isMulticast flag */ @@ -153,11 +153,11 @@ public: * is received. * * Called from higher layer to send packet into Network Device - * to the specified destination MacAddress + * to the specified destination Address * * \return whether the Send operation succeeded */ - bool Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber); + bool Send(Packet& p, const Address& dest, uint16_t protocolNumber); /** * \returns the node base class which contains this network * interface. @@ -187,12 +187,12 @@ public: * \param node base class node pointer of device's node * \param addr MAC address of this device. */ - NetDevice(Ptr node, const MacAddress& addr); + NetDevice(Ptr node, const Address& addr); /** * Enable broadcast support. This method should be * called by subclasses from their constructor */ - void EnableBroadcast (MacAddress broadcast); + void EnableBroadcast (Address broadcast); /** * Set m_isBroadcast flag to false */ @@ -255,7 +255,7 @@ public: * method. When the link is Up, this method is invoked to ask * subclasses to forward packets. Subclasses MUST override this method. */ - virtual bool SendTo (Packet& p, const MacAddress& dest) = 0; + virtual bool SendTo (Packet& p, const Address& dest) = 0; /** * \returns true if this NetDevice needs the higher-layers * to perform ARP over it, false otherwise. @@ -282,8 +282,8 @@ public: Ptr m_node; std::string m_name; uint16_t m_ifIndex; - MacAddress m_address; - MacAddress m_broadcast; + Address m_address; + Address m_broadcast; uint16_t m_mtu; bool m_isUp; bool m_isBroadcast; diff --git a/src/node/wscript b/src/node/wscript index e11cd8eac..738402fd3 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -12,7 +12,6 @@ def build(bld): 'node.cc', 'ipv4-address.cc', 'net-device.cc', - 'mac-address.cc', 'llc-snap-header.cc', 'ipv4-route.cc', 'queue.cc', @@ -35,7 +34,6 @@ def build(bld): 'node.h', 'ipv4-address.h', 'net-device.h', - 'mac-address.h', 'ipv4-route.h', 'queue.h', 'drop-tail-queue.h', From c716994cabb144cbcc6627f58b11a75c57bf77c5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 08:23:20 +0200 Subject: [PATCH 085/278] convert Socket to use Address class --- examples/simple-p2p.cc | 7 +-- samples/main-simple.cc | 9 ++- src/applications/onoff-application.cc | 20 +++--- src/applications/onoff-application.h | 20 +++--- src/internet-node/udp-socket.cc | 83 +++++++++++++++--------- src/internet-node/udp-socket.h | 27 ++++---- src/node/socket.cc | 28 ++++----- src/node/socket.h | 91 +++++++++------------------ 8 files changed, 133 insertions(+), 152 deletions(-) diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index ac98440c8..c5b0e61ce 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -57,6 +57,7 @@ #include "ns3/p2p-channel.h" #include "ns3/p2p-net-device.h" #include "ns3/ipv4-address.h" +#include "ns3/ipv4-transport-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" #include "ns3/ipv4-route.h" @@ -142,8 +143,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - Ipv4Address("10.1.3.2"), - 80, + Ipv4TransportAddress(Ipv4Address ("10.1.3.2"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -154,8 +154,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - Ipv4Address("10.1.2.1"), - 80, + Ipv4TransportAddress(Ipv4Address ("10.1.2.1"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/samples/main-simple.cc b/samples/main-simple.cc index f0f4ce4dc..80128d7d5 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -4,6 +4,7 @@ #include "ns3/simulator.h" #include "ns3/socket-factory.h" #include "ns3/socket.h" +#include "ns3/ipv4-transport-address.h" #include "ns3/nstime.h" using namespace ns3; @@ -24,7 +25,7 @@ GenerateTraffic (Ptr socket, uint32_t size) } static void -SocketPrinter (Ptr socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort) +SocketPrinter (Ptr socket, uint32_t size, const Address &from) { std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl; } @@ -44,10 +45,12 @@ RunSimulation (void) Ptr socketFactory = a->QueryInterface (iid); Ptr sink = socketFactory->CreateSocket (); - sink->Bind (80); + Ipv4TransportAddress local = Ipv4TransportAddress (Ipv4Address::GetAny (), 80); + sink->Bind (local.ConvertTo ()); Ptr source = socketFactory->CreateSocket (); - source->Connect (Ipv4Address::GetLoopback (), 80); + Ipv4TransportAddress remote = Ipv4TransportAddress (Ipv4Address::GetLoopback (), 80); + source->Connect (remote.ConvertTo ()); GenerateTraffic (source, 500); PrintTraffic (sink); diff --git a/src/applications/onoff-application.cc b/src/applications/onoff-application.cc index f9c4146c8..5fa2c8266 100644 --- a/src/applications/onoff-application.cc +++ b/src/applications/onoff-application.cc @@ -22,7 +22,7 @@ // George F. Riley, Georgia Tech, Spring 2007 // Adapted from ApplicationOnOff in GTNetS. -#include "ns3/ipv4-address.h" +#include "ns3/address.h" #include "ns3/node.h" #include "ns3/nstime.h" #include "ns3/data-rate.h" @@ -47,22 +47,20 @@ static NumericDefaultValue g_defaultSize ("OnOffApplicationPacketSize" // Constructors OnOffApplication::OnOffApplication(Ptr n, - const Ipv4Address rip, - uint16_t rport, + const Address &remote, std::string iid, const RandomVariable& ontime, const RandomVariable& offtime) : Application(n), m_cbrRate (g_defaultRate.GetValue ()) { - Construct (n, rip, rport, iid, + Construct (n, remote, iid, ontime, offtime, g_defaultSize.GetValue ()); } OnOffApplication::OnOffApplication(Ptr n, - const Ipv4Address rip, - uint16_t rport, + const Address &remote, std::string iid, const RandomVariable& ontime, const RandomVariable& offtime, @@ -71,22 +69,20 @@ OnOffApplication::OnOffApplication(Ptr n, : Application(n), m_cbrRate (rate) { - Construct (n, rip, rport, iid, + Construct (n, remote, iid, ontime, offtime, size); } void OnOffApplication::Construct (Ptr n, - const Ipv4Address rip, - uint16_t rport, + const Address &remote, std::string iid, const RandomVariable& onTime, const RandomVariable& offTime, uint32_t size) { m_socket = 0; - m_peerIp = rip; - m_peerPort = rport; + m_peer = remote; m_connected = false; m_onTime = onTime.Copy (); m_offTime = offTime.Copy (); @@ -144,7 +140,7 @@ void OnOffApplication::StartApplication() // Called at time specified by Star Ptr socketFactory = GetNode ()->QueryInterface (iid); m_socket = socketFactory->CreateSocket (); m_socket->Bind (); - m_socket->Connect (m_peerIp, m_peerPort); + m_socket->Connect (m_peer); } // Insure no pending event StopApplication(); diff --git a/src/applications/onoff-application.h b/src/applications/onoff-application.h index e3aafcb11..c42d9d14f 100644 --- a/src/applications/onoff-application.h +++ b/src/applications/onoff-application.h @@ -31,7 +31,7 @@ namespace ns3 { -class Ipv4Address; +class Address; class RandomVariable; class Socket; class DataRate; @@ -52,23 +52,20 @@ class OnOffApplication : public Application public: /** * \param n node associated to this application - * \param rip remote ip address - * \param rport remove port number + * \param remote remote ip address * \param iid * \param ontime on time random variable * \param offtime off time random variable */ OnOffApplication(Ptr n, - const Ipv4Address rip, - uint16_t rport, + const Address &remote, std::string iid, const RandomVariable& ontime, const RandomVariable& offtime); /** * \param n node associated to this application - * \param rip remote ip address - * \param rport remove port number + * \param remote remote ip address * \param iid * \param ontime on time random variable * \param offtime off time random variable @@ -76,8 +73,7 @@ public: * \param size size of packets when sending data. */ OnOffApplication(Ptr n, - const Ipv4Address rip, - uint16_t rport, + const Address &remote, std::string iid, const RandomVariable& ontime, const RandomVariable& offtime, @@ -112,8 +108,7 @@ private: virtual void StopApplication (void); // Called at time specified by Stop void Construct (Ptr n, - const Ipv4Address rip, - uint16_t rport, + const Address &remote, std::string iid, const RandomVariable& ontime, const RandomVariable& offtime, @@ -126,8 +121,7 @@ private: void SendPacket(); Ptr m_socket; // Associated socket - Ipv4Address m_peerIp; // Peer IP address - uint16_t m_peerPort; // Peer port + Address m_peer; // Peer address bool m_connected; // True if connected RandomVariable* m_onTime; // rng for On Time RandomVariable* m_offTime; // rng for Off Time diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 0ab911c9e..97b6a3564 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -19,6 +19,7 @@ * Author: Mathieu Lacage */ #include "ns3/node.h" +#include "ns3/ipv4-transport-address.h" #include "udp-socket.h" #include "udp-l4-protocol.h" #include "ipv4-end-point.h" @@ -88,21 +89,28 @@ UdpSocket::Bind (void) return FinishBind (); } int -UdpSocket::Bind (Ipv4Address address) +UdpSocket::Bind (const Address &address) { - m_endPoint = m_udp->Allocate (address); - return FinishBind (); -} -int -UdpSocket::Bind (uint16_t port) -{ - m_endPoint = m_udp->Allocate (port); - return FinishBind (); -} -int -UdpSocket::Bind (Ipv4Address address, uint16_t port) -{ - m_endPoint = m_udp->Allocate (address, port); + Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + Ipv4Address ipv4 = transport.GetIpv4 (); + uint16_t port = transport.GetPort (); + if (ipv4 == Ipv4Address::GetAny () && port == 0) + { + m_endPoint = m_udp->Allocate (); + } + else if (ipv4 == Ipv4Address::GetAny () && port != 0) + { + m_endPoint = m_udp->Allocate (port); + } + else if (ipv4 != Ipv4Address::GetAny () && port == 0) + { + m_endPoint = m_udp->Allocate (ipv4); + } + else if (ipv4 != Ipv4Address::GetAny () && port != 0) + { + m_endPoint = m_udp->Allocate (ipv4, port); + } + return FinishBind (); } @@ -134,14 +142,14 @@ UdpSocket::DoClose(ns3::Callback > closeCompleted) } } void -UdpSocket::DoConnect(const Ipv4Address & address, - uint16_t portNumber, +UdpSocket::DoConnect(const Address & address, ns3::Callback > connectionSucceeded, ns3::Callback > connectionFailed, ns3::Callback > halfClose) { - m_defaultAddress = address; - m_defaultPort = portNumber; + Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + m_defaultAddress = transport.GetIpv4 (); + m_defaultPort = transport.GetPort (); if (!connectionSucceeded.IsNull ()) { connectionSucceeded (this); @@ -149,8 +157,8 @@ UdpSocket::DoConnect(const Ipv4Address & address, m_connected = true; } int -UdpSocket::DoAccept(ns3::Callback, const Ipv4Address&, uint16_t> connectionRequest, - ns3::Callback, const Ipv4Address&, uint16_t> newConnectionCreated, +UdpSocket::DoAccept(ns3::Callback, const Address&> connectionRequest, + ns3::Callback, const Address&> newConnectionCreated, ns3::Callback > closeRequested) { // calling accept on a udp socket is a programming error. @@ -179,7 +187,16 @@ UdpSocket::DoSend (const uint8_t* buffer, return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent); } int -UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, +UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, + ns3::Callback, uint32_t> dataSent) +{ + Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + Ipv4Address ipv4 = transport.GetIpv4 (); + uint16_t port = transport.GetPort (); + return DoSendPacketTo (p, ipv4, port, dataSent); +} +int +UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address ipv4, uint16_t port, ns3::Callback, uint32_t> dataSent) { if (m_endPoint == 0) @@ -196,8 +213,8 @@ UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, m_errno = ERROR_SHUTDOWN; return -1; } - m_udp->Send (p, m_endPoint->GetLocalAddress (), daddr, - m_endPoint->GetLocalPort (), dport); + m_udp->Send (p, m_endPoint->GetLocalAddress (), ipv4, + m_endPoint->GetLocalPort (), port); if (!dataSent.IsNull ()) { dataSent (this, p.GetSize ()); @@ -205,8 +222,7 @@ UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, return 0; } int -UdpSocket::DoSendTo(const Ipv4Address &address, - uint16_t port, +UdpSocket::DoSendTo(const Address &address, const uint8_t *buffer, uint32_t size, ns3::Callback, uint32_t> dataSent) @@ -225,34 +241,39 @@ UdpSocket::DoSendTo(const Ipv4Address &address, { p = Packet (buffer, size); } - return DoSendPacketTo (p, address, port, dataSent); + Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + Ipv4Address ipv4 = transport.GetIpv4 (); + uint16_t port = transport.GetPort (); + return DoSendPacketTo (p, ipv4, port, dataSent); } void -UdpSocket::DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback) +UdpSocket::DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Address&> callback) { m_rxCallback = callback; } void -UdpSocket::DoRecvDummy(ns3::Callback, uint32_t,const Ipv4Address&, uint16_t> callback) +UdpSocket::DoRecvDummy(ns3::Callback, uint32_t,const Address&> callback) { m_dummyRxCallback = callback; } void -UdpSocket::ForwardUp (const Packet &packet, Ipv4Address saddr, uint16_t sport) +UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) { if (m_shutdownRecv) { return; } + + Address address = Ipv4TransportAddress (ipv4, port).ConvertTo (); Packet p = packet; if (!m_dummyRxCallback.IsNull ()) { - m_dummyRxCallback (this, p.GetSize (), saddr, sport); + m_dummyRxCallback (this, p.GetSize (), address); } if (!m_rxCallback.IsNull ()) { - m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport); + m_rxCallback (this, p.PeekData (), p.GetSize (), address); } } diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket.h index c2923c80f..82d3cd6a3 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket.h @@ -25,6 +25,7 @@ #include "ns3/callback.h" #include "ns3/socket.h" #include "ns3/ptr.h" +#include "ns3/ipv4-address.h" namespace ns3 { @@ -45,39 +46,37 @@ public: virtual enum SocketErrno GetErrno (void) const; virtual Ptr GetNode (void) const; virtual int Bind (void); - virtual int Bind (Ipv4Address address); - virtual int Bind (uint16_t port); - virtual int Bind (Ipv4Address address, uint16_t port); + virtual int Bind (const Address &address); virtual int ShutdownSend (void); virtual int ShutdownRecv (void); private: virtual void DoClose(ns3::Callback > closeCompleted); - virtual void DoConnect(const Ipv4Address & address, - uint16_t portNumber, + virtual void DoConnect(const Address & address, ns3::Callback > connectionSucceeded, ns3::Callback > connectionFailed, ns3::Callback > halfClose); - virtual int DoAccept(ns3::Callback, const Ipv4Address&, uint16_t> connectionRequest, - ns3::Callback, const Ipv4Address&, uint16_t> newConnectionCreated, + virtual int DoAccept(ns3::Callback, const Address&> connectionRequest, + ns3::Callback, const Address&> newConnectionCreated, ns3::Callback > closeRequested); virtual int DoSend (const uint8_t* buffer, uint32_t size, ns3::Callback, uint32_t> dataSent); - virtual int DoSendTo(const Ipv4Address &address, - uint16_t port, + virtual int DoSendTo(const Address &address, const uint8_t *buffer, uint32_t size, ns3::Callback, uint32_t> dataSent); - virtual void DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t>); - virtual void DoRecvDummy(ns3::Callback, uint32_t,const Ipv4Address&, uint16_t>); + virtual void DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Address&>); + virtual void DoRecvDummy(ns3::Callback, uint32_t,const Address&>); private: friend class Udp; // invoked by Udp class int FinishBind (void); - void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport); + void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port); void Destroy (void); + int DoSendPacketTo (const Packet &p, const Address &daddr, + ns3::Callback, uint32_t> dataSent); int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, ns3::Callback, uint32_t> dataSent); @@ -86,8 +85,8 @@ private: Ptr m_udp; Ipv4Address m_defaultAddress; uint16_t m_defaultPort; - Callback,uint32_t,const Ipv4Address &,uint16_t> m_dummyRxCallback; - Callback,uint8_t const*,uint32_t,const Ipv4Address &,uint16_t> m_rxCallback; + Callback,uint32_t,const Address &> m_dummyRxCallback; + Callback,uint8_t const*,uint32_t,const Address &> m_rxCallback; enum SocketErrno m_errno; bool m_shutdownSend; bool m_shutdownRecv; diff --git a/src/node/socket.cc b/src/node/socket.cc index 75cd3a023..b8995cfea 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -12,17 +12,16 @@ Socket::Close(Callback > closeCompleted) } void -Socket::Connect(const Ipv4Address & address, - uint16_t portNumber, +Socket::Connect(const Address & address, Callback > connectionSucceeded, Callback > connectionFailed, Callback > halfClose) { - DoConnect (address, portNumber, connectionSucceeded, connectionFailed, halfClose); + DoConnect (address, connectionSucceeded, connectionFailed, halfClose); } int -Socket::Accept(Callback, const Ipv4Address&, uint16_t> connectionRequest, - Callback, const Ipv4Address&, uint16_t> newConnectionCreated, +Socket::Accept(Callback, const Address&> connectionRequest, + Callback, const Address&> newConnectionCreated, Callback > closeRequested) { return DoAccept (connectionRequest, newConnectionCreated, closeRequested); @@ -35,28 +34,27 @@ Socket::Send (const uint8_t* buffer, return DoSend (buffer, size, dataSent); } int -Socket::SendTo(const Ipv4Address &address, - uint16_t port, +Socket::SendTo(const Address &address, const uint8_t *buffer, uint32_t size, Callback, uint32_t> dataSent) { - return DoSendTo (address, port, buffer, size, dataSent); + return DoSendTo (address, buffer, size, dataSent); } void -Socket::Recv(Callback, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback) +Socket::Recv(Callback, const uint8_t*, uint32_t,const Address&> callback) { DoRecv (callback); } void -Socket::RecvDummy(Callback, uint32_t,const Ipv4Address&, uint16_t> callback) +Socket::RecvDummy(Callback, uint32_t,const Address&> callback) { DoRecvDummy (callback); } bool -Socket::RefuseAllConnections (Ptr socket, const Ipv4Address& address, uint16_t port) +Socket::RefuseAllConnections (Ptr socket, const Address& address) { return false; } @@ -67,14 +65,14 @@ void Socket::DummyCallbackVoidSocketUi32 (Ptr socket, uint32_t) {} void -Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr socket, uint32_t, const Ipv4Address &, uint16_t) +Socket::DummyCallbackVoidSocketUi32Address (Ptr socket, uint32_t, const Address &) {} void -Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr socket, const uint8_t *, uint32_t, - const Ipv4Address &, uint16_t) +Socket::DummyCallbackVoidSocketBufferUi32Address (Ptr socket, const uint8_t *, uint32_t, + const Address &) {} void -Socket::DummyCallbackVoidSocketIpv4AddressUi16 (Ptr socket, const Ipv4Address &, uint16_t) +Socket::DummyCallbackVoidSocketAddress (Ptr socket, const Address &) {} diff --git a/src/node/socket.h b/src/node/socket.h index b0ec81b05..3cba7fd59 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -23,8 +23,8 @@ #include "ns3/callback.h" #include "ns3/ptr.h" -#include "ipv4-address.h" #include "ns3/object.h" +#include "address.h" #include namespace ns3 { @@ -35,8 +35,7 @@ class Node; * \brief Define a Socket API based on the BSD Socket API. * * Contrary to the original BSD socket API, this API is asynchronous: - * it does not contain blocking calls. This API also does not use - * the dreaded BSD sockaddr_t type. Other than that, it tries to stick + * it does not contain blocking calls. Other than that, it tries to stick * to the BSD API to make it easier those who know the BSD API to use * this API. */ @@ -69,42 +68,20 @@ public: virtual Ptr GetNode (void) const = 0; /** - * Allocate a free port number and - * bind this socket to this port number on all - * interfaces of this system. - * + * \param address the address to try to allocate * \returns 0 on success, -1 on failure. + * + * Allocate a local endpoint for this socket. */ - virtual int Bind (void) = 0; + virtual int Bind (const Address &address) = 0; /** - * Allocate a free port number and - * bind this socket to this port number on the - * specified interface. + * Allocate a local endpoint for this socket. * - * \param address address of interface to bind to. * \returns 0 on success, -1 on failure. */ - virtual int Bind (Ipv4Address address) = 0; + virtual int Bind () = 0; - /** - * Bind this socket to this port number - * on all interfaces of this system. - * - * \param port port to bind to on all interfaces - * \returns 0 on success, -1 on failure. - */ - virtual int Bind (uint16_t port) = 0; - - /** - * Bind this socket to this port number - * on the interface specified by address. - * - * \param address address of interface to bind to. - * \param port port to bind to on specified interface - * \returns 0 on success, -1 on failure. - */ - virtual int Bind (Ipv4Address address, uint16_t port) = 0; /** * \brief Close a socket. @@ -134,8 +111,7 @@ public: /** * \brief Initiate a connection to a remote host - * \param address IP Address of remote. - * \param portNumber Port number of remote + * \param address Address of remote. * \param connectionSucceeded this callback is invoked when the connection request * initiated by the user is successfully completed. The callback is passed * back a pointer to the same socket object. @@ -145,8 +121,7 @@ public: * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the * other side closes the connection ? Or when I call Close ? */ - void Connect(const Ipv4Address & address, - uint16_t portNumber, + void Connect(const Address &address, Callback > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket), Callback > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket), Callback > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket)); @@ -170,10 +145,10 @@ public: * \param closeRequested Callback for connection close request from peer. * XXX: when is this callback invoked ? */ - int Accept(Callback, const Ipv4Address&, uint16_t> connectionRequest = + int Accept(Callback, const Address &> connectionRequest = MakeCallback(&Socket::RefuseAllConnections), - Callback, const Ipv4Address&, uint16_t> newConnectionCreated = - MakeCallback (&Socket::DummyCallbackVoidSocketIpv4AddressUi16), + Callback, const Address&> newConnectionCreated = + MakeCallback (&Socket::DummyCallbackVoidSocketAddress), Callback > closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket)); /** @@ -191,15 +166,13 @@ public: /** * \brief Send data to a specified peer. * \param address IP Address of remote host - * \param port port number * \param buffer Data to send (nil if dummy data). * \param size Number of bytes to send. * \param dataSent Data sent callback. * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - int SendTo(const Ipv4Address &address, - uint16_t port, + int SendTo(const Address &address, const uint8_t *buffer, uint32_t size, Callback, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32)); @@ -213,8 +186,8 @@ public: * allocation to hold the dummy memory into a buffer which can be passed * to the user. Instead, consider using the RecvDummy method. */ - void Recv(Callback, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receivedData = - MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16)); + void Recv(Callback, const uint8_t*, uint32_t,const Address&> receivedData = + MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Address)); /** * \brief Receive data @@ -223,38 +196,36 @@ public: * This method is included because it is vastly more efficient than the * Recv method when you use dummy payload. */ - void RecvDummy(Callback, uint32_t,const Ipv4Address&, uint16_t> receivedData = - MakeCallback (&Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16)); + void RecvDummy(Callback, uint32_t,const Address&> receivedData = + MakeCallback (&Socket::DummyCallbackVoidSocketUi32Address)); private: virtual void DoClose(Callback > closeCompleted) = 0; - virtual void DoConnect(const Ipv4Address & address, - uint16_t portNumber, + virtual void DoConnect(const Address & address, Callback > connectionSucceeded, Callback > connectionFailed, Callback > halfClose) = 0; - virtual int DoAccept(Callback, const Ipv4Address&, uint16_t> connectionRequest, - Callback, const Ipv4Address&, uint16_t> newConnectionCreated, + virtual int DoAccept(Callback, const Address&> connectionRequest, + Callback, const Address&> newConnectionCreated, Callback > closeRequested) = 0; virtual int DoSend (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent) = 0; - virtual int DoSendTo(const Ipv4Address &address, - uint16_t port, + uint32_t size, + Callback, uint32_t> dataSent) = 0; + virtual int DoSendTo(const Address &address, const uint8_t *buffer, uint32_t size, Callback, uint32_t> dataSent) = 0; - virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receive) = 0; - virtual void DoRecvDummy(Callback, uint32_t,const Ipv4Address&, uint16_t>) = 0; + virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Address&> receive) = 0; + virtual void DoRecvDummy(Callback, uint32_t,const Address&>) = 0; - static bool RefuseAllConnections (Ptr socket, const Ipv4Address& address, uint16_t port); + static bool RefuseAllConnections (Ptr socket, const Address& address); static void DummyCallbackVoidSocket (Ptr socket); static void DummyCallbackVoidSocketUi32 (Ptr socket, uint32_t); - static void DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr socket, uint32_t, const Ipv4Address &, uint16_t); - static void DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr socket, const uint8_t *, uint32_t, - const Ipv4Address &, uint16_t); - static void DummyCallbackVoidSocketIpv4AddressUi16 (Ptr socket, const Ipv4Address &, uint16_t); + static void DummyCallbackVoidSocketUi32Address (Ptr socket, uint32_t, const Address &); + static void DummyCallbackVoidSocketBufferUi32Address (Ptr socket, const uint8_t *, uint32_t, + const Address &); + static void DummyCallbackVoidSocketAddress (Ptr socket, const Address &); }; } //namespace ns3 From 863de62880e2e4ca7f7ab652015708c569a6947b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 08:32:34 +0200 Subject: [PATCH 086/278] ipv4-transport-address -> inet-address --- examples/simple-p2p.cc | 2 +- samples/main-simple.cc | 2 +- src/internet-node/udp-socket.cc | 2 +- src/node/{ipv4-transport-address.cc => inet-address.cc} | 2 +- src/node/{ipv4-transport-address.h => inet-address.h} | 0 src/node/wscript | 4 ++-- 6 files changed, 6 insertions(+), 6 deletions(-) rename src/node/{ipv4-transport-address.cc => inet-address.cc} (97%) rename src/node/{ipv4-transport-address.h => inet-address.h} (100%) diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index c5b0e61ce..9aaff28f3 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -57,7 +57,7 @@ #include "ns3/p2p-channel.h" #include "ns3/p2p-net-device.h" #include "ns3/ipv4-address.h" -#include "ns3/ipv4-transport-address.h" +#include "ns3/inet-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" #include "ns3/ipv4-route.h" diff --git a/samples/main-simple.cc b/samples/main-simple.cc index 80128d7d5..bdfd9e6f8 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -4,7 +4,7 @@ #include "ns3/simulator.h" #include "ns3/socket-factory.h" #include "ns3/socket.h" -#include "ns3/ipv4-transport-address.h" +#include "ns3/inet-address.h" #include "ns3/nstime.h" using namespace ns3; diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 97b6a3564..d92cde129 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -19,7 +19,7 @@ * Author: Mathieu Lacage */ #include "ns3/node.h" -#include "ns3/ipv4-transport-address.h" +#include "ns3/inet-address.h" #include "udp-socket.h" #include "udp-l4-protocol.h" #include "ipv4-end-point.h" diff --git a/src/node/ipv4-transport-address.cc b/src/node/inet-address.cc similarity index 97% rename from src/node/ipv4-transport-address.cc rename to src/node/inet-address.cc index 9330737c8..2f7fff7c6 100644 --- a/src/node/ipv4-transport-address.cc +++ b/src/node/inet-address.cc @@ -1,4 +1,4 @@ -#include "ipv4-transport-address.h" +#include "inet-address.h" #include "ns3/assert.h" namespace ns3 { diff --git a/src/node/ipv4-transport-address.h b/src/node/inet-address.h similarity index 100% rename from src/node/ipv4-transport-address.h rename to src/node/inet-address.h diff --git a/src/node/wscript b/src/node/wscript index 738402fd3..d02aea513 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -8,7 +8,7 @@ def build(bld): node.source = [ 'address.cc', 'eui48-address.cc', - 'ipv4-transport-address.cc', + 'inet-address.cc', 'node.cc', 'ipv4-address.cc', 'net-device.cc', @@ -30,7 +30,7 @@ def build(bld): headers.source = [ 'address.h', 'eui48-address.h', - 'ipv4-transport-address.h', + 'inet-address.h', 'node.h', 'ipv4-address.h', 'net-device.h', From 695119b3a505b04d78e6c6ce29b3cb67db8720c2 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 08:44:26 +0200 Subject: [PATCH 087/278] Ipv4TransportAddress -> InetAddress --- examples/simple-p2p.cc | 4 ++-- samples/main-simple.cc | 4 ++-- src/internet-node/udp-socket.cc | 10 +++++----- src/node/inet-address.cc | 24 ++++++++++++------------ src/node/inet-address.h | 10 +++++----- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index 9aaff28f3..ec41936a8 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -143,7 +143,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - Ipv4TransportAddress(Ipv4Address ("10.1.3.2"), 80).ConvertTo (), + InetAddress(Ipv4Address ("10.1.3.2"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -154,7 +154,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - Ipv4TransportAddress(Ipv4Address ("10.1.2.1"), 80).ConvertTo (), + InetAddress(Ipv4Address ("10.1.2.1"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/samples/main-simple.cc b/samples/main-simple.cc index bdfd9e6f8..4c709b4c5 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -45,11 +45,11 @@ RunSimulation (void) Ptr socketFactory = a->QueryInterface (iid); Ptr sink = socketFactory->CreateSocket (); - Ipv4TransportAddress local = Ipv4TransportAddress (Ipv4Address::GetAny (), 80); + InetAddress local = InetAddress (Ipv4Address::GetAny (), 80); sink->Bind (local.ConvertTo ()); Ptr source = socketFactory->CreateSocket (); - Ipv4TransportAddress remote = Ipv4TransportAddress (Ipv4Address::GetLoopback (), 80); + InetAddress remote = InetAddress (Ipv4Address::GetLoopback (), 80); source->Connect (remote.ConvertTo ()); GenerateTraffic (source, 500); diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index d92cde129..9ae438f6b 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -91,7 +91,7 @@ UdpSocket::Bind (void) int UdpSocket::Bind (const Address &address) { - Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + InetAddress transport = InetAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); if (ipv4 == Ipv4Address::GetAny () && port == 0) @@ -147,7 +147,7 @@ UdpSocket::DoConnect(const Address & address, ns3::Callback > connectionFailed, ns3::Callback > halfClose) { - Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + InetAddress transport = InetAddress::ConvertFrom (address); m_defaultAddress = transport.GetIpv4 (); m_defaultPort = transport.GetPort (); if (!connectionSucceeded.IsNull ()) @@ -190,7 +190,7 @@ int UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, ns3::Callback, uint32_t> dataSent) { - Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + InetAddress transport = InetAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -241,7 +241,7 @@ UdpSocket::DoSendTo(const Address &address, { p = Packet (buffer, size); } - Ipv4TransportAddress transport = Ipv4TransportAddress::ConvertFrom (address); + InetAddress transport = InetAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -265,7 +265,7 @@ UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) return; } - Address address = Ipv4TransportAddress (ipv4, port).ConvertTo (); + Address address = InetAddress (ipv4, port).ConvertTo (); Packet p = packet; if (!m_dummyRxCallback.IsNull ()) { diff --git a/src/node/inet-address.cc b/src/node/inet-address.cc index 2f7fff7c6..2c48cc922 100644 --- a/src/node/inet-address.cc +++ b/src/node/inet-address.cc @@ -3,42 +3,42 @@ namespace ns3 { -Ipv4TransportAddress::Ipv4TransportAddress (Ipv4Address ipv4, uint16_t port) +InetAddress::InetAddress (Ipv4Address ipv4, uint16_t port) : m_ipv4 (ipv4), m_port (port) {} -Ipv4TransportAddress::Ipv4TransportAddress (Ipv4Address ipv4) +InetAddress::InetAddress (Ipv4Address ipv4) : m_ipv4 (ipv4), m_port (0) {} -Ipv4TransportAddress::Ipv4TransportAddress (uint16_t port) +InetAddress::InetAddress (uint16_t port) : m_ipv4 (Ipv4Address::GetAny ()), m_port (port) {} uint16_t -Ipv4TransportAddress::GetPort (void) const +InetAddress::GetPort (void) const { return m_port; } Ipv4Address -Ipv4TransportAddress::GetIpv4 (void) const +InetAddress::GetIpv4 (void) const { return m_ipv4; } void -Ipv4TransportAddress::SetPort (uint16_t port) +InetAddress::SetPort (uint16_t port) { m_port = port; } void -Ipv4TransportAddress::SetIpv4 (Ipv4Address address) +InetAddress::SetIpv4 (Ipv4Address address) { m_ipv4 = address; } Address -Ipv4TransportAddress::ConvertTo (void) const +InetAddress::ConvertTo (void) const { uint8_t buf[6]; m_ipv4.Serialize (buf); @@ -46,18 +46,18 @@ Ipv4TransportAddress::ConvertTo (void) const buf[5] = (m_port >> 8) & 0xff; return Address (GetType (), buf, 6); } -Ipv4TransportAddress -Ipv4TransportAddress::ConvertFrom (const Address &address) +InetAddress +InetAddress::ConvertFrom (const Address &address) { NS_ASSERT (address.CheckCompatible (GetType (), 6)); uint8_t buf[6]; address.CopyTo (buf); Ipv4Address ipv4 = Ipv4Address::Deserialize (buf); uint16_t port = buf[0] | (buf[1] << 8); - return Ipv4TransportAddress (ipv4, port); + return InetAddress (ipv4, port); } uint8_t -Ipv4TransportAddress::GetType (void) +InetAddress::GetType (void) { static uint8_t type = Address::Register (); return type; diff --git a/src/node/inet-address.h b/src/node/inet-address.h index e73ca8d3d..51c0766fb 100644 --- a/src/node/inet-address.h +++ b/src/node/inet-address.h @@ -7,12 +7,12 @@ namespace ns3 { -class Ipv4TransportAddress +class InetAddress { public: - Ipv4TransportAddress (Ipv4Address ipv4, uint16_t port); - Ipv4TransportAddress (Ipv4Address ipv4); - Ipv4TransportAddress (uint16_t post); + InetAddress (Ipv4Address ipv4, uint16_t port); + InetAddress (Ipv4Address ipv4); + InetAddress (uint16_t post); uint16_t GetPort (void) const; Ipv4Address GetIpv4 (void) const; @@ -20,7 +20,7 @@ public: void SetIpv4 (Ipv4Address address); Address ConvertTo (void) const; - static Ipv4TransportAddress ConvertFrom (const Address &address); + static InetAddress ConvertFrom (const Address &address); private: static uint8_t GetType (void); Ipv4Address m_ipv4; From 8474486b7404ee1ab223345506b962277397bec3 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 08:47:58 +0200 Subject: [PATCH 088/278] add extra conveniance constructors and use them --- examples/simple-p2p.cc | 4 ++-- src/node/inet-address.cc | 8 ++++++++ src/node/inet-address.h | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index ec41936a8..5d1bb545e 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -143,7 +143,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - InetAddress(Ipv4Address ("10.1.3.2"), 80).ConvertTo (), + InetAddress("10.1.3.2", 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -154,7 +154,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - InetAddress(Ipv4Address ("10.1.2.1"), 80).ConvertTo (), + InetAddress("10.1.2.1", 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/src/node/inet-address.cc b/src/node/inet-address.cc index 2c48cc922..bf82cfc83 100644 --- a/src/node/inet-address.cc +++ b/src/node/inet-address.cc @@ -11,6 +11,14 @@ InetAddress::InetAddress (Ipv4Address ipv4) : m_ipv4 (ipv4), m_port (0) {} +InetAddress::InetAddress (const char *ipv4, uint16_t port) + : m_ipv4 (Ipv4Address (ipv4)), + m_port (port) +{} +InetAddress::InetAddress (const char * ipv4) + : m_ipv4 (Ipv4Address (ipv4)), + m_port (0) +{} InetAddress::InetAddress (uint16_t port) : m_ipv4 (Ipv4Address::GetAny ()), m_port (port) diff --git a/src/node/inet-address.h b/src/node/inet-address.h index 51c0766fb..6ba6da5de 100644 --- a/src/node/inet-address.h +++ b/src/node/inet-address.h @@ -12,7 +12,9 @@ class InetAddress public: InetAddress (Ipv4Address ipv4, uint16_t port); InetAddress (Ipv4Address ipv4); - InetAddress (uint16_t post); + InetAddress (uint16_t port); + InetAddress (const char *ipv4, uint16_t port); + InetAddress (const char *ipv4); uint16_t GetPort (void) const; Ipv4Address GetIpv4 (void) const; From 3cec6af4a86d98fa9c3cc0aed421a947219536f2 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 09:44:24 +0200 Subject: [PATCH 089/278] add doxygen --- src/node/address.cc | 2 +- src/node/address.h | 98 ++++++++++++++++++++++++++++++++++++++-- src/node/eui48-address.h | 24 ++++++++++ src/node/inet-address.h | 54 +++++++++++++++++++++- 4 files changed, 173 insertions(+), 5 deletions(-) diff --git a/src/node/address.cc b/src/node/address.cc index 408a152e6..9bb67f4fb 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -47,7 +47,7 @@ Address::GetLength (void) const return m_len; } void -Address::CopyTo (uint8_t *buffer) const +Address::CopyTo (uint8_t buffer[MAX_SIZE]) const { NS_ASSERT (m_len <= MAX_SIZE); memcpy (buffer, m_data, m_len); diff --git a/src/node/address.h b/src/node/address.h index 417bdce0a..e6bbec026 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -6,24 +6,116 @@ namespace ns3 { +/** + * \brief a polymophic address class + * + * This class is very similar in design and spirit to the BSD sockaddr + * structure: they are both used to hold multiple types of addresses + * together with the type of the address. + * + * A new address class defined by a user needs to: + * - allocate a type id with Address::Register + * - provide a method to convert his new address to an Address + * instance. This method is typically a member method named ConvertTo: + * Address MyAddress::ConvertTo (void) const; + * - provide a method to convert an Address instance back to + * an instance of his new address type. This method is typically + * a static member method of his address class named ConvertFrom: + * static MyAddress MyAddress::ConvertFrom (const Address &address); + * - the ConvertFrom method is expected to check that the type of the + * input Address instance is compatible with its own type. + * + * Typical code to create a new class type looks like: + * \code + * // this class represents addresses which are 2 bytes long. + * class MyAddress + * { + * public: + * Address ConvertTo (void) const; + * static MyAddress ConvertFrom (void); + * private: + * static uint8_t GetType (void); + * }; + * + * Address MyAddress::ConvertTo (void) const + * { + * return Address (GetType (), m_buffer, 2); + * } + * MyAddress MyAddress::ConvertFrom (const Address &address) + * { + * MyAddress ad; + * NS_ASSERT (address.CheckCompatible (GetType (), 2)); + * address.CopyTo (ad.m_buffer, 2); + * return ad; + * } + * uint8_t MyAddress::GetType (void) + * { + * static uint8_t type = Address::Register (); + * return type; + * } + * \endcode + */ class Address { public: enum { + /** + * The maximum size of a byte buffer which + * can be stored in an Address instance. + */ MAX_SIZE = 14 }; + /** + * Create an invalid address + */ Address (); + /** + * \param type the type of the Address to create + * \param buffer a pointer to a buffer of bytes which hold + * a serialized representation of the address in network + * byte order. + * \param len the length of the buffer. + * + * Create an address from a type and a buffer. This constructor + * is typically invoked from the conversion functions of various + * address types when they have to convert themselves to an + * Address instance. + */ Address (uint8_t type, const uint8_t *buffer, uint8_t len); Address (const Address & address); Address &operator = (const Address &address); + /** + * \returns the length of the underlying address. + */ uint8_t GetLength (void) const; - void CopyTo (uint8_t *buffer) const; + /** + * \param buffer buffer to copy the address bytes to. + */ + void CopyTo (uint8_t buffer[MAX_SIZE]) const; + /** + * \param buffer pointer to a buffer of bytes which contain + * a serialized representation of the address in network + * byte order. + * \param len length of buffer + * + * Copy the input buffer to the internal buffer of this address + * instance. + */ void CopyFrom (uint8_t *buffer, uint8_t len); + /** + * \param type a type id as returned by Address::Register + * \param len the length associated to this type id. + * + * \returns true if the type of the address stored internally + * is compatible with the requested type, false otherwise. + */ bool CheckCompatible (uint8_t type, uint8_t len) const; - - + /** + * Allocate a new type id for a new type of address. + * \returns a new type id. + */ static uint8_t Register (void); private: friend bool operator == (const Address &a, const Address &b); diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h index b051b4c31..d113503db 100644 --- a/src/node/eui48-address.h +++ b/src/node/eui48-address.h @@ -7,13 +7,37 @@ namespace ns3 { class Address; +/** + * \brief an EUI-48 address + * + * This class can contain 48 bit IEEE addresses. + */ class Eui48Address { public: Eui48Address (); + /** + * \param str a string representing the new Eui48Address + * + * The format of the string is "xx:xx:xx:xx:xx:xx" + */ Eui48Address (const char *str); + /** + * \returns a new Address instance + * + * Convert an instance of this class to a polymorphic Address instance. + */ Address ConvertTo (void) const; + /** + * \param address a polymorphic address + * + * Convert a polymorphic address to an Eui48Address instance. + * The conversion performs a type check. + */ static Eui48Address ConvertFrom (const Address &address); + /** + * Allocate a new Eui48Address. + */ static Eui48Address Allocate (void); private: static uint8_t GetType (void); diff --git a/src/node/inet-address.h b/src/node/inet-address.h index 6ba6da5de..577974325 100644 --- a/src/node/inet-address.h +++ b/src/node/inet-address.h @@ -7,21 +7,73 @@ namespace ns3 { + +/** + * \brief an Inet address class + * + * This class is similar to inet_sockaddr in the BSD socket + * API. i.e., this class holds an Ipv4Address and a port number + * to form an ipv4 transport endpoint. + */ class InetAddress { public: + /** + * \param ipv4 the ipv4 address + * \param port the port number + */ InetAddress (Ipv4Address ipv4, uint16_t port); + /** + * \param ipv4 the ipv4 address + * + * The port number is set to zero by default. + */ InetAddress (Ipv4Address ipv4); + /** + * \param port the port number + * + * The ipv4 address is set to the "Any" address by default. + */ InetAddress (uint16_t port); + /** + * \param ipv4 string which represents an ipv4 address + * \param port the port number + */ InetAddress (const char *ipv4, uint16_t port); + /** + * \param ipv4 string which represents an ipv4 address + * + * The port number is set to zero. + */ InetAddress (const char *ipv4); + /** + * \returns the port number + */ uint16_t GetPort (void) const; + /** + * \returns the ipv4 address + */ Ipv4Address GetIpv4 (void) const; - void SetPort (uint16_t post); + /** + * \param port the new port number. + */ + void SetPort (uint16_t port); + /** + * \param address the new ipv4 address + */ void SetIpv4 (Ipv4Address address); + /** + * \returns an Address instance which represents this + * InetAddress instance. + */ Address ConvertTo (void) const; + /** + * \param address the Address instance to convert from. + * \returns an InetAddress which corresponds to the input + * Address + */ static InetAddress ConvertFrom (const Address &address); private: static uint8_t GetType (void); From 0b1ddb45a20fb872b7e9299371b516d5ae5339a0 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 09:50:21 +0200 Subject: [PATCH 090/278] GetEventImpl -> PeekEventImpl --- src/simulator/event-id.cc | 2 +- src/simulator/event-id.h | 2 +- src/simulator/scheduler-heap.cc | 4 ++-- src/simulator/scheduler-list.cc | 4 ++-- src/simulator/scheduler-map.cc | 4 ++-- src/simulator/simulator.cc | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index 18f875935..b7b367ab5 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -55,7 +55,7 @@ EventId::IsRunning (void) return !IsExpired (); } EventImpl * -EventId::GetEventImpl (void) const +EventId::PeekEventImpl (void) const { return m_eventImpl; } diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index 4350c9bbe..bbe7e388a 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -51,7 +51,7 @@ public: * they are supposed to be invoked only by * subclasses of the Scheduler base class. */ - EventImpl *GetEventImpl (void) const; + EventImpl *PeekEventImpl (void) const; uint64_t GetTs (void) const; uint32_t GetUid (void) const; private: diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc index 0339dfed1..9bb08219e 100644 --- a/src/simulator/scheduler-heap.cc +++ b/src/simulator/scheduler-heap.cc @@ -225,7 +225,7 @@ SchedulerHeap::TopDown (uint32_t start) void SchedulerHeap::RealInsert (EventId id) { - EventImpl *event = id.GetEventImpl (); + EventImpl *event = id.PeekEventImpl (); Scheduler::EventKey key; key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); @@ -256,7 +256,7 @@ SchedulerHeap::RealRemove (EventId id) { if (uid == m_heap[i].second.m_uid) { - NS_ASSERT (m_heap[i].first == id.GetEventImpl ()); + NS_ASSERT (m_heap[i].first == id.PeekEventImpl ()); Exch (i, Last ()); m_heap.pop_back (); TopDown (i); diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc index ba3960458..2bf9a5de7 100644 --- a/src/simulator/scheduler-list.cc +++ b/src/simulator/scheduler-list.cc @@ -70,7 +70,7 @@ void SchedulerList::RealInsert (EventId id) { Scheduler::EventKey key; - EventImpl *event = id.GetEventImpl (); + EventImpl *event = id.PeekEventImpl (); key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); for (EventsI i = m_events.begin (); i != m_events.end (); i++) @@ -108,7 +108,7 @@ SchedulerList::RealRemove (EventId id) { if (i->second.m_uid == id.GetUid ()) { - NS_ASSERT (id.GetEventImpl () == i->first); + NS_ASSERT (id.PeekEventImpl () == i->first); m_events.erase (i); return true; } diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index 59be61ca7..addf18290 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -90,7 +90,7 @@ SchedulerMap::EventKeyCompare::operator () (struct EventKey const&a, struct Even void SchedulerMap::RealInsert (EventId id) { - EventImpl *event = id.GetEventImpl (); + EventImpl *event = id.PeekEventImpl (); Scheduler::EventKey key; key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); @@ -126,7 +126,7 @@ SchedulerMap::RealRemove (EventId id) key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); EventMapI i = m_list.find (key); - NS_ASSERT (i->second == id.GetEventImpl ()); + NS_ASSERT (i->second == id.PeekEventImpl ()); m_list.erase (i); return true; } diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index c133cb5a4..9204f6fdf 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -114,7 +114,7 @@ SimulatorPrivate::~SimulatorPrivate () { while (!m_destroyEvents.empty ()) { - EventImpl *ev = m_destroyEvents.front ().GetEventImpl (); + EventImpl *ev = m_destroyEvents.front ().PeekEventImpl (); m_destroyEvents.pop_front (); TRACE ("handle destroy " << ev); if (!ev->IsCancelled ()) @@ -151,7 +151,7 @@ SimulatorPrivate::ProcessOneEvent (void) { m_log << "e "<Invoke (); delete event; } @@ -275,7 +275,7 @@ SimulatorPrivate::Remove (EventId ev) return; } m_events->Remove (ev); - delete ev.GetEventImpl (); + delete ev.PeekEventImpl (); if (m_logEnable) { @@ -306,11 +306,11 @@ SimulatorPrivate::IsExpired (const EventId ev) } return true; } - if (ev.GetEventImpl () == 0 || + if (ev.PeekEventImpl () == 0 || ev.GetTs () < m_currentTs || (ev.GetTs () == m_currentTs && ev.GetUid () <= m_currentUid) || - ev.GetEventImpl ()->IsCancelled ()) + ev.PeekEventImpl ()->IsCancelled ()) { return true; } From c7906b2d6130240f810f9c491a119e3bc80ac0d1 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 09:53:15 +0200 Subject: [PATCH 091/278] add refcounting to EventImpl --- src/simulator/event-impl.cc | 18 +++++++++++++++++- src/simulator/event-impl.h | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/simulator/event-impl.cc b/src/simulator/event-impl.cc index fb6c7b1ad..e3e10bc53 100644 --- a/src/simulator/event-impl.cc +++ b/src/simulator/event-impl.cc @@ -29,8 +29,24 @@ EventImpl::~EventImpl () {} EventImpl::EventImpl () - : m_cancel (false) + : m_cancel (false), + m_count (1) {} +void +EventImpl::Ref (void) const +{ + m_count++; +} +void +EventImpl::Unref (void) const +{ + m_count--; + if (m_count == 0) + { + delete this; + } +} + void EventImpl::Invoke (void) { diff --git a/src/simulator/event-impl.h b/src/simulator/event-impl.h index fd7d54e2d..c6ff0f5eb 100644 --- a/src/simulator/event-impl.h +++ b/src/simulator/event-impl.h @@ -28,6 +28,8 @@ namespace ns3 { class EventImpl { public: EventImpl (); + void Ref (void) const; + void Unref (void) const; virtual ~EventImpl () = 0; void Invoke (void); void Cancel (void); @@ -37,6 +39,7 @@ protected: private: friend class Event; bool m_cancel; + mutable uint32_t m_count; }; }; // namespace ns3 From 9d5184bae4539b72f84efb2f200acf8d9163677b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 15:37:05 +0200 Subject: [PATCH 092/278] add an extra constructor to use when the Create template cannot be used --- src/core/ptr.cc | 15 +++++++++++++++ src/core/ptr.h | 21 ++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/core/ptr.cc b/src/core/ptr.cc index 10e63c606..cee3f59e2 100644 --- a/src/core/ptr.cc +++ b/src/core/ptr.cc @@ -28,9 +28,14 @@ namespace ns3 { +template +void Foo (void) {} + + class NoCount : public Object { public: + NoCount (void (*fn) (void)); NoCount (Callback cb); ~NoCount (); void Nothing (void) const; @@ -292,12 +297,22 @@ PtrTest::RunTests (void) callback (); } + #if 0 // as expected, fails compilation. { Ptr p = Create (cb); Callback callback = MakeCallback (&NoCount::Nothing, p); } + // local types are not allowed as arguments to a template. + { + class B + { + public: + B () {} + }; + Foo (); + } #endif diff --git a/src/core/ptr.h b/src/core/ptr.h index f5a52292e..5d3ce46a6 100644 --- a/src/core/ptr.h +++ b/src/core/ptr.h @@ -81,7 +81,16 @@ public: * same, so that object is deleted if no more references to it * remain. */ - Ptr (T *ptr); + Ptr (T *ptr); + /** + * \param ptr raw pointer to manage + * \param ref if set to true, this method calls Ref, otherwise, + * it does not call Ref. + * + * Create a smart pointer which points to the object pointed to by + * the input raw pointer ptr. + */ + Ptr (T *ptr, bool ref); Ptr (Ptr const&o); // allow conversions from T to T const. template @@ -378,6 +387,16 @@ Ptr::Ptr (T *ptr) Acquire (); } +template +Ptr::Ptr (T *ptr, bool ref) + : m_ptr (ptr) +{ + if (ref) + { + Acquire (); + } +} + template Ptr::Ptr (Ptr const&o) : m_ptr (PeekPointer (o)) From daa9c3c13c3fdf68a13c2cc7abc41721d7b62548 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 15:37:22 +0200 Subject: [PATCH 093/278] use a Ptr<> to manage EventImpl instances --- src/simulator/event-id.cc | 12 ++--- src/simulator/event-id.h | 8 ++-- src/simulator/scheduler-heap.cc | 11 ++++- src/simulator/scheduler-list.cc | 10 ++++- src/simulator/scheduler-map.cc | 10 ++++- src/simulator/scheduler.h | 2 - src/simulator/simulator.cc | 72 ++++++++++++++++++------------ src/simulator/simulator.h | 78 ++++++++++++++++----------------- 8 files changed, 118 insertions(+), 85 deletions(-) diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index b7b367ab5..f25902160 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -30,7 +30,7 @@ EventId::EventId () m_uid (0) {} -EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid) +EventId::EventId (Ptr impl, uint64_t ts, uint32_t uid) : m_eventImpl (impl), m_ts (ts), m_uid (uid) @@ -38,11 +38,7 @@ EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid) void EventId::Cancel (void) { - if (!IsExpired ()) - { - m_eventImpl->Cancel (); - m_eventImpl = 0; - } + Simulator::Cancel (*this); } bool EventId::IsExpired (void) @@ -54,8 +50,8 @@ EventId::IsRunning (void) { return !IsExpired (); } -EventImpl * -EventId::PeekEventImpl (void) const +Ptr +EventId::GetEventImpl (void) const { return m_eventImpl; } diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index bbe7e388a..3f28d367a 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -22,6 +22,8 @@ #define EVENT_ID_H #include +#include "ns3/ptr.h" +#include "event-impl.h" namespace ns3 { @@ -33,7 +35,7 @@ class EventImpl; class EventId { public: EventId (); - EventId (EventImpl *impl, uint64_t ts, uint32_t uid); + EventId (Ptr impl, uint64_t ts, uint32_t uid); /** * This method is syntactic sugar for the ns3::Simulator::cancel * method. @@ -51,12 +53,12 @@ public: * they are supposed to be invoked only by * subclasses of the Scheduler base class. */ - EventImpl *PeekEventImpl (void) const; + Ptr GetEventImpl (void) const; uint64_t GetTs (void) const; uint32_t GetUid (void) const; private: friend bool operator == (const EventId &a, const EventId &b); - EventImpl *m_eventImpl; + Ptr m_eventImpl; uint64_t m_ts; uint32_t m_uid; }; diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc index 9bb08219e..5251e3af9 100644 --- a/src/simulator/scheduler-heap.cc +++ b/src/simulator/scheduler-heap.cc @@ -225,7 +225,8 @@ SchedulerHeap::TopDown (uint32_t start) void SchedulerHeap::RealInsert (EventId id) { - EventImpl *event = id.PeekEventImpl (); + // acquire single ref + EventImpl *event = GetPointer (id.GetEventImpl ()); Scheduler::EventKey key; key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); @@ -242,6 +243,9 @@ SchedulerHeap::RealPeekNext (void) const void SchedulerHeap::RealRemoveNext (void) { + std::pair next = m_heap[Root ()]; + // release single ref + next.first->Unref (); Exch (Root (), Last ()); m_heap.pop_back (); TopDown (Root ()); @@ -256,7 +260,10 @@ SchedulerHeap::RealRemove (EventId id) { if (uid == m_heap[i].second.m_uid) { - NS_ASSERT (m_heap[i].first == id.PeekEventImpl ()); + NS_ASSERT (m_heap[i].first == id.GetEventImpl ()); + std::pair next = m_heap[i]; + // release single ref + next.first->Unref (); Exch (i, Last ()); m_heap.pop_back (); TopDown (i); diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc index 2bf9a5de7..f96c5e0cd 100644 --- a/src/simulator/scheduler-list.cc +++ b/src/simulator/scheduler-list.cc @@ -70,7 +70,8 @@ void SchedulerList::RealInsert (EventId id) { Scheduler::EventKey key; - EventImpl *event = id.PeekEventImpl (); + // acquire refcount on EventImpl + EventImpl *event = GetPointer (id.GetEventImpl ()); key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); for (EventsI i = m_events.begin (); i != m_events.end (); i++) @@ -98,6 +99,9 @@ SchedulerList::RealPeekNext (void) const void SchedulerList::RealRemoveNext (void) { + std::pair next = m_events.front (); + // release single acquired ref. + next.first->Unref (); m_events.pop_front (); } @@ -108,7 +112,9 @@ SchedulerList::RealRemove (EventId id) { if (i->second.m_uid == id.GetUid ()) { - NS_ASSERT (id.PeekEventImpl () == i->first); + NS_ASSERT (id.GetEventImpl () == i->first); + // release single acquire ref. + i->first->Unref (); m_events.erase (i); return true; } diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index addf18290..29f68dee4 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -90,7 +90,8 @@ SchedulerMap::EventKeyCompare::operator () (struct EventKey const&a, struct Even void SchedulerMap::RealInsert (EventId id) { - EventImpl *event = id.PeekEventImpl (); + // acquire a single ref + EventImpl *event = GetPointer (id.GetEventImpl ()); Scheduler::EventKey key; key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); @@ -116,6 +117,9 @@ SchedulerMap::RealPeekNext (void) const void SchedulerMap::RealRemoveNext (void) { + EventMapCI i = m_list.begin (); + // release single ref. + i->second->Unref (); m_list.erase (m_list.begin ()); } @@ -126,7 +130,9 @@ SchedulerMap::RealRemove (EventId id) key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); EventMapI i = m_list.find (key); - NS_ASSERT (i->second == id.PeekEventImpl ()); + NS_ASSERT (i->second == id.GetEventImpl ()); + // release single ref. + i->second->Unref (); m_list.erase (i); return true; } diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index 0df7a77df..194beead2 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -27,8 +27,6 @@ namespace ns3 { -class EventImpl; - /** * \brief Maintain the event list * diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 9204f6fdf..5b825fae5 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -23,6 +23,7 @@ #include "scheduler.h" #include "event-impl.h" +#include "ns3/ptr.h" #include "ns3/assert.h" #include "ns3/default-value.h" @@ -61,9 +62,9 @@ public: Time Next (void) const; void Stop (void); void StopAt (Time const &time); - EventId Schedule (Time const &time, EventImpl *event); - EventId ScheduleNow (EventImpl *event); - EventId ScheduleDestroy (EventImpl *event); + EventId Schedule (Time const &time, Ptr event); + EventId ScheduleNow (Ptr event); + EventId ScheduleDestroy (Ptr event); void Remove (EventId ev); void Cancel (EventId &ev); bool IsExpired (EventId ev); @@ -114,13 +115,12 @@ SimulatorPrivate::~SimulatorPrivate () { while (!m_destroyEvents.empty ()) { - EventImpl *ev = m_destroyEvents.front ().PeekEventImpl (); + Ptr ev = m_destroyEvents.front ().GetEventImpl (); m_destroyEvents.pop_front (); TRACE ("handle destroy " << ev); if (!ev->IsCancelled ()) { ev->Invoke (); - delete ev; } } delete m_events; @@ -151,9 +151,8 @@ SimulatorPrivate::ProcessOneEvent (void) { m_log << "e "< event = next.GetEventImpl (); event->Invoke (); - delete event; } bool @@ -204,7 +203,7 @@ SimulatorPrivate::StopAt (Time const &at) m_stopAt = at.GetTimeStep (); } EventId -SimulatorPrivate::Schedule (Time const &time, EventImpl *event) +SimulatorPrivate::Schedule (Time const &time, Ptr event) { NS_ASSERT (time.IsPositive ()); NS_ASSERT (time >= TimeStep (m_currentTs)); @@ -221,7 +220,7 @@ SimulatorPrivate::Schedule (Time const &time, EventImpl *event) return id; } EventId -SimulatorPrivate::ScheduleNow (EventImpl *event) +SimulatorPrivate::ScheduleNow (Ptr event) { EventId id (event, m_currentTs, m_uid); if (m_logEnable) @@ -235,7 +234,7 @@ SimulatorPrivate::ScheduleNow (EventImpl *event) return id; } EventId -SimulatorPrivate::ScheduleDestroy (EventImpl *event) +SimulatorPrivate::ScheduleDestroy (Ptr event) { EventId id (event, m_currentTs, 2); m_destroyEvents.push_back (id); @@ -275,7 +274,7 @@ SimulatorPrivate::Remove (EventId ev) return; } m_events->Remove (ev); - delete ev.PeekEventImpl (); + Cancel (ev); if (m_logEnable) { @@ -288,7 +287,10 @@ SimulatorPrivate::Remove (EventId ev) void SimulatorPrivate::Cancel (EventId &id) { - id.Cancel (); + if (!IsExpired (id)) + { + id.GetEventImpl ()->Cancel (); + } } bool @@ -306,11 +308,11 @@ SimulatorPrivate::IsExpired (const EventId ev) } return true; } - if (ev.PeekEventImpl () == 0 || + if (ev.GetEventImpl () == 0 || ev.GetTs () < m_currentTs || (ev.GetTs () == m_currentTs && ev.GetUid () <= m_currentUid) || - ev.PeekEventImpl ()->IsCancelled ()) + ev.GetEventImpl ()->IsCancelled ()) { return true; } @@ -411,39 +413,39 @@ Simulator::Now (void) return GetPriv ()->Now (); } -EventImpl * +Ptr Simulator::MakeEvent (void (*f) (void)) { // zero arg version class EventFunctionImpl0 : public EventImpl { public: - typedef void (*F)(void); + typedef void (*F)(void); - EventFunctionImpl0 (F function) - : m_function (function) - {} - virtual ~EventFunctionImpl0 () {} + EventFunctionImpl0 (F function) + : m_function (function) + {} + virtual ~EventFunctionImpl0 () {} protected: - virtual void Notify (void) { - (*m_function) (); - } + virtual void Notify (void) { + (*m_function) (); + } private: F m_function; } *ev = new EventFunctionImpl0 (f); - return ev; + return Ptr (ev, false); } EventId -Simulator::Schedule (Time const &time, EventImpl *ev) +Simulator::Schedule (Time const &time, Ptr ev) { return GetPriv ()->Schedule (Now () + time, ev); } EventId -Simulator::ScheduleNow (EventImpl *ev) +Simulator::ScheduleNow (Ptr ev) { return GetPriv ()->ScheduleNow (ev); } EventId -Simulator::ScheduleDestroy (EventImpl *ev) +Simulator::ScheduleDestroy (Ptr ev) { return GetPriv ()->ScheduleDestroy (ev); } @@ -884,6 +886,22 @@ SimulatorTests::RunTests (void) ok = false; } + EventId anId = Simulator::ScheduleNow (&foo0); + EventId anotherId = anId; + if (anId.IsExpired () || anotherId.IsExpired ()) + { + ok = false; + } + Simulator::Remove (anId); + if (!anId.IsExpired () || !anotherId.IsExpired ()) + { + ok = false; + } + + Simulator::Run (); + Simulator::Destroy (); + + return ok; } diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index a7eea7600..b12ba0763 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -570,49 +570,49 @@ private: ~Simulator (); template - static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj); + static Ptr MakeEvent (void (T::*mem_ptr) (void), OBJ obj); template - static EventImpl *MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1); + static Ptr MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1); template - static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2); + static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2); template - static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3); + static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3); template - static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); + static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); template - static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, + static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); - static EventImpl *MakeEvent (void (*f) (void)); + static Ptr MakeEvent (void (*f) (void)); template - static EventImpl *MakeEvent (void (*f) (U1), T1 a1); + static Ptr MakeEvent (void (*f) (U1), T1 a1); template - static EventImpl *MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2); + static Ptr MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2); template - static EventImpl *MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); + static Ptr MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3); template - static EventImpl *MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); + static Ptr MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4); template - static EventImpl *MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + static Ptr MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); static SimulatorPrivate *GetPriv (void); - static EventId Schedule (Time const &time, EventImpl *event); - static EventId ScheduleDestroy (EventImpl *event); - static EventId ScheduleNow (EventImpl *event); + static EventId Schedule (Time const &time, Ptr event); + static EventId ScheduleDestroy (Ptr event); + static EventId ScheduleNow (Ptr event); static SimulatorPrivate *m_priv; }; @@ -650,7 +650,7 @@ struct EventMemberImplObjTraits }; template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) +Ptr Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) { // zero argument version class EventMemberImpl0 : public EventImpl { @@ -667,15 +667,15 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) } OBJ m_obj; F m_function; - } *ev = new EventMemberImpl0 (obj, mem_ptr); - return ev; + } * ev = new EventMemberImpl0 (obj, mem_ptr); + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) +Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) { // one argument version class EventMemberImpl1 : public EventImpl { @@ -696,13 +696,13 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) F m_function; typename TypeTraits::ReferencedType m_a1; } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) +Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) { // two argument version class EventMemberImpl2 : public EventImpl { @@ -726,13 +726,13 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 typename TypeTraits::ReferencedType m_a1; typename TypeTraits::ReferencedType m_a2; } *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) +Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) { // three argument version class EventMemberImpl3 : public EventImpl { @@ -758,13 +758,13 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, typename TypeTraits::ReferencedType m_a2; typename TypeTraits::ReferencedType m_a3; } *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) +Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) { // four argument version class EventMemberImpl4 : public EventImpl { @@ -792,13 +792,13 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a typename TypeTraits::ReferencedType m_a3; typename TypeTraits::ReferencedType m_a4; } *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, +Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { // five argument version @@ -829,11 +829,11 @@ EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, typename TypeTraits::ReferencedType m_a4; typename TypeTraits::ReferencedType m_a5; } *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (*f) (U1), T1 a1) +Ptr Simulator::MakeEvent (void (*f) (U1), T1 a1) { // one arg version class EventFunctionImpl1 : public EventImpl { @@ -852,12 +852,12 @@ EventImpl *Simulator::MakeEvent (void (*f) (U1), T1 a1) } F m_function; typename TypeTraits::ReferencedType m_a1; - } *ev = new EventFunctionImpl1(f, a1); - return ev; + } *ev = new EventFunctionImpl1 (f, a1); + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) +Ptr Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) { // two arg version class EventFunctionImpl2 : public EventImpl { @@ -879,12 +879,12 @@ EventImpl *Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) typename TypeTraits::ReferencedType m_a1; typename TypeTraits::ReferencedType m_a2; } *ev = new EventFunctionImpl2 (f, a1, a2); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3) +Ptr Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3) { // three arg version class EventFunctionImpl3 : public EventImpl { @@ -908,12 +908,12 @@ EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3) typename TypeTraits::ReferencedType m_a2; typename TypeTraits::ReferencedType m_a3; } *ev = new EventFunctionImpl3 (f, a1, a2, a3); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) +Ptr Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) { // four arg version class EventFunctionImpl4 : public EventImpl { @@ -939,12 +939,12 @@ EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T typename TypeTraits::ReferencedType m_a3; typename TypeTraits::ReferencedType m_a4; } *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4); - return ev; + return Ptr (ev, false); } template -EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) +Ptr Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { // five arg version class EventFunctionImpl5 : public EventImpl { @@ -972,7 +972,7 @@ EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3 typename TypeTraits::ReferencedType m_a4; typename TypeTraits::ReferencedType m_a5; } *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5); - return ev; + return Ptr (ev, false); } template From 21be3e3912657e8b830d042d96b55509ee7472e9 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 17:18:14 +0200 Subject: [PATCH 094/278] optimize EventImpl refcounting --- src/simulator/event-id.cc | 5 +++++ src/simulator/event-id.h | 1 + src/simulator/event-impl.cc | 15 --------------- src/simulator/event-impl.h | 23 +++++++++++++++++++++-- src/simulator/scheduler-heap.cc | 15 +++++++-------- src/simulator/scheduler-heap.h | 12 ++++++------ src/simulator/scheduler-list.cc | 15 +++++++-------- src/simulator/scheduler-list.h | 12 ++++++------ src/simulator/scheduler-map.cc | 15 +++++++-------- src/simulator/scheduler-map.h | 10 +++++----- src/simulator/scheduler.cc | 29 ----------------------------- src/simulator/scheduler.h | 30 +++++++++++------------------- src/simulator/simulator.cc | 5 ++--- 13 files changed, 78 insertions(+), 109 deletions(-) diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index f25902160..43491505d 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -55,6 +55,11 @@ EventId::GetEventImpl (void) const { return m_eventImpl; } +EventImpl * +EventId::PeekEventImpl (void) const +{ + return PeekPointer (m_eventImpl); +} uint64_t EventId::GetTs (void) const { diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index 3f28d367a..9432a5d4b 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -54,6 +54,7 @@ public: * subclasses of the Scheduler base class. */ Ptr GetEventImpl (void) const; + EventImpl *PeekEventImpl (void) const; uint64_t GetTs (void) const; uint32_t GetUid (void) const; private: diff --git a/src/simulator/event-impl.cc b/src/simulator/event-impl.cc index e3e10bc53..9c89bb52f 100644 --- a/src/simulator/event-impl.cc +++ b/src/simulator/event-impl.cc @@ -32,21 +32,6 @@ EventImpl::EventImpl () : m_cancel (false), m_count (1) {} -void -EventImpl::Ref (void) const -{ - m_count++; -} -void -EventImpl::Unref (void) const -{ - m_count--; - if (m_count == 0) - { - delete this; - } -} - void EventImpl::Invoke (void) { diff --git a/src/simulator/event-impl.h b/src/simulator/event-impl.h index c6ff0f5eb..51ac1e7a1 100644 --- a/src/simulator/event-impl.h +++ b/src/simulator/event-impl.h @@ -28,8 +28,8 @@ namespace ns3 { class EventImpl { public: EventImpl (); - void Ref (void) const; - void Unref (void) const; + inline void Ref (void) const; + inline void Unref (void) const; virtual ~EventImpl () = 0; void Invoke (void); void Cancel (void); @@ -44,4 +44,23 @@ private: }; // namespace ns3 +namespace ns3 { + +void +EventImpl::Ref (void) const +{ + m_count++; +} +void +EventImpl::Unref (void) const +{ + m_count--; + if (m_count == 0) + { + delete this; + } +} + +} // namespace ns3 + #endif /* EVENT_IMPL_H */ diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc index 5251e3af9..fb62e248a 100644 --- a/src/simulator/scheduler-heap.cc +++ b/src/simulator/scheduler-heap.cc @@ -170,7 +170,7 @@ SchedulerHeap::Smallest (uint32_t a, uint32_t b) const } bool -SchedulerHeap::RealIsEmpty (void) const +SchedulerHeap::IsEmpty (void) const { return (m_heap.size () == 1)?true:false; } @@ -223,7 +223,7 @@ SchedulerHeap::TopDown (uint32_t start) void -SchedulerHeap::RealInsert (EventId id) +SchedulerHeap::Insert (const EventId &id) { // acquire single ref EventImpl *event = GetPointer (id.GetEventImpl ()); @@ -235,25 +235,24 @@ SchedulerHeap::RealInsert (EventId id) } EventId -SchedulerHeap::RealPeekNext (void) const +SchedulerHeap::PeekNext (void) const { std::pair next = m_heap[Root ()]; return EventId (next.first, next.second.m_ts, next.second.m_uid); } -void -SchedulerHeap::RealRemoveNext (void) +EventId +SchedulerHeap::RemoveNext (void) { std::pair next = m_heap[Root ()]; - // release single ref - next.first->Unref (); Exch (Root (), Last ()); m_heap.pop_back (); TopDown (Root ()); + return EventId (Ptr (next.first, false), next.second.m_ts, next.second.m_uid); } bool -SchedulerHeap::RealRemove (EventId id) +SchedulerHeap::Remove (const EventId &id) { uint32_t uid = id.GetUid (); for (uint32_t i = 1; i < m_heap.size (); i++) diff --git a/src/simulator/scheduler-heap.h b/src/simulator/scheduler-heap.h index c57fe1368..fbc6e1ca1 100644 --- a/src/simulator/scheduler-heap.h +++ b/src/simulator/scheduler-heap.h @@ -35,13 +35,13 @@ public: SchedulerHeap (); virtual ~SchedulerHeap (); -private: - virtual void RealInsert (EventId id); - virtual bool RealIsEmpty (void) const; - virtual EventId RealPeekNext (void) const; - virtual void RealRemoveNext (void); - virtual bool RealRemove (EventId ev); + virtual void Insert (const EventId &id); + virtual bool IsEmpty (void) const; + virtual EventId PeekNext (void) const; + virtual EventId RemoveNext (void); + virtual bool Remove (const EventId &ev); +private: typedef std::vector > BinaryHeap; inline uint32_t Parent (uint32_t id) const; diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc index f96c5e0cd..4c85713c7 100644 --- a/src/simulator/scheduler-list.cc +++ b/src/simulator/scheduler-list.cc @@ -67,7 +67,7 @@ SchedulerList::IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b } void -SchedulerList::RealInsert (EventId id) +SchedulerList::Insert (const EventId &id) { Scheduler::EventKey key; // acquire refcount on EventImpl @@ -85,28 +85,27 @@ SchedulerList::RealInsert (EventId id) m_events.push_back (std::make_pair (event, key)); } bool -SchedulerList::RealIsEmpty (void) const +SchedulerList::IsEmpty (void) const { return m_events.empty (); } EventId -SchedulerList::RealPeekNext (void) const +SchedulerList::PeekNext (void) const { std::pair next = m_events.front (); return EventId (next.first, next.second.m_ts, next.second.m_uid); } -void -SchedulerList::RealRemoveNext (void) +EventId +SchedulerList::RemoveNext (void) { std::pair next = m_events.front (); - // release single acquired ref. - next.first->Unref (); m_events.pop_front (); + return EventId (Ptr (next.first,false), next.second.m_ts, next.second.m_uid); } bool -SchedulerList::RealRemove (EventId id) +SchedulerList::Remove (const EventId &id) { for (EventsI i = m_events.begin (); i != m_events.end (); i++) { diff --git a/src/simulator/scheduler-list.h b/src/simulator/scheduler-list.h index cbce5e68f..306d19270 100644 --- a/src/simulator/scheduler-list.h +++ b/src/simulator/scheduler-list.h @@ -37,13 +37,13 @@ class SchedulerList : public Scheduler { SchedulerList (); virtual ~SchedulerList (); - private: - virtual void RealInsert (EventId id); - virtual bool RealIsEmpty (void) const; - virtual EventId RealPeekNext (void) const; - virtual void RealRemoveNext (void); - virtual bool RealRemove (EventId ev); + virtual void Insert (const EventId &id); + virtual bool IsEmpty (void) const; + virtual EventId PeekNext (void) const; + virtual EventId RemoveNext (void); + virtual bool Remove (const EventId &ev); + private: inline bool IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const; typedef std::list > Events; diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index 29f68dee4..5e002a4a7 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -88,7 +88,7 @@ SchedulerMap::EventKeyCompare::operator () (struct EventKey const&a, struct Even void -SchedulerMap::RealInsert (EventId id) +SchedulerMap::Insert (const EventId &id) { // acquire a single ref EventImpl *event = GetPointer (id.GetEventImpl ()); @@ -101,30 +101,29 @@ SchedulerMap::RealInsert (EventId id) } bool -SchedulerMap::RealIsEmpty (void) const +SchedulerMap::IsEmpty (void) const { return m_list.empty (); } EventId -SchedulerMap::RealPeekNext (void) const +SchedulerMap::PeekNext (void) const { EventMapCI i = m_list.begin (); NS_ASSERT (i != m_list.end ()); return EventId (i->second, i->first.m_ts, i->first.m_uid); } -void -SchedulerMap::RealRemoveNext (void) +EventId +SchedulerMap::RemoveNext (void) { EventMapCI i = m_list.begin (); - // release single ref. - i->second->Unref (); m_list.erase (m_list.begin ()); + return EventId (Ptr (i->second, false), i->first.m_ts, i->first.m_uid); } bool -SchedulerMap::RealRemove (EventId id) +SchedulerMap::Remove (const EventId &id) { Scheduler::EventKey key; key.m_ts = id.GetTs (); diff --git a/src/simulator/scheduler-map.h b/src/simulator/scheduler-map.h index b8fb2cfa5..dbbc7fdbd 100644 --- a/src/simulator/scheduler-map.h +++ b/src/simulator/scheduler-map.h @@ -36,12 +36,12 @@ public: SchedulerMap (); virtual ~SchedulerMap (); + virtual void Insert (const EventId &id); + virtual bool IsEmpty (void) const; + virtual EventId PeekNext (void) const; + virtual EventId RemoveNext (void); + virtual bool Remove (const EventId &ev); private: - virtual void RealInsert (EventId id); - virtual bool RealIsEmpty (void) const; - virtual EventId RealPeekNext (void) const; - virtual void RealRemoveNext (void); - virtual bool RealRemove (EventId ev); class EventKeyCompare { public: diff --git a/src/simulator/scheduler.cc b/src/simulator/scheduler.cc index f8190bb39..4ba1d01b6 100644 --- a/src/simulator/scheduler.cc +++ b/src/simulator/scheduler.cc @@ -27,33 +27,4 @@ namespace ns3 { Scheduler::~Scheduler () {} -void -Scheduler::Insert (EventId id) -{ - return RealInsert (id); -} -bool -Scheduler::IsEmpty (void) const -{ - return RealIsEmpty (); -} -EventId -Scheduler::PeekNext (void) const -{ - NS_ASSERT (!RealIsEmpty ()); - return RealPeekNext (); -} -void -Scheduler::RemoveNext (void) -{ - NS_ASSERT (!RealIsEmpty ()); - return RealRemoveNext (); -} -bool -Scheduler::Remove (EventId id) -{ - NS_ASSERT (!RealIsEmpty ()); - return RealRemove (id); -} - }; // namespace ns3 diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index 194beead2..33917a870 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -33,13 +33,12 @@ namespace ns3 { * This base class specifies the interface used to maintain the * event list. If you want to provide a new event list scheduler, * you need to create a subclass of this base class and implement - * all the private pure virtual methods defined here. Namely: - * - ns3::Scheduler::realInsert - * - ns3::Scheduler::realIsEmpty - * - ns3::Scheduler::realPeekNext - * - ns3::Scheduler::realPeekNextKey - * - ns3::Scheduler::realRemoveNext - * - ns3::Scheduler::realRemove + * all the pure virtual methods defined here. Namely: + * - ns3::Scheduler::Insert + * - ns3::Scheduler::IsEmpty + * - ns3::Scheduler::PeekNext + * - ns3::Scheduler::RemoveNext + * - ns3::Scheduler::Remove * * If you need to provide a new event list scheduler without * editing the main simulator class, you need to also implement @@ -58,13 +57,6 @@ class Scheduler { virtual ~Scheduler () = 0; - void Insert (EventId id); - bool IsEmpty (void) const; - EventId PeekNext (void) const; - void RemoveNext (void); - bool Remove (EventId); - -private: /** * \param event event to store in the event list * \param key timecode associated to this new event @@ -72,23 +64,23 @@ private: * * This method takes ownership of the event pointer. */ - virtual void RealInsert (EventId id) = 0; + virtual void Insert (const EventId &id) = 0; /** * \returns true if the event list is empty and false otherwise. */ - virtual bool RealIsEmpty (void) const = 0; + virtual bool IsEmpty (void) const = 0; /** * \returns a pointer to the next earliest event. The caller * takes ownership of the returned pointer. * * This method cannot be invoked if the list is empty. */ - virtual EventId RealPeekNext (void) const = 0; + virtual EventId PeekNext (void) const = 0; /** * This method cannot be invoked if the list is empty. * Remove the next earliest event from the event list. */ - virtual void RealRemoveNext (void) = 0; + virtual EventId RemoveNext (void) = 0; /** * \param id the id of the event to remove * \param key the timecode of the event removed @@ -97,7 +89,7 @@ private: * * This methods cannot be invoked if the list is empty. */ - virtual bool RealRemove (EventId id) = 0; + virtual bool Remove (const EventId &id) = 0; }; }; // namespace ns3 diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 5b825fae5..83e8b1d45 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -138,8 +138,7 @@ SimulatorPrivate::EnableLogTo (char const *filename) void SimulatorPrivate::ProcessOneEvent (void) { - EventId next = m_events->PeekNext (); - m_events->RemoveNext (); + EventId next = m_events->RemoveNext (); NS_ASSERT (next.GetTs () >= m_currentTs); --m_unscheduledEvents; @@ -151,7 +150,7 @@ SimulatorPrivate::ProcessOneEvent (void) { m_log << "e "< event = next.GetEventImpl (); + EventImpl *event = next.PeekEventImpl (); event->Invoke (); } From dcf642ffb0e9511fca0b3439075212b52399f1f5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 17:28:17 +0200 Subject: [PATCH 095/278] more optimizations --- src/simulator/event-id.cc | 2 +- src/simulator/event-id.h | 2 +- src/simulator/simulator.cc | 18 +++++++++--------- src/simulator/simulator.h | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index 43491505d..fa6ee84fa 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -30,7 +30,7 @@ EventId::EventId () m_uid (0) {} -EventId::EventId (Ptr impl, uint64_t ts, uint32_t uid) +EventId::EventId (const Ptr &impl, uint64_t ts, uint32_t uid) : m_eventImpl (impl), m_ts (ts), m_uid (uid) diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index 9432a5d4b..14023c4c9 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -35,7 +35,7 @@ class EventImpl; class EventId { public: EventId (); - EventId (Ptr impl, uint64_t ts, uint32_t uid); + EventId (const Ptr &impl, uint64_t ts, uint32_t uid); /** * This method is syntactic sugar for the ns3::Simulator::cancel * method. diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 83e8b1d45..2e2e39347 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -62,9 +62,9 @@ public: Time Next (void) const; void Stop (void); void StopAt (Time const &time); - EventId Schedule (Time const &time, Ptr event); - EventId ScheduleNow (Ptr event); - EventId ScheduleDestroy (Ptr event); + EventId Schedule (Time const &time, const Ptr &event); + EventId ScheduleNow (const Ptr &event); + EventId ScheduleDestroy (const Ptr &event); void Remove (EventId ev); void Cancel (EventId &ev); bool IsExpired (EventId ev); @@ -202,7 +202,7 @@ SimulatorPrivate::StopAt (Time const &at) m_stopAt = at.GetTimeStep (); } EventId -SimulatorPrivate::Schedule (Time const &time, Ptr event) +SimulatorPrivate::Schedule (Time const &time, const Ptr &event) { NS_ASSERT (time.IsPositive ()); NS_ASSERT (time >= TimeStep (m_currentTs)); @@ -219,7 +219,7 @@ SimulatorPrivate::Schedule (Time const &time, Ptr event) return id; } EventId -SimulatorPrivate::ScheduleNow (Ptr event) +SimulatorPrivate::ScheduleNow (const Ptr &event) { EventId id (event, m_currentTs, m_uid); if (m_logEnable) @@ -233,7 +233,7 @@ SimulatorPrivate::ScheduleNow (Ptr event) return id; } EventId -SimulatorPrivate::ScheduleDestroy (Ptr event) +SimulatorPrivate::ScheduleDestroy (const Ptr &event) { EventId id (event, m_currentTs, 2); m_destroyEvents.push_back (id); @@ -434,17 +434,17 @@ Simulator::MakeEvent (void (*f) (void)) return Ptr (ev, false); } EventId -Simulator::Schedule (Time const &time, Ptr ev) +Simulator::Schedule (Time const &time, const Ptr &ev) { return GetPriv ()->Schedule (Now () + time, ev); } EventId -Simulator::ScheduleNow (Ptr ev) +Simulator::ScheduleNow (const Ptr &ev) { return GetPriv ()->ScheduleNow (ev); } EventId -Simulator::ScheduleDestroy (Ptr ev) +Simulator::ScheduleDestroy (const Ptr &ev) { return GetPriv ()->ScheduleDestroy (ev); } diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index b12ba0763..ecd0550bd 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -610,9 +610,9 @@ private: static Ptr MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); static SimulatorPrivate *GetPriv (void); - static EventId Schedule (Time const &time, Ptr event); - static EventId ScheduleDestroy (Ptr event); - static EventId ScheduleNow (Ptr event); + static EventId Schedule (Time const &time, const Ptr &event); + static EventId ScheduleDestroy (const Ptr &event); + static EventId ScheduleNow (const Ptr &event); static SimulatorPrivate *m_priv; }; From 0b1819cdc8762ee133f833d3605479979a5a6d12 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 17:36:14 +0200 Subject: [PATCH 096/278] be more consistant in the handling of references --- src/simulator/simulator.cc | 18 +++++++++--------- src/simulator/simulator.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 2e2e39347..39afc093c 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -65,9 +65,9 @@ public: EventId Schedule (Time const &time, const Ptr &event); EventId ScheduleNow (const Ptr &event); EventId ScheduleDestroy (const Ptr &event); - void Remove (EventId ev); - void Cancel (EventId &ev); - bool IsExpired (EventId ev); + void Remove (const EventId &ev); + void Cancel (const EventId &ev); + bool IsExpired (const EventId &ev); void Run (void); Time Now (void) const; @@ -253,7 +253,7 @@ SimulatorPrivate::Now (void) const } void -SimulatorPrivate::Remove (EventId ev) +SimulatorPrivate::Remove (const EventId &ev) { if (ev.GetUid () == 2) { @@ -284,7 +284,7 @@ SimulatorPrivate::Remove (EventId ev) } void -SimulatorPrivate::Cancel (EventId &id) +SimulatorPrivate::Cancel (const EventId &id) { if (!IsExpired (id)) { @@ -293,7 +293,7 @@ SimulatorPrivate::Cancel (EventId &id) } bool -SimulatorPrivate::IsExpired (const EventId ev) +SimulatorPrivate::IsExpired (const EventId &ev) { if (ev.GetUid () == 2) { @@ -466,18 +466,18 @@ Simulator::ScheduleDestroy (void (*f) (void)) void -Simulator::Remove (EventId ev) +Simulator::Remove (const EventId &ev) { return GetPriv ()->Remove (ev); } void -Simulator::Cancel (EventId &ev) +Simulator::Cancel (const EventId &ev) { return GetPriv ()->Cancel (ev); } bool -Simulator::IsExpired (EventId id) +Simulator::IsExpired (const EventId &id) { return GetPriv ()->IsExpired (id); } diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index ecd0550bd..9c9cd201e 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -534,7 +534,7 @@ public: * * @param id the event to remove from the list of scheduled events. */ - static void Remove (EventId id); + static void Remove (const EventId &id); /** * Set the cancel bit on this event: the event's associated function * will not be invoked when it expires. @@ -547,7 +547,7 @@ public: * * @param id the event to cancel */ - static void Cancel (EventId &id); + static void Cancel (const EventId &id); /** * This method has O(1) complexity. * Note that it is not possible to test for the expiration of @@ -560,7 +560,7 @@ public: * @param id the event to test for expiration * @returns true if the event has expired, false otherwise. */ - static bool IsExpired (const EventId id); + static bool IsExpired (const EventId &id); /** * Return the "current simulation time". */ From c3e1f137e1f8fe47658d82760bdf30f94225f3e7 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 17:44:15 +0200 Subject: [PATCH 097/278] remove GetEventImpl --- src/simulator/event-id.cc | 5 ----- src/simulator/event-id.h | 1 - src/simulator/scheduler-heap.cc | 5 +++-- src/simulator/scheduler-list.cc | 5 +++-- src/simulator/scheduler-map.cc | 5 +++-- src/simulator/simulator.cc | 8 ++++---- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index fa6ee84fa..548634b59 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -50,11 +50,6 @@ EventId::IsRunning (void) { return !IsExpired (); } -Ptr -EventId::GetEventImpl (void) const -{ - return m_eventImpl; -} EventImpl * EventId::PeekEventImpl (void) const { diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index 14023c4c9..e080499fd 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -53,7 +53,6 @@ public: * they are supposed to be invoked only by * subclasses of the Scheduler base class. */ - Ptr GetEventImpl (void) const; EventImpl *PeekEventImpl (void) const; uint64_t GetTs (void) const; uint32_t GetUid (void) const; diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc index fb62e248a..f924c70f4 100644 --- a/src/simulator/scheduler-heap.cc +++ b/src/simulator/scheduler-heap.cc @@ -226,7 +226,8 @@ void SchedulerHeap::Insert (const EventId &id) { // acquire single ref - EventImpl *event = GetPointer (id.GetEventImpl ()); + EventImpl *event = id.PeekEventImpl (); + event->Ref (); Scheduler::EventKey key; key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); @@ -259,7 +260,7 @@ SchedulerHeap::Remove (const EventId &id) { if (uid == m_heap[i].second.m_uid) { - NS_ASSERT (m_heap[i].first == id.GetEventImpl ()); + NS_ASSERT (m_heap[i].first == id.PeekEventImpl ()); std::pair next = m_heap[i]; // release single ref next.first->Unref (); diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc index 4c85713c7..c3de7891a 100644 --- a/src/simulator/scheduler-list.cc +++ b/src/simulator/scheduler-list.cc @@ -71,7 +71,8 @@ SchedulerList::Insert (const EventId &id) { Scheduler::EventKey key; // acquire refcount on EventImpl - EventImpl *event = GetPointer (id.GetEventImpl ()); + EventImpl *event = id.PeekEventImpl (); + event->Ref (); key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); for (EventsI i = m_events.begin (); i != m_events.end (); i++) @@ -111,7 +112,7 @@ SchedulerList::Remove (const EventId &id) { if (i->second.m_uid == id.GetUid ()) { - NS_ASSERT (id.GetEventImpl () == i->first); + NS_ASSERT (id.PeekEventImpl () == i->first); // release single acquire ref. i->first->Unref (); m_events.erase (i); diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index 5e002a4a7..f413ed830 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -91,7 +91,8 @@ void SchedulerMap::Insert (const EventId &id) { // acquire a single ref - EventImpl *event = GetPointer (id.GetEventImpl ()); + EventImpl *event = id.PeekEventImpl (); + event->Ref (); Scheduler::EventKey key; key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); @@ -129,7 +130,7 @@ SchedulerMap::Remove (const EventId &id) key.m_ts = id.GetTs (); key.m_uid = id.GetUid (); EventMapI i = m_list.find (key); - NS_ASSERT (i->second == id.GetEventImpl ()); + NS_ASSERT (i->second == id.PeekEventImpl ()); // release single ref. i->second->Unref (); m_list.erase (i); diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 39afc093c..8190aeb79 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -115,7 +115,7 @@ SimulatorPrivate::~SimulatorPrivate () { while (!m_destroyEvents.empty ()) { - Ptr ev = m_destroyEvents.front ().GetEventImpl (); + Ptr ev = m_destroyEvents.front ().PeekEventImpl (); m_destroyEvents.pop_front (); TRACE ("handle destroy " << ev); if (!ev->IsCancelled ()) @@ -288,7 +288,7 @@ SimulatorPrivate::Cancel (const EventId &id) { if (!IsExpired (id)) { - id.GetEventImpl ()->Cancel (); + id.PeekEventImpl ()->Cancel (); } } @@ -307,11 +307,11 @@ SimulatorPrivate::IsExpired (const EventId &ev) } return true; } - if (ev.GetEventImpl () == 0 || + if (ev.PeekEventImpl () == 0 || ev.GetTs () < m_currentTs || (ev.GetTs () == m_currentTs && ev.GetUid () <= m_currentUid) || - ev.GetEventImpl ()->IsCancelled ()) + ev.PeekEventImpl ()->IsCancelled ()) { return true; } From 64a8418674337d1fa889ebbe226806186cf00731 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 27 Jul 2007 17:49:04 +0200 Subject: [PATCH 098/278] optmize slightly Ptr::Acquire --- src/core/ptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ptr.h b/src/core/ptr.h index 5d3ce46a6..f2436dd63 100644 --- a/src/core/ptr.h +++ b/src/core/ptr.h @@ -65,7 +65,7 @@ private: template friend U *PeekPointer (const Ptr &p); - void Acquire (void) const; + inline void Acquire (void) const; public: /** * Create an empty smart pointer From d38da7ae3d0a6085650ef206eb1df11967cf6abe Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 27 Jul 2007 14:04:54 -0700 Subject: [PATCH 099/278] rename party --- examples/wscript | 7 +- src/internet-node/internet-node.cc | 8 +- src/routing/{ => global}/candidate-queue.cc | 0 src/routing/{ => global}/candidate-queue.h | 2 +- .../global-route-manager-impl.cc} | 312 +++++++++--------- .../global-route-manager-impl.h} | 174 +++++----- .../global-route-manager.cc} | 20 +- .../global-route-manager.h} | 32 +- .../global-router-interface.cc} | 206 ++++++------ .../global-router-interface.h} | 194 +++++------ .../{ => global}/routing-environment.cc | 8 +- .../{ => global}/routing-environment.h | 5 +- src/routing/wscript | 26 -- src/wscript | 2 +- 14 files changed, 490 insertions(+), 506 deletions(-) rename src/routing/{ => global}/candidate-queue.cc (100%) rename src/routing/{ => global}/candidate-queue.h (99%) rename src/routing/{static-route-manager-impl.cc => global/global-route-manager-impl.cc} (81%) rename src/routing/{static-route-manager-impl.h => global/global-route-manager-impl.h} (85%) rename src/routing/{static-route-manager.cc => global/global-route-manager.cc} (71%) rename src/routing/{static-route-manager.h => global/global-route-manager.h} (73%) rename src/routing/{static-router.cc => global/global-router-interface.cc} (68%) rename src/routing/{static-router.h => global/global-router-interface.h} (72%) rename src/routing/{ => global}/routing-environment.cc (85%) rename src/routing/{ => global}/routing-environment.h (97%) delete mode 100644 src/routing/wscript diff --git a/examples/wscript b/examples/wscript index 6e8fea84d..f16c98c84 100644 --- a/examples/wscript +++ b/examples/wscript @@ -9,6 +9,9 @@ def build(bld): obj.source = source return obj - obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node']) - obj = create_ns_prog('simple-static-routing', 'simple-static-routing.cc', deps=['p2p', 'internet-node', 'routing']) + obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', + deps=['p2p', 'internet-node']) + + obj = create_ns_prog('simple-global-routing', 'simple-global-routing.cc', + deps=['p2p', 'internet-node', 'routing']) diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index 611b6c9a5..c6eb92f43 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -24,7 +24,7 @@ #include "ns3/composite-trace-resolver.h" #include "ns3/net-device.h" #include "ns3/routing-environment.h" -#include "ns3/static-router.h" +#include "ns3/global-router-interface.h" #include "l3-demux.h" #include "ipv4-l4-demux.h" @@ -83,10 +83,10 @@ InternetNode::Construct (void) // of the StaticRouter interface tells the route manager that it needs to // ask a given node about any link state records that it may want to advertise. // - if (RoutingEnvironment::StaticRoutingEnabled()) + if (RoutingEnvironment::GlobalRoutingEnabled()) { - Ptr staticRouter = Create (this); - Object::AddInterface (staticRouter); + Ptr globalRouter = Create (this); + Object::AddInterface (globalRouter); } } diff --git a/src/routing/candidate-queue.cc b/src/routing/global/candidate-queue.cc similarity index 100% rename from src/routing/candidate-queue.cc rename to src/routing/global/candidate-queue.cc diff --git a/src/routing/candidate-queue.h b/src/routing/global/candidate-queue.h similarity index 99% rename from src/routing/candidate-queue.h rename to src/routing/global/candidate-queue.h index 27fcd01b4..1c01cb2ec 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/global/candidate-queue.h @@ -19,7 +19,7 @@ #include #include -#include "static-route-manager-impl.h" +#include "global-route-manager-impl.h" namespace ns3 { diff --git a/src/routing/static-route-manager-impl.cc b/src/routing/global/global-route-manager-impl.cc similarity index 81% rename from src/routing/static-route-manager-impl.cc rename to src/routing/global/global-route-manager-impl.cc index 0b2a61ddb..df6ad3ad5 100644 --- a/src/routing/static-route-manager-impl.cc +++ b/src/routing/global/global-route-manager-impl.cc @@ -22,11 +22,11 @@ #include "ns3/debug.h" #include "ns3/node-list.h" #include "ns3/ipv4.h" -#include "static-router.h" -#include "static-route-manager-impl.h" +#include "global-router-interface.h" +#include "global-route-manager-impl.h" #include "candidate-queue.h" -NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); +NS_DEBUG_COMPONENT_DEFINE ("GlobalRouteManager"); namespace ns3 { @@ -48,7 +48,7 @@ SPFVertex::SPFVertex () : { } -SPFVertex::SPFVertex (StaticRouterLSA* lsa) : +SPFVertex::SPFVertex (GlobalRouterLSA* lsa) : m_vertexType (VertexRouter), m_vertexId (lsa->GetLinkStateId ()), m_lsa (lsa), @@ -99,12 +99,12 @@ SPFVertex::GetVertexId (void) const } void -SPFVertex::SetLSA (StaticRouterLSA* lsa) +SPFVertex::SetLSA (GlobalRouterLSA* lsa) { m_lsa = lsa; } - StaticRouterLSA* + GlobalRouterLSA* SPFVertex::GetLSA (void) const { return m_lsa; @@ -191,56 +191,56 @@ SPFVertex::AddChild (SPFVertex* child) // --------------------------------------------------------------------------- // -// StaticRouteManagerLSDB Implementation +// GlobalRouteManagerLSDB Implementation // // --------------------------------------------------------------------------- -StaticRouteManagerLSDB::StaticRouteManagerLSDB () +GlobalRouteManagerLSDB::GlobalRouteManagerLSDB () : m_database () { - NS_DEBUG ("StaticRouteManagerLSDB::StaticRouteManagerLSDB ()"); + NS_DEBUG ("GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()"); } -StaticRouteManagerLSDB::~StaticRouteManagerLSDB () +GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB () { - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); + NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()"); LSDBMap_t::iterator i; for (i= m_database.begin (); i!= m_database.end (); i++) { - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ():free LSA"); - StaticRouterLSA* temp = i->second; + NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ():free LSA"); + GlobalRouterLSA* temp = i->second; delete temp; } - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); + NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB (): clear map"); m_database.clear (); } void -StaticRouteManagerLSDB::Initialize () +GlobalRouteManagerLSDB::Initialize () { - NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); + NS_DEBUG ("GlobalRouteManagerLSDB::Initialize ()"); LSDBMap_t::iterator i; for (i= m_database.begin (); i!= m_database.end (); i++) { - StaticRouterLSA* temp = i->second; - temp->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); + GlobalRouterLSA* temp = i->second; + temp->SetStatus (GlobalRouterLSA::LSA_SPF_NOT_EXPLORED); } } void -StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) +GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRouterLSA* lsa) { - NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); + NS_DEBUG ("GlobalRouteManagerLSDB::Insert ()"); m_database.insert (LSDBPair_t (addr, lsa)); } - StaticRouterLSA* -StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const + GlobalRouterLSA* +GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const { - NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); + NS_DEBUG ("GlobalRouteManagerLSDB::GetLSA ()"); // // Look up an LSA by its address. // @@ -257,21 +257,21 @@ StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const // --------------------------------------------------------------------------- // -// StaticRouteManagerImpl Implementation +// GlobalRouteManagerImpl Implementation // // --------------------------------------------------------------------------- -StaticRouteManagerImpl::StaticRouteManagerImpl () +GlobalRouteManagerImpl::GlobalRouteManagerImpl () : m_spfroot (0) { - NS_DEBUG ("StaticRouteManagerImpl::StaticRoutemanagerImpl ()"); - m_lsdb = new StaticRouteManagerLSDB (); + NS_DEBUG ("GlobalRouteManagerImpl::GlobalRoutemanagerImpl ()"); + m_lsdb = new GlobalRouteManagerLSDB (); } -StaticRouteManagerImpl::~StaticRouteManagerImpl () +GlobalRouteManagerImpl::~GlobalRouteManagerImpl () { - NS_DEBUG ("StaticRouteManagerImpl::~StaticRouteManagerImpl ()"); + NS_DEBUG ("GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()"); if (m_lsdb) { @@ -280,9 +280,9 @@ StaticRouteManagerImpl::~StaticRouteManagerImpl () } void -StaticRouteManagerImpl::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) +GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb) { - NS_DEBUG ("StaticRouteManagerImpl::DebugUseLsdb ()"); + NS_DEBUG ("GlobalRouteManagerImpl::DebugUseLsdb ()"); if (m_lsdb) { @@ -293,7 +293,7 @@ StaticRouteManagerImpl::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) // // In order to build the routing database, we need to walk the list of nodes -// in the system and look for those that support the StaticRouter interface. +// in the system and look for those that support the GlobalRouter interface. // These routers will export a number of Link State Advertisements (LSAs) // that describe the links and networks that are "adjacent" (i.e., that are // on the other side of a point-to-point link). We take these LSAs and put @@ -301,19 +301,19 @@ StaticRouteManagerImpl::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) // ultimately be computed. // void -StaticRouteManagerImpl::BuildStaticRoutingDatabase () +GlobalRouteManagerImpl::BuildGlobalRoutingDatabase () { - NS_DEBUG ("StaticRouteManagerImpl::BuildStaticRoutingDatabase()"); + NS_DEBUG ("GlobalRouteManagerImpl::BuildGlobalRoutingDatabase()"); // -// Walk the list of nodes looking for the StaticRouter Interface. +// Walk the list of nodes looking for the GlobalRouter Interface. // typedef std::vector < Ptr >::iterator Iterator; for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) { Ptr node = *i; - Ptr rtr = - node->QueryInterface (StaticRouter::iid); + Ptr rtr = + node->QueryInterface (GlobalRouter::iid); // // Ignore nodes that aren't participating in routing. // @@ -324,7 +324,7 @@ StaticRouteManagerImpl::BuildStaticRoutingDatabase () // // You must call DiscoverLSAs () before trying to use any routing info or to // update LSAs. DiscoverLSAs () drives the process of discovering routes in -// the StaticRouter. Afterward, you may use GetNumLSAs (), which is a very +// the GlobalRouter. Afterward, you may use GetNumLSAs (), which is a very // computationally inexpensive call. If you call GetNumLSAs () before calling // DiscoverLSAs () will get zero as the number since no routes have been // found. @@ -334,7 +334,7 @@ StaticRouteManagerImpl::BuildStaticRoutingDatabase () for (uint32_t j = 0; j < numLSAs; ++j) { - StaticRouterLSA* lsa = new StaticRouterLSA (); + GlobalRouterLSA* lsa = new GlobalRouterLSA (); // // This is the call to actually fetch a Link State Advertisement from the // router. @@ -351,8 +351,8 @@ StaticRouteManagerImpl::BuildStaticRoutingDatabase () } // -// For each node that is a static router (which is determined by the presence -// of an aggregated StaticRouter interface), run the Dijkstra SPF calculation +// For each node that is a global router (which is determined by the presence +// of an aggregated GlobalRouter interface), run the Dijkstra SPF calculation // on the database rooted at that router, and populate the node forwarding // tables. // @@ -384,9 +384,9 @@ StaticRouteManagerImpl::BuildStaticRoutingDatabase () // list becomes empty. // void -StaticRouteManagerImpl::InitializeRoutes () +GlobalRouteManagerImpl::InitializeRoutes () { - NS_DEBUG ("StaticRouteManagerImpl::InitializeRoutes ()"); + NS_DEBUG ("GlobalRouteManagerImpl::InitializeRoutes ()"); // // Walk the list of nodes in the system. // @@ -395,13 +395,13 @@ StaticRouteManagerImpl::InitializeRoutes () { Ptr node = *i; // -// Look for the StaticRouter interface that indicates that the node is +// Look for the GlobalRouter interface that indicates that the node is // participating in routing. // - Ptr rtr = - node->QueryInterface (StaticRouter::iid); + Ptr rtr = + node->QueryInterface (GlobalRouter::iid); // -// if the node has a static router interface, then run the static routing +// if the node has a global router interface, then run the global routing // algorithms. // if (rtr && rtr->GetNumLSAs () ) @@ -425,13 +425,13 @@ StaticRouteManagerImpl::InitializeRoutes () // vertex already on the candidate list, store the new (lower) cost. // void -StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) +GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) { SPFVertex* w = 0; - StaticRouterLSA* w_lsa = 0; + GlobalRouterLSA* w_lsa = 0; uint32_t distance = 0; - NS_DEBUG ("StaticRouteManagerImpl::SPFNext ()"); + NS_DEBUG ("GlobalRouteManagerImpl::SPFNext ()"); // // Always true for now, since all our LSAs are RouterLSAs. // @@ -452,8 +452,8 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // Links to stub networks will be considered in the second stage of the // shortest path calculation. // - StaticRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) + GlobalRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); + if (l->GetLinkType () == GlobalRouterLinkRecord::StubNetwork) { NS_DEBUG ("SPFNext: Found a Stub record to " << l->GetLinkId ()); @@ -464,7 +464,7 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // the vertex W's LSA (router-LSA or network-LSA) in Area A's link state // database. // - if (l->GetLinkType () == StaticRouterLinkRecord::PointToPoint) + if (l->GetLinkType () == GlobalRouterLinkRecord::PointToPoint) { // // Lookup the link state advertisement of the new link -- we call it in @@ -482,7 +482,7 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // then we have it covered -- ignore it. // if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_IN_SPFTREE) + GlobalRouterLSA::LSA_SPF_IN_SPFTREE) { NS_DEBUG ("SPFNext: Skipping-> LSA "<< w_lsa->GetLinkStateId () << " already in SPF tree"); @@ -502,7 +502,7 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) w_lsa->GetLinkStateId ()); if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + GlobalRouterLSA::LSA_SPF_NOT_EXPLORED) { // // If we haven't yet considered the link represented by we have to create @@ -518,7 +518,7 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) if (SPFNexthopCalculation (v, w, l, distance)) { w_lsa->SetStatus ( - StaticRouterLSA::LSA_SPF_CANDIDATE); + GlobalRouterLSA::LSA_SPF_CANDIDATE); // // Push this new vertex onto the priority queue (ordered by distance from the // root node). @@ -530,7 +530,7 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) } } } else if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_CANDIDATE) + GlobalRouterLSA::LSA_SPF_CANDIDATE) { // // We have already considered the link represented by . What wse have to @@ -589,13 +589,13 @@ StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // For now, this is greatly simplified from the quagga code // int -StaticRouteManagerImpl::SPFNexthopCalculation ( +GlobalRouteManagerImpl::SPFNexthopCalculation ( SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* l, + GlobalRouterLinkRecord* l, uint32_t distance) { - NS_DEBUG ("StaticRouteManagerImpl::SPFNexthopCalculation ()"); + NS_DEBUG ("GlobalRouteManagerImpl::SPFNexthopCalculation ()"); // // The vertex m_spfroot is a distinguished vertex representing the node at // the root of the calculations. That is, it is the node for which we are @@ -633,7 +633,7 @@ StaticRouteManagerImpl::SPFNexthopCalculation ( { // // In the case of point-to-point links, the link data field (m_linkData) of a -// Static Router Link Record contains the local IP address. If we look at the +// Global Router Link Record contains the local IP address. If we look at the // link record describing the link from the perspecive of (the remote // node from the viewpoint of ) back to the root node, we can discover the // IP address of the router to which is adjacent. This is a distinguished @@ -644,12 +644,12 @@ StaticRouteManagerImpl::SPFNexthopCalculation ( // return the link record describing the link from to . Think of it as // SPFGetLink. // - StaticRouterLinkRecord *linkRemote = 0; + GlobalRouterLinkRecord *linkRemote = 0; linkRemote = SPFGetNextLink (w, v, linkRemote); // -// At this point, is the Static Router Link Record describing the point- +// At this point, is the Global Router Link Record describing the point- // to point link from to from the perspective of ; and -// is the Static Router Link Record describing that same link from the +// is the Global Router Link Record describing that same link from the // perspective of (back to ). Now we can just copy the next hop // address from the m_linkData member variable. // @@ -702,25 +702,28 @@ StaticRouteManagerImpl::SPFNexthopCalculation ( // // This method is derived from quagga ospf_get_next_link () // -// First search the Static Router Link Records of vertex for one +// First search the Global Router Link Records of vertex for one // representing a point-to point link to vertex . // // What is done depends on prev_link. Contrary to appearances, prev_link just -// acts as a flag here. If prev_link is NULL, we return the first Static +// acts as a flag here. If prev_link is NULL, we return the first Global // Router Link Record we find that describes a point-to-point link from -// to . If prev_link is not NULL, we return a Static Router Link Record +// to . If prev_link is not NULL, we return a Global Router Link Record // representing a possible *second* link from to . // - StaticRouterLinkRecord* -StaticRouteManagerImpl::SPFGetNextLink ( +// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for +// any link records after pre_link and not just after the first? +// + GlobalRouterLinkRecord* +GlobalRouteManagerImpl::SPFGetNextLink ( SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* prev_link) + GlobalRouterLinkRecord* prev_link) { - NS_DEBUG ("StaticRouteManagerImpl::SPFGetNextLink ()"); + NS_DEBUG ("GlobalRouteManagerImpl::SPFGetNextLink ()"); bool skip = true; - StaticRouterLinkRecord* l; + GlobalRouterLinkRecord* l; // // If prev_link is 0, we are really looking for the first link, not the next // link. @@ -730,14 +733,14 @@ StaticRouteManagerImpl::SPFGetNextLink ( skip = false; } // -// Iterate through the Static Router Link Records advertised by the vertex +// Iterate through the Global Router Link Records advertised by the vertex // looking for records representing the point-to-point links off of this // vertex. // for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) { l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) + if (l->GetLinkType () != GlobalRouterLinkRecord::PointToPoint) { continue; } @@ -768,7 +771,7 @@ StaticRouteManagerImpl::SPFGetNextLink ( { // // Skip is true and we've found a link from to . We want the next one. -// Setting skip to false gets us the next point-to-point static router link +// Setting skip to false gets us the next point-to-point global router link // record in the LSA from . // NS_DEBUG ("SPFGetNextLink: Skipping the found link"); @@ -784,17 +787,17 @@ StaticRouteManagerImpl::SPFGetNextLink ( // Used for unit tests. // void -StaticRouteManagerImpl::DebugSPFCalculate (Ipv4Address root) +GlobalRouteManagerImpl::DebugSPFCalculate (Ipv4Address root) { - NS_DEBUG ("StaticRouteManagerImpl::DebugSPFCalculate ()"); + NS_DEBUG ("GlobalRouteManagerImpl::DebugSPFCalculate ()"); SPFCalculate (root); } // quagga ospf_spf_calculate void -StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) +GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root) { - NS_DEBUG ("StaticRouteManagerImpl::SPFCalculate (): " + NS_DEBUG ("GlobalRouteManagerImpl::SPFCalculate (): " "root = " << root); SPFVertex *v; @@ -821,7 +824,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) // m_spfroot= v; v->SetDistanceFromRoot (0); - v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); + v->GetLSA ()->SetStatus (GlobalRouterLSA::LSA_SPF_IN_SPFTREE); for (;;) { @@ -831,7 +834,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) // // RFC2328 16.1. (2). // -// We examine the Static Router Link Records in the Link State +// We examine the Global Router Link Records in the Link State // Advertisements of the current vertex. If there are any point-to-point // links to unexplored adjacent vertices we add them to the tree and update // the distance and next hop information on how to get there. We also add @@ -857,7 +860,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) // list in the process). // // Recall that in the previous step, we created SPFVertex structures for each -// of the routers found in the Static Router Link Records and added tehm to +// of the routers found in the Global Router Link Records and added tehm to // the candidate list. // v = candidate.Pop (); @@ -866,7 +869,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) // Update the status field of the vertex to indicate that it is in the SPF // tree. // - v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); + v->GetLSA ()->SetStatus (GlobalRouterLSA::LSA_SPF_IN_SPFTREE); // // The current vertex has a parent pointer. By calling this rather oddly // named method (blame quagga) we add the current vertex to the list of @@ -893,7 +896,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) // We're going to pop of a pointer to every vertex in the tree except the // root in order of distance from the root. For each of the vertices, we call // SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the -// point-to-point Static Router Link Records (the links to nodes adjacent to +// point-to-point Global Router Link Records (the links to nodes adjacent to // the node represented by the vertex). We add a route to the IP address // specified by the m_linkData field of each of those link records. This will // be the *local* IP address associated with the interface attached to the @@ -930,7 +933,7 @@ StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) // Return the interface index corresponding to a given IP address // uint32_t -StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) +GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) { // // We have an IP address and a vertex ID of the root of the SPF tree. @@ -951,10 +954,10 @@ StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) { Ptr node = *i; - Ptr rtr = - node->QueryInterface (StaticRouter::iid); + Ptr rtr = + node->QueryInterface (GlobalRouter::iid); // -// If the node doesn't have a StaticRouter interface it can't be the one +// If the node doesn't have a GlobalRouter interface it can't be the one // we're interested in. // if (rtr == 0) @@ -972,7 +975,7 @@ StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) // Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG (ipv4, - "StaticRouteManagerImpl::FindOutgoingInterfaceId (): " + "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): " "QI for interface failed"); // // Look through the interfaces on this node for one that has the IP address @@ -984,7 +987,7 @@ StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) if (ipv4->GetAddress (i) == a) { NS_DEBUG ( - "StaticRouteManagerImpl::FindOutgoingInterfaceId (): " + "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): " "Interface match for " << a); return i; } @@ -1014,12 +1017,12 @@ StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) // route. // void -StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) +GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) { - NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter ()"); + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter ()"); NS_ASSERT_MSG (m_spfroot, - "StaticRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set"); + "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set"); // // The root of the Shortest Path First tree is the router to which we are // going to write the actual routing table entries. The vertex corresponding @@ -1029,7 +1032,7 @@ StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // Ipv4Address routerId = m_spfroot->GetVertexId (); - NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): " "Vertex ID = " << routerId); // // We need to walk the list of nodes looking for the one that has the router @@ -1041,17 +1044,17 @@ StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) { Ptr node = *i; // -// The router ID is accessible through the StaticRouter interface, so we need -// to QI for that interface. If there's no StaticRouter interface, the node +// The router ID is accessible through the GlobalRouter interface, so we need +// to QI for that interface. If there's no GlobalRouter interface, the node // in question cannot be the router we want, so we continue. // - Ptr rtr = - node->QueryInterface (StaticRouter::iid); + Ptr rtr = + node->QueryInterface (GlobalRouter::iid); if (rtr == 0) { - NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " - "No StaticRouter interface on node " << node->GetId ()); + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): " + "No GlobalRouter interface on node " << node->GetId ()); continue; } // @@ -1059,12 +1062,12 @@ StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // root of the SPF tree, then this node is the one for which we need to // write the routing tables. // - NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): " "Considering router " << rtr->GetRouterId ()); if (rtr->GetRouterId () == routerId) { - NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): " "setting routes for node " << node->GetId ()); // // Routing information is updated using the Ipv4 interface. We need to QI @@ -1073,17 +1076,17 @@ StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG (ipv4, - "StaticRouteManagerImpl::SPFIntraAddRouter (): " + "GlobalRouteManagerImpl::SPFIntraAddRouter (): " "QI for interface failed"); // -// Get the Static Router Link State Advertisement from the vertex we're -// adding the routes to. The LSA will have a number of attached Static Router +// Get the Global Router Link State Advertisement from the vertex we're +// adding the routes to. The LSA will have a number of attached Global Router // Link Records corresponding to links off of that vertex / node. We're going // to be interested in the records corresponding to point-to-point links. // - StaticRouterLSA *lsa = v->GetLSA (); + GlobalRouterLSA *lsa = v->GetLSA (); NS_ASSERT_MSG (lsa, - "StaticRouteManagerImpl::SPFIntraAddRouter (): " + "GlobalRouteManagerImpl::SPFIntraAddRouter (): " "Expected valid LSA in SPFVertex* v"); uint32_t nLinkRecords = lsa->GetNLinkRecords (); @@ -1100,13 +1103,13 @@ StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // // We are only concerned about point-to-point links // - StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); - if (lr->GetLinkType () != StaticRouterLinkRecord::PointToPoint) + GlobalRouterLinkRecord *lr = lsa->GetLinkRecord (j); + if (lr->GetLinkType () != GlobalRouterLinkRecord::PointToPoint) { continue; } - NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): " " Node " << node->GetId () << " add route to " << lr->GetLinkData () << " using next hop " << v->GetNextHop () << @@ -1147,7 +1150,7 @@ StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // For now, only one parent (not doing equal-cost multipath) // void -StaticRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) +GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) { v->GetParent ()->AddChild (v); } @@ -1166,44 +1169,44 @@ StaticRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) namespace ns3 { -class StaticRouterTestNode : public Node +class GlobalRouterTestNode : public Node { public: - StaticRouterTestNode (); + GlobalRouterTestNode (); private: virtual void DoAddDevice (Ptr device) const {}; virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); }; -StaticRouterTestNode::StaticRouterTestNode () +GlobalRouterTestNode::GlobalRouterTestNode () { // Ptr ipv4 = Create (this); } TraceResolver* -StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) +GlobalRouterTestNode::DoCreateTraceResolver (TraceContext const &context) { return 0; } -class StaticRouteManagerImplTest : public Test { +class GlobalRouteManagerImplTest : public Test { public: - StaticRouteManagerImplTest (); - virtual ~StaticRouteManagerImplTest (); + GlobalRouteManagerImplTest (); + virtual ~GlobalRouteManagerImplTest (); virtual bool RunTests (void); }; -StaticRouteManagerImplTest::StaticRouteManagerImplTest () - : Test ("StaticRouteManagerImpl") +GlobalRouteManagerImplTest::GlobalRouteManagerImplTest () + : Test ("GlobalRouteManagerImpl") { } -StaticRouteManagerImplTest::~StaticRouteManagerImplTest () +GlobalRouteManagerImplTest::~GlobalRouteManagerImplTest () {} bool -StaticRouteManagerImplTest::RunTests (void) +GlobalRouteManagerImplTest::RunTests (void) { bool ok = true; @@ -1246,81 +1249,81 @@ StaticRouteManagerImplTest::RunTests (void) // link2: 10.1.3.1/30, 10.1.3.2/30 // // Router 0 - StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, + GlobalRouterLinkRecord* lr0 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::PointToPoint, "0.0.0.2", // router ID 0.0.0.2 "10.1.1.1", // local ID 1); // metric - StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, + GlobalRouterLinkRecord* lr1 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::StubNetwork, "10.1.1.1", "255.255.255.252", 1); - StaticRouterLSA* lsa0 = new StaticRouterLSA (); + GlobalRouterLSA* lsa0 = new GlobalRouterLSA (); lsa0->SetLinkStateId ("0.0.0.0"); lsa0->SetAdvertisingRouter ("0.0.0.0"); lsa0->AddLinkRecord (lr0); lsa0->AddLinkRecord (lr1); // Router 1 - StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, + GlobalRouterLinkRecord* lr2 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::PointToPoint, "0.0.0.2", "10.1.2.1", 1); - StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, + GlobalRouterLinkRecord* lr3 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::StubNetwork, "10.1.2.1", "255.255.255.252", 1); - StaticRouterLSA* lsa1 = new StaticRouterLSA (); + GlobalRouterLSA* lsa1 = new GlobalRouterLSA (); lsa1->SetLinkStateId ("0.0.0.1"); lsa1->SetAdvertisingRouter ("0.0.0.1"); lsa1->AddLinkRecord (lr2); lsa1->AddLinkRecord (lr3); // Router 2 - StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, + GlobalRouterLinkRecord* lr4 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::PointToPoint, "0.0.0.0", "10.1.1.2", 1); - StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, + GlobalRouterLinkRecord* lr5 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::StubNetwork, "10.1.1.2", "255.255.255.252", 1); - StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, + GlobalRouterLinkRecord* lr6 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::PointToPoint, "0.0.0.1", "10.1.2.2", 1); - StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, + GlobalRouterLinkRecord* lr7 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::StubNetwork, "10.1.2.2", "255.255.255.252", 1); - StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, + GlobalRouterLinkRecord* lr8 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::PointToPoint, "0.0.0.3", "10.1.3.2", 1); - StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, + GlobalRouterLinkRecord* lr9 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::StubNetwork, "10.1.3.2", "255.255.255.252", 1); - StaticRouterLSA* lsa2 = new StaticRouterLSA (); + GlobalRouterLSA* lsa2 = new GlobalRouterLSA (); lsa2->SetLinkStateId ("0.0.0.2"); lsa2->SetAdvertisingRouter ("0.0.0.2"); lsa2->AddLinkRecord (lr4); @@ -1331,26 +1334,26 @@ StaticRouteManagerImplTest::RunTests (void) lsa2->AddLinkRecord (lr9); // Router 3 - StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, + GlobalRouterLinkRecord* lr10 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::PointToPoint, "0.0.0.2", "10.1.2.1", 1); - StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, + GlobalRouterLinkRecord* lr11 = new GlobalRouterLinkRecord ( + GlobalRouterLinkRecord::StubNetwork, "10.1.2.1", "255.255.255.252", 1); - StaticRouterLSA* lsa3 = new StaticRouterLSA (); + GlobalRouterLSA* lsa3 = new GlobalRouterLSA (); lsa3->SetLinkStateId ("0.0.0.3"); lsa3->SetAdvertisingRouter ("0.0.0.3"); lsa3->AddLinkRecord (lr10); lsa3->AddLinkRecord (lr11); // Test the database - StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); + GlobalRouteManagerLSDB* srmlsdb = new GlobalRouteManagerLSDB (); srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0); srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1); srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2); @@ -1358,13 +1361,11 @@ StaticRouteManagerImplTest::RunTests (void) NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); // next, calculate routes based on the manually created LSDB - StaticRouteManagerImpl* srm = new StaticRouteManagerImpl (); + GlobalRouteManagerImpl* srm = new GlobalRouteManagerImpl (); srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB // Note-- this will succeed without any nodes in the topology // because the NodeList is empty srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 - - // XXX here we should do some verification of the routes built // This delete clears the srm, which deletes the LSDB, which clears // all of the LSAs, which each destroys the attached LinkRecords. @@ -1374,7 +1375,8 @@ StaticRouteManagerImplTest::RunTests (void) } // Instantiate this class for the unit tests -static StaticRouteManagerImplTest g_staticRouteManagerTest; +// XXX here we should do some verification of the routes built +static GlobalRouteManagerImplTest g_globalRouteManagerTest; } // namespace ns3 diff --git a/src/routing/static-route-manager-impl.h b/src/routing/global/global-route-manager-impl.h similarity index 85% rename from src/routing/static-route-manager-impl.h rename to src/routing/global/global-route-manager-impl.h index 776904818..a355cdfb0 100644 --- a/src/routing/static-route-manager-impl.h +++ b/src/routing/global/global-route-manager-impl.h @@ -13,8 +13,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef STATIC_ROUTE_MANAGER_IMPL_H -#define STATIC_ROUTE_MANAGER_IMPL_H +#ifndef GLOBAL_ROUTE_MANAGER_IMPL_H +#define GLOBAL_ROUTE_MANAGER_IMPL_H #include #include @@ -23,7 +23,7 @@ #include "ns3/object.h" #include "ns3/ptr.h" #include "ns3/ipv4-address.h" -#include "static-router.h" +#include "global-router-interface.h" namespace ns3 { @@ -46,9 +46,9 @@ class CandidateQueue; * or networks in the simulation are arranged in the SPF tree. It is this * tree that represents the Shortest Paths to the other networks. * - * Each SPFVertex has a pointer to the Static Router Link State Advertisement + * Each SPFVertex has a pointer to the Global Router Link State Advertisement * (LSA) that its underlying router has exported. Within these LSAs are - * Static Router Link Records that describe the point to point links from the + * Global Router Link Records that describe the point to point links from the * underlying router to other nodes (represented by other SPFVertex objects) * in the simulation topology. The combination of the arrangement of the * SPFVertex objects in the SPF tree, along with the details of the link @@ -96,10 +96,10 @@ public: * * @see SPFVertex::SPFVertex () * @see VertexType - * @see StaticRouterLSA + * @see GlobalRouterLSA * @param lsa The Link State Advertisement used for finding initial values. */ - SPFVertex(StaticRouterLSA* lsa); + SPFVertex(GlobalRouterLSA* lsa); /** * @brief Destroy an SPFVertex (Shortest Path First Vertex). * @@ -136,7 +136,7 @@ public: * representing routers, and comes from the Link State Advertisement of a * router aggregated to a node in the simulation. These IDs are allocated * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increase as new routers are + * beginning at 0.0.0.0 and monotonically increasing as new routers are * instantiated. * * @returns The Ipv4Address Vertex ID of the current SPFVertex object. @@ -158,31 +158,31 @@ public: */ void SetVertexId (Ipv4Address id); /** - * @brief Get the Static Router Link State Advertisement returned by the - * Static Router represented by this SPFVertex during the route discovery + * @brief Get the Global Router Link State Advertisement returned by the + * Global Router represented by this SPFVertex during the route discovery * process. * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @returns A pointer to the StaticRouterLSA found by the router represented + * @see GlobalRouter + * @see GlobalRouterLSA + * @see GlobalRouter::DiscoverLSAs () + * @returns A pointer to the GlobalRouterLSA found by the router represented * by this SPFVertex object. */ - StaticRouterLSA* GetLSA (void) const; + GlobalRouterLSA* GetLSA (void) const; /** - * @brief Set the Static Router Link State Advertisement returned by the - * Static Router represented by this SPFVertex during the route discovery + * @brief Set the Global Router Link State Advertisement returned by the + * Global Router represented by this SPFVertex during the route discovery * process. * * @see SPFVertex::GetLSA () - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () + * @see GlobalRouter + * @see GlobalRouterLSA + * @see GlobalRouter::DiscoverLSAs () * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You * must not delete the LSA after calling this method. - * @param lsa A pointer to the StaticRouterLSA. + * @param lsa A pointer to the GlobalRouterLSA. */ - void SetLSA (StaticRouterLSA* lsa); + void SetLSA (GlobalRouterLSA* lsa); /** * @brief Get the distance from the root vertex to "this" SPFVertex object. * @@ -240,11 +240,11 @@ public: * path to "this" vertex. * * When initializing the root SPFVertex, the interface ID is determined by - * examining the Static Router Link Records of the Link State Advertisement - * generated by the root node's StaticRouter. These interfaces are used to + * examining the Global Router Link Records of the Link State Advertisement + * generated by the root node's GlobalRouter. These interfaces are used to * forward packets off of the root's network down those links. As other * vertices are discovered which are further away from the root, they will - * be accessible down one of the paths begun by a Static Router Link Record. + * be accessible down one of the paths begun by a Global Router Link Record. * * To forward packets to these hosts or networks, the root node must begin * the forwarding process by sending the packets to the interface of that @@ -256,9 +256,9 @@ public: * should I use to get a packet to the network or host represented by 'this' * SPFVertex." * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord + * @see GlobalRouter + * @see GlobalRouterLSA + * @see GlobalRouterLinkRecord * @returns The interface index to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ @@ -280,11 +280,11 @@ public: * path to "this" vertex. * * When initializing the root SPFVertex, the interface ID is determined by - * examining the Static Router Link Records of the Link State Advertisement - * generated by the root node's StaticRouter. These interfaces are used to + * examining the Global Router Link Records of the Link State Advertisement + * generated by the root node's GlobalRouter. These interfaces are used to * forward packets off of the root's network down those links. As other * vertices are discovered which are further away from the root, they will - * be accessible down one of the paths begun by a Static Router Link Record. + * be accessible down one of the paths begun by a Global Router Link Record. * * To forward packets to these hosts or networks, the root node must begin * the forwarding process by sending the packets to the interface of that @@ -296,9 +296,9 @@ public: * interfaces it should use to get a packet to the network or host represented * by "this" SPFVertex. * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord + * @see GlobalRouter + * @see GlobalRouterLSA + * @see GlobalRouterLinkRecord * @param id The interface index to use when forwarding packets to the host or * network represented by "this" SPFVertex. */ @@ -320,12 +320,12 @@ public: * destination for packets along the path to "this" vertex. * * When initializing the root SPFVertex, the IP address used when forwarding - * packets is determined by examining the Static Router Link Records of the - * Link State Advertisement generated by the root node's StaticRouter. This + * packets is determined by examining the Global Router Link Records of the + * Link State Advertisement generated by the root node's GlobalRouter. This * address is used to forward packets off of the root's network down those * links. As other vertices / nodes are discovered which are further away * from the root, they will be accessible down one of the paths via a link - * described by one of these Static Router Link Records. + * described by one of these Global Router Link Records. * * To forward packets to these hosts or networks, the root node must begin * the forwarding process by sending the packets to a first hop router down @@ -337,9 +337,9 @@ public: * packet to in order to get that packet to the network or host represented * by 'this' SPFVertex." * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord + * @see GlobalRouter + * @see GlobalRouterLSA + * @see GlobalRouterLinkRecord * @returns The IP address to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ @@ -361,12 +361,12 @@ public: * destination for packets along the path to "this" vertex. * * When initializing the root SPFVertex, the IP address used when forwarding - * packets is determined by examining the Static Router Link Records of the - * Link State Advertisement generated by the root node's StaticRouter. This + * packets is determined by examining the Global Router Link Records of the + * Link State Advertisement generated by the root node's GlobalRouter. This * address is used to forward packets off of the root's network down those * links. As other vertices / nodes are discovered which are further away * from the root, they will be accessible down one of the paths via a link - * described by one of these Static Router Link Records. + * described by one of these Global Router Link Records. * * To forward packets to these hosts or networks, the root node must begin * the forwarding process by sending the packets to a first hop router down @@ -378,9 +378,9 @@ public: * should I send a packet to in order to get that packet to the network or * host represented by 'this' SPFVertex." * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord + * @see GlobalRouter + * @see GlobalRouterLSA + * @see GlobalRouterLinkRecord * @param nextHop The IP address to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ @@ -501,7 +501,7 @@ public: private: VertexType m_vertexType; Ipv4Address m_vertexId; - StaticRouterLSA* m_lsa; + GlobalRouterLSA* m_lsa; uint32_t m_distanceFromRoot; uint32_t m_rootOif; Ipv4Address m_nextHop; @@ -521,65 +521,65 @@ private: }; /** - * @brief The Link State DataBase (LSDB) of the StaticRouteManager. + * @brief The Link State DataBase (LSDB) of the Global Route Manager. * - * Each node in the simulation participating in static routing has a - * StaticRouter interface. The primary job of this interface is to export - * Static Router Link State Advertisements (LSAs). These advertisements in - * turn contain a number of Static Router Link Records that describe the + * Each node in the simulation participating in global routing has a + * GlobalRouter interface. The primary job of this interface is to export + * Global Router Link State Advertisements (LSAs). These advertisements in + * turn contain a number of Global Router Link Records that describe the * point to point links from the underlying node to other nodes (that will * also export their own LSAs. * * This class implements a searchable database of LSAs gathered from every * router in the simulation. */ -class StaticRouteManagerLSDB +class GlobalRouteManagerLSDB { public: /** - * @brief Construct an empty StaticRoutingManager Link State Database. + * @brief Construct an empty Global Router Manager Link State Database. * * The database map composing the Link State Database is initialized in * this constructor. */ - StaticRouteManagerLSDB (); + GlobalRouteManagerLSDB (); /** - * @brief Destroy an empty StaticRoutingManager Link State Database. + * @brief Destroy an empty Global Router Manager Link State Database. * * The database map is walked and all of the Link State Advertisements stored * in the database are freed; then the database map itself is clear ()ed to * release any remaining resources. */ - ~StaticRouteManagerLSDB (); + ~GlobalRouteManagerLSDB (); /** * @brief Insert an IP address / Link State Advertisement pair into the Link * State Database. * - * The IPV4 address and the StaticRouterLSA given as parameters are converted + * The IPV4 address and the GlobalRouterLSA given as parameters are converted * to an STL pair and are inserted into the database map. * - * @see StaticRouterLSA + * @see GlobalRouterLSA * @see Ipv4Address * @param addr The IP address associated with the LSA. Typically the Router * ID. * @param lsa A pointer to the Link State Advertisement for the router. */ - void Insert(Ipv4Address addr, StaticRouterLSA* lsa); + void Insert(Ipv4Address addr, GlobalRouterLSA* lsa); /** * @brief Look up the Link State Advertisement associated with the given * IP Address. * * The database map is searched for the given IPV4 address and corresponding - * StaticRouterLSA is returned. + * GlobalRouterLSA is returned. * - * @see StaticRouterLSA + * @see GlobalRouterLSA * @see Ipv4Address * @param addr The IP address associated with the LSA. Typically the Router * ID. * @returns A pointer to the Link State Advertisement for the router specified * by the IP address addr. */ - StaticRouterLSA* GetLSA (Ipv4Address addr) const; + GlobalRouterLSA* GetLSA (Ipv4Address addr) const; /** * @brief Set all LSA flags to an initialized state, for SPF computation * @@ -588,50 +588,50 @@ public: * prior to each SPF calculation to reset the state of the SPFVertex structures * that will reference the LSAs during the calculation. * - * @see StaticRouterLSA + * @see GlobalRouterLSA * @see SPFVertex */ void Initialize (); private: - typedef std::map LSDBMap_t; - typedef std::pair LSDBPair_t; + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; LSDBMap_t m_database; /** - * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no + * @brief GlobalRouteManagerLSDB copy construction is disallowed. There's no * need for it and a compiler provided shallow copy would be wrong. */ - StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); + GlobalRouteManagerLSDB (GlobalRouteManagerLSDB& lsdb); /** * @brief The SPFVertex copy assignment operator is disallowed. There's no * need for it and a compiler provided shallow copy would be wrong. */ - StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); + GlobalRouteManagerLSDB& operator= (GlobalRouteManagerLSDB& lsdb); }; /** - * @brief A global static router + * @brief A global router implementation. * * This singleton object can query interface each node in the system - * for a StaticRouter interface. For those nodes, it fetches one or + * for a GlobalRouter interface. For those nodes, it fetches one or * more Link State Advertisements and stores them in a local database. * Then, it can compute shortest paths on a per-node basis to all routers, * and finally configure each of the node's forwarding tables. * * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. */ -class StaticRouteManagerImpl +class GlobalRouteManagerImpl { public: - StaticRouteManagerImpl (); - virtual ~StaticRouteManagerImpl (); + GlobalRouteManagerImpl (); + virtual ~GlobalRouteManagerImpl (); /** * @brief Build the routing database by gathering Link State Advertisements - * from each node exporting a StaticRouter interface. + * from each node exporting a GlobalRouter interface. * */ - virtual void BuildStaticRoutingDatabase(); + virtual void BuildGlobalRoutingDatabase(); /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables @@ -640,38 +640,38 @@ public: /** * @brief Debugging routine; allow client code to supply a pre-built LSDB */ - void DebugUseLsdb (StaticRouteManagerLSDB*); + void DebugUseLsdb (GlobalRouteManagerLSDB*); /** * @brief Debugging routine; call the core SPF from the unit tests */ void DebugSPFCalculate (Ipv4Address root); private: /** - * @brief StaticRouteManager Implementation copy construction is disallowed. + * @brief GlobalRouteManagerImpl copy construction is disallowed. * There's no need for it and a compiler provided shallow copy would be * wrong. */ - StaticRouteManagerImpl (StaticRouteManagerImpl& srmi); + GlobalRouteManagerImpl (GlobalRouteManagerImpl& srmi); /** - * @brief StaticRouteManager Implementation assignment operator is + * @brief Global Route Manager Implementation assignment operator is * disallowed. There's no need for it and a compiler provided shallow copy - * would be wrong. + * would be hopelessly wrong. */ - StaticRouteManagerImpl& operator= (StaticRouteManagerImpl& srmi); + GlobalRouteManagerImpl& operator= (GlobalRouteManagerImpl& srmi); SPFVertex* m_spfroot; - StaticRouteManagerLSDB* m_lsdb; + GlobalRouteManagerLSDB* m_lsdb; void SPFCalculate (Ipv4Address root); void SPFNext (SPFVertex*, CandidateQueue&); int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* l, uint32_t distance); + GlobalRouterLinkRecord* l, uint32_t distance); void SPFVertexAddParent(SPFVertex* v); - StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* prev_link); + GlobalRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, + GlobalRouterLinkRecord* prev_link); void SPFIntraAddRouter(SPFVertex* v); uint32_t FindOutgoingInterfaceId(Ipv4Address a); }; } // namespace ns3 -#endif /* STATIC_ROUTE_MANAGER_IMPL_H */ +#endif /* GLOBAL_ROUTE_MANAGER_IMPL_H */ diff --git a/src/routing/static-route-manager.cc b/src/routing/global/global-route-manager.cc similarity index 71% rename from src/routing/static-route-manager.cc rename to src/routing/global/global-route-manager.cc index b3a0cb6ff..ce9e891c0 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/global/global-route-manager.cc @@ -17,35 +17,35 @@ #include "ns3/assert.h" #include "ns3/debug.h" #include "ns3/simulation-singleton.h" -#include "static-route-manager.h" -#include "static-route-manager-impl.h" +#include "global-route-manager.h" +#include "global-route-manager-impl.h" namespace ns3 { // --------------------------------------------------------------------------- // -// StaticRouteManager Implementation +// GlobalRouteManager Implementation // // --------------------------------------------------------------------------- void -StaticRouteManager::PopulateRoutingTables () +GlobalRouteManager::PopulateRoutingTables () { - BuildStaticRoutingDatabase (); + BuildGlobalRoutingDatabase (); InitializeRoutes (); } void -StaticRouteManager::BuildStaticRoutingDatabase () +GlobalRouteManager::BuildGlobalRoutingDatabase () { - return SimulationSingleton::Get ()-> - BuildStaticRoutingDatabase (); + return SimulationSingleton::Get ()-> + BuildGlobalRoutingDatabase (); } void -StaticRouteManager::InitializeRoutes () +GlobalRouteManager::InitializeRoutes () { - return SimulationSingleton::Get ()-> + return SimulationSingleton::Get ()-> InitializeRoutes (); } diff --git a/src/routing/static-route-manager.h b/src/routing/global/global-route-manager.h similarity index 73% rename from src/routing/static-route-manager.h rename to src/routing/global/global-route-manager.h index 11c6ec718..3a695dcdf 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/global/global-route-manager.h @@ -15,60 +15,64 @@ */ #ifndef STATIC_ROUTE_MANAGER_H -#define STATIC_ROUTE_MANAGER_H +#define GLOBAL_ROUTE_MANAGER_H namespace ns3 { /** - * @brief A global static router + * @brief A global global router * * This singleton object can query interface each node in the system - * for a StaticRouter interface. For those nodes, it fetches one or + * for a GlobalRouter interface. For those nodes, it fetches one or * more Link State Advertisements and stores them in a local database. * Then, it can compute shortest paths on a per-node basis to all routers, * and finally configure each of the node's forwarding tables. * * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. */ -class StaticRouteManager +class GlobalRouteManager { public: /** * @brief Build a routing database and initialize the routing tables of * the nodes in the simulation. * - * All this function does is call BuildStaticRoutingDatabase () and - * InitializeRoutes (). + * All this function does is call BuildGlobalRoutingDatabase () and + * InitializeRoutes (). * - * @see BuildStaticRoutingDatabase (); + * @see BuildGlobalRoutingDatabase (); * @see InitializeRoutes (); */ static void PopulateRoutingTables (); + private: /** * @brief Build the routing database by gathering Link State Advertisements - * from each node exporting a StaticRouter interface. + * from each node exporting a GlobalRouter interface. * */ - static void BuildStaticRoutingDatabase (); + static void BuildGlobalRoutingDatabase (); + /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables */ static void InitializeRoutes (); + /** - * @brief Static Route Manager copy construction is disallowed. There's no + * @brief Global Route Manager copy construction is disallowed. There's no * need for it and a compiler provided shallow copy would be wrong. * */ - StaticRouteManager (StaticRouteManager& srm); + GlobalRouteManager (GlobalRouteManager& srm); + /** - * @brief Static Router copy assignment operator is disallowed. There's no + * @brief Global Router copy assignment operator is disallowed. There's no * need for it and a compiler provided shallow copy would be wrong. */ - StaticRouteManager& operator= (StaticRouteManager& srm); + GlobalRouteManager& operator= (GlobalRouteManager& srm); }; } // namespace ns3 -#endif /* STATIC_ROUTE_MANAGER_H */ +#endif /* GLOBAL_ROUTE_MANAGER_H */ diff --git a/src/routing/static-router.cc b/src/routing/global/global-router-interface.cc similarity index 68% rename from src/routing/static-router.cc rename to src/routing/global/global-router-interface.cc index 82aa2c2e4..ff1f06318 100644 --- a/src/routing/static-router.cc +++ b/src/routing/global/global-router-interface.cc @@ -20,29 +20,29 @@ #include "ns3/net-device.h" #include "ns3/internet-node.h" #include "ns3/ipv4.h" -#include "static-router.h" +#include "global-router-interface.h" -NS_DEBUG_COMPONENT_DEFINE ("StaticRouter"); +NS_DEBUG_COMPONENT_DEFINE ("GlobalRouter"); namespace ns3 { // --------------------------------------------------------------------------- // -// StaticRouterLinkRecord Implementation +// GlobalRouterLinkRecord Implementation // // --------------------------------------------------------------------------- -StaticRouterLinkRecord::StaticRouterLinkRecord () +GlobalRouterLinkRecord::GlobalRouterLinkRecord () : m_linkId ("0.0.0.0"), m_linkData ("0.0.0.0"), m_linkType (Unknown), m_metric (0) { - NS_DEBUG("StaticRouterLinkRecord::StaticRouterLinkRecord ()"); + NS_DEBUG("GlobalRouterLinkRecord::GlobalRouterLinkRecord ()"); } -StaticRouterLinkRecord::StaticRouterLinkRecord ( +GlobalRouterLinkRecord::GlobalRouterLinkRecord ( LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, @@ -53,90 +53,90 @@ StaticRouterLinkRecord::StaticRouterLinkRecord ( m_linkType (linkType), m_metric (metric) { - NS_DEBUG("StaticRouterLinkRecord::StaticRouterLinkRecord (" << + NS_DEBUG("GlobalRouterLinkRecord::GlobalRouterLinkRecord (" << linkType << ", " << linkId << ", " << linkData << ", " << metric << ")"); } -StaticRouterLinkRecord::~StaticRouterLinkRecord () +GlobalRouterLinkRecord::~GlobalRouterLinkRecord () { - NS_DEBUG("StaticRouterLinkRecord::~StaticRouterLinkRecord ()"); + NS_DEBUG("GlobalRouterLinkRecord::~GlobalRouterLinkRecord ()"); } Ipv4Address -StaticRouterLinkRecord::GetLinkId (void) const +GlobalRouterLinkRecord::GetLinkId (void) const { - NS_DEBUG("StaticRouterLinkRecord::GetLinkId ()"); + NS_DEBUG("GlobalRouterLinkRecord::GetLinkId ()"); return m_linkId; } void -StaticRouterLinkRecord::SetLinkId (Ipv4Address addr) +GlobalRouterLinkRecord::SetLinkId (Ipv4Address addr) { - NS_DEBUG("StaticRouterLinkRecord::SetLinkId ()"); + NS_DEBUG("GlobalRouterLinkRecord::SetLinkId ()"); m_linkId = addr; } Ipv4Address -StaticRouterLinkRecord::GetLinkData (void) const +GlobalRouterLinkRecord::GetLinkData (void) const { - NS_DEBUG("StaticRouterLinkRecord::GetLinkData ()"); + NS_DEBUG("GlobalRouterLinkRecord::GetLinkData ()"); return m_linkData; } void -StaticRouterLinkRecord::SetLinkData (Ipv4Address addr) +GlobalRouterLinkRecord::SetLinkData (Ipv4Address addr) { - NS_DEBUG("StaticRouterLinkRecord::SetLinkData ()"); + NS_DEBUG("GlobalRouterLinkRecord::SetLinkData ()"); m_linkData = addr; } - StaticRouterLinkRecord::LinkType -StaticRouterLinkRecord::GetLinkType (void) const + GlobalRouterLinkRecord::LinkType +GlobalRouterLinkRecord::GetLinkType (void) const { - NS_DEBUG("StaticRouterLinkRecord::GetLinkType ()"); + NS_DEBUG("GlobalRouterLinkRecord::GetLinkType ()"); return m_linkType; } void -StaticRouterLinkRecord::SetLinkType ( - StaticRouterLinkRecord::LinkType linkType) +GlobalRouterLinkRecord::SetLinkType ( + GlobalRouterLinkRecord::LinkType linkType) { - NS_DEBUG("StaticRouterLinkRecord::SetLinkType ()"); + NS_DEBUG("GlobalRouterLinkRecord::SetLinkType ()"); m_linkType = linkType; } uint32_t -StaticRouterLinkRecord::GetMetric (void) const +GlobalRouterLinkRecord::GetMetric (void) const { - NS_DEBUG("StaticRouterLinkRecord::GetMetric ()"); + NS_DEBUG("GlobalRouterLinkRecord::GetMetric ()"); return m_metric; } void -StaticRouterLinkRecord::SetMetric (uint32_t metric) +GlobalRouterLinkRecord::SetMetric (uint32_t metric) { - NS_DEBUG("StaticRouterLinkRecord::SetMetric ()"); + NS_DEBUG("GlobalRouterLinkRecord::SetMetric ()"); m_metric = metric; } // --------------------------------------------------------------------------- // -// StaticRouterLSA Implementation +// GlobalRouterLSA Implementation // // --------------------------------------------------------------------------- -StaticRouterLSA::StaticRouterLSA() +GlobalRouterLSA::GlobalRouterLSA() : m_linkStateId("0.0.0.0"), m_advertisingRtr("0.0.0.0"), m_linkRecords(), - m_status(StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + m_status(GlobalRouterLSA::LSA_SPF_NOT_EXPLORED) { - NS_DEBUG("StaticRouterLSA::StaticRouterLSA ()"); + NS_DEBUG("GlobalRouterLSA::GlobalRouterLSA ()"); } -StaticRouterLSA::StaticRouterLSA ( - StaticRouterLSA::SPFStatus status, +GlobalRouterLSA::GlobalRouterLSA ( + GlobalRouterLSA::SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr) : @@ -145,21 +145,21 @@ StaticRouterLSA::StaticRouterLSA ( m_linkRecords(), m_status(status) { - NS_DEBUG("StaticRouterLSA::StaticRouterLSA (" << status << ", " << + NS_DEBUG("GlobalRouterLSA::GlobalRouterLSA (" << status << ", " << linkStateId << ", " << advertisingRtr << ")"); } -StaticRouterLSA::StaticRouterLSA (StaticRouterLSA& lsa) +GlobalRouterLSA::GlobalRouterLSA (GlobalRouterLSA& lsa) : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr), m_status(lsa.m_status) { NS_ASSERT_MSG(IsEmpty(), - "StaticRouterLSA::StaticRouterLSA (): Non-empty LSA in constructor"); + "GlobalRouterLSA::GlobalRouterLSA (): Non-empty LSA in constructor"); CopyLinkRecords (lsa); } - StaticRouterLSA& -StaticRouterLSA::operator= (const StaticRouterLSA& lsa) + GlobalRouterLSA& +GlobalRouterLSA::operator= (const GlobalRouterLSA& lsa) { m_linkStateId = lsa.m_linkStateId; m_advertisingRtr = lsa.m_advertisingRtr; @@ -171,14 +171,14 @@ StaticRouterLSA::operator= (const StaticRouterLSA& lsa) } void -StaticRouterLSA::CopyLinkRecords (const StaticRouterLSA& lsa) +GlobalRouterLSA::CopyLinkRecords (const GlobalRouterLSA& lsa) { for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin (); i != lsa.m_linkRecords.end (); i++) { - StaticRouterLinkRecord *pSrc = *i; - StaticRouterLinkRecord *pDst = new StaticRouterLinkRecord; + GlobalRouterLinkRecord *pSrc = *i; + GlobalRouterLinkRecord *pDst = new GlobalRouterLinkRecord; pDst->SetLinkType (pSrc->GetLinkType ()); pDst->SetLinkId (pSrc->GetLinkId ()); @@ -189,46 +189,46 @@ StaticRouterLSA::CopyLinkRecords (const StaticRouterLSA& lsa) } } -StaticRouterLSA::~StaticRouterLSA() +GlobalRouterLSA::~GlobalRouterLSA() { - NS_DEBUG("StaticRouterLSA::~StaticRouterLSA ()"); + NS_DEBUG("GlobalRouterLSA::~GlobalRouterLSA ()"); ClearLinkRecords (); } void -StaticRouterLSA::ClearLinkRecords(void) +GlobalRouterLSA::ClearLinkRecords(void) { for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); i != m_linkRecords.end (); i++) { - NS_DEBUG("StaticRouterLSA::ClearLinkRecords (): free link record"); + NS_DEBUG("GlobalRouterLSA::ClearLinkRecords (): free link record"); - StaticRouterLinkRecord *p = *i; + GlobalRouterLinkRecord *p = *i; delete p; p = 0; *i = 0; } - NS_DEBUG("StaticRouterLSA::ClearLinkRecords(): clear list"); + NS_DEBUG("GlobalRouterLSA::ClearLinkRecords(): clear list"); m_linkRecords.clear(); } uint32_t -StaticRouterLSA::AddLinkRecord (StaticRouterLinkRecord* lr) +GlobalRouterLSA::AddLinkRecord (GlobalRouterLinkRecord* lr) { m_linkRecords.push_back (lr); return m_linkRecords.size (); } uint32_t -StaticRouterLSA::GetNLinkRecords (void) const +GlobalRouterLSA::GetNLinkRecords (void) const { return m_linkRecords.size (); } - StaticRouterLinkRecord * -StaticRouterLSA::GetLinkRecord (uint32_t n) const + GlobalRouterLinkRecord * +GlobalRouterLSA::GetLinkRecord (uint32_t n) const { uint32_t j = 0; for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin (); @@ -240,54 +240,54 @@ StaticRouterLSA::GetLinkRecord (uint32_t n) const return *i; } } - NS_ASSERT_MSG(false, "StaticRouterLSA::GetLinkRecord (): invalid index"); + NS_ASSERT_MSG(false, "GlobalRouterLSA::GetLinkRecord (): invalid index"); return 0; } bool -StaticRouterLSA::IsEmpty (void) const +GlobalRouterLSA::IsEmpty (void) const { return m_linkRecords.size () == 0; } Ipv4Address -StaticRouterLSA::GetLinkStateId (void) const +GlobalRouterLSA::GetLinkStateId (void) const { return m_linkStateId; } void -StaticRouterLSA::SetLinkStateId (Ipv4Address addr) +GlobalRouterLSA::SetLinkStateId (Ipv4Address addr) { m_linkStateId = addr; } Ipv4Address -StaticRouterLSA::GetAdvertisingRouter (void) const +GlobalRouterLSA::GetAdvertisingRouter (void) const { return m_advertisingRtr; } void -StaticRouterLSA::SetAdvertisingRouter (Ipv4Address addr) +GlobalRouterLSA::SetAdvertisingRouter (Ipv4Address addr) { m_advertisingRtr = addr; } - StaticRouterLSA::SPFStatus -StaticRouterLSA::GetStatus (void) const + GlobalRouterLSA::SPFStatus +GlobalRouterLSA::GetStatus (void) const { return m_status; } void -StaticRouterLSA::SetStatus (StaticRouterLSA::SPFStatus status) +GlobalRouterLSA::SetStatus (GlobalRouterLSA::SPFStatus status) { m_status = status; } void -StaticRouterLSA::Print (std::ostream &os) const +GlobalRouterLSA::Print (std::ostream &os) const { os << "m_linkStateId = " << m_linkStateId << std::endl << "m_advertisingRtr = " << m_advertisingRtr << std::endl; @@ -296,14 +296,14 @@ StaticRouterLSA::Print (std::ostream &os) const i != m_linkRecords.end (); i++) { - StaticRouterLinkRecord *p = *i; + GlobalRouterLinkRecord *p = *i; os << "----------" << std::endl; os << "m_linkId = " << p->GetLinkId () << std::endl; os << "m_linkData = " << p->GetLinkData () << std::endl; } } -std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa) +std::ostream& operator<< (std::ostream& os, GlobalRouterLSA& lsa) { lsa.Print (os); return os; @@ -311,50 +311,50 @@ std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa) // --------------------------------------------------------------------------- // -// StaticRouter Implementation +// GlobalRouter Implementation // // --------------------------------------------------------------------------- -const InterfaceId StaticRouter::iid = - MakeInterfaceId ("StaticRouter", Object::iid); +const InterfaceId GlobalRouter::iid = + MakeInterfaceId ("GlobalRouter", Object::iid); -StaticRouter::StaticRouter (Ptr node) +GlobalRouter::GlobalRouter (Ptr node) : m_node(node), m_LSAs() { - NS_DEBUG("StaticRouter::StaticRouter ()"); - SetInterfaceId (StaticRouter::iid); + NS_DEBUG("GlobalRouter::GlobalRouter ()"); + SetInterfaceId (GlobalRouter::iid); m_routerId.Set(RoutingEnvironment::AllocateRouterId()); } -StaticRouter::~StaticRouter () +GlobalRouter::~GlobalRouter () { - NS_DEBUG("StaticRouter::~StaticRouter ()"); + NS_DEBUG("GlobalRouter::~GlobalRouter ()"); ClearLSAs(); } void -StaticRouter::ClearLSAs () +GlobalRouter::ClearLSAs () { - NS_DEBUG("StaticRouter::ClearLSAs ()"); + NS_DEBUG("GlobalRouter::ClearLSAs ()"); for ( ListOfLSAs_t::iterator i = m_LSAs.begin (); i != m_LSAs.end (); i++) { - NS_DEBUG("StaticRouter::ClearLSAs (): free LSA"); + NS_DEBUG("GlobalRouter::ClearLSAs (): free LSA"); - StaticRouterLSA *p = *i; + GlobalRouterLSA *p = *i; delete p; p = 0; *i = 0; } - NS_DEBUG("StaticRouter::ClearLSAs (): clear list"); + NS_DEBUG("GlobalRouter::ClearLSAs (): clear list"); m_LSAs.clear(); } Ipv4Address -StaticRouter::GetRouterId (void) const +GlobalRouter::GetRouterId (void) const { return m_routerId; } @@ -364,11 +364,11 @@ StaticRouter::GetRouterId (void) const // Advertisements that reflect them and their associated networks. // uint32_t -StaticRouter::DiscoverLSAs (void) +GlobalRouter::DiscoverLSAs (void) { - NS_DEBUG("StaticRouter::DiscoverLSAs ()"); + NS_DEBUG("GlobalRouter::DiscoverLSAs ()"); NS_ASSERT_MSG(m_node, - "StaticRouter::DiscoverLSAs (): interface not set"); + "GlobalRouter::DiscoverLSAs (): interface not set"); ClearLSAs (); // @@ -378,17 +378,17 @@ StaticRouter::DiscoverLSAs (void) // Ptr ipv4Local = m_node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4Local, - "StaticRouter::DiscoverLSAs (): QI for interface failed"); + "GlobalRouter::DiscoverLSAs (): QI for interface failed"); // // We are, for now at least, only going to report RouterLSAs in this method. // What this means is that there is going to be one advertisement with some // number of link records. This means that GetNumLSAs will actually always // return exactly one. // - StaticRouterLSA *pLSA = new StaticRouterLSA; + GlobalRouterLSA *pLSA = new GlobalRouterLSA; pLSA->SetLinkStateId (m_routerId); pLSA->SetAdvertisingRouter (m_routerId); - pLSA->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); + pLSA->SetStatus (GlobalRouterLSA::LSA_SPF_NOT_EXPLORED); // // We need to ask the node for the number of net devices attached. This isn't // necessarily equal to the number of links to adjacent nodes (other routers) @@ -398,7 +398,7 @@ StaticRouter::DiscoverLSAs (void) // a point-to-point channel. // uint32_t numDevices = m_node->GetNDevices(); - NS_DEBUG("StaticRouter::DiscoverLSAs (): numDevices = " << numDevices); + NS_DEBUG("GlobalRouter::DiscoverLSAs (): numDevices = " << numDevices); // // Loop through the devices looking for those connected to a point-to-point // channel. @@ -409,11 +409,11 @@ StaticRouter::DiscoverLSAs (void) if (!ndLocal->IsPointToPoint ()) { - NS_DEBUG("StaticRouter::DiscoverLSAs (): non-point-to-point device"); + NS_DEBUG("GlobalRouter::DiscoverLSAs (): non-point-to-point device"); continue; } - NS_DEBUG("StaticRouter::DiscoverLSAs (): Point-to-point device"); + NS_DEBUG("GlobalRouter::DiscoverLSAs (): Point-to-point device"); // // Now, we have to find the Ipv4 interface whose netdevice is the one we // just found. This is still the IP on the local side of the channel. There @@ -442,15 +442,15 @@ StaticRouter::DiscoverLSAs (void) Ptr nodeRemote = ndRemote->GetNode(); Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4Remote, - "StaticRouter::DiscoverLSAs (): QI for remote failed"); + "GlobalRouter::DiscoverLSAs (): QI for remote failed"); // // Per the OSPF spec, we're going to need the remote router ID, so we might as // well get it now. // - Ptr srRemote = - nodeRemote->QueryInterface (StaticRouter::iid); + Ptr srRemote = + nodeRemote->QueryInterface (GlobalRouter::iid); NS_ASSERT_MSG(srRemote, - "StaticRouter::DiscoverLSAs (): QI for remote failed"); + "GlobalRouter::DiscoverLSAs (): QI for remote failed"); Ipv4Address rtrIdRemote = srRemote->GetRouterId(); NS_DEBUG("Working with remote router " << rtrIdRemote); // @@ -470,15 +470,15 @@ StaticRouter::DiscoverLSAs (void) // link records; the first is a point-to-point record describing the link and // the second is a stub network record with the network number. // - StaticRouterLinkRecord *plr = new StaticRouterLinkRecord; - plr->SetLinkType (StaticRouterLinkRecord::PointToPoint); + GlobalRouterLinkRecord *plr = new GlobalRouterLinkRecord; + plr->SetLinkType (GlobalRouterLinkRecord::PointToPoint); plr->SetLinkId (rtrIdRemote); plr->SetLinkData (addrLocal); pLSA->AddLinkRecord(plr); plr = 0; - plr = new StaticRouterLinkRecord; - plr->SetLinkType (StaticRouterLinkRecord::StubNetwork); + plr = new GlobalRouterLinkRecord; + plr->SetLinkType (GlobalRouterLinkRecord::StubNetwork); plr->SetLinkId (addrRemote); plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown pLSA->AddLinkRecord(plr); @@ -493,9 +493,9 @@ StaticRouter::DiscoverLSAs (void) } uint32_t -StaticRouter::GetNumLSAs (void) const +GlobalRouter::GetNumLSAs (void) const { - NS_DEBUG("StaticRouter::GetNumLSAs ()"); + NS_DEBUG("GlobalRouter::GetNumLSAs ()"); return m_LSAs.size (); } @@ -503,9 +503,9 @@ StaticRouter::GetNumLSAs (void) const // Get the nth link state advertisement from this router. // bool -StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) const +GlobalRouter::GetLSA (uint32_t n, GlobalRouterLSA &lsa) const { - NS_ASSERT_MSG(lsa.IsEmpty(), "StaticRouter::GetLSA (): Must pass empty LSA"); + NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA"); // // All of the work was done in GetNumLSAs. All we have to do here is to // walk the list of link state advertisements created there and return the @@ -518,7 +518,7 @@ StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) const { if (j == n) { - StaticRouterLSA *p = *i; + GlobalRouterLSA *p = *i; lsa = *p; return true; } @@ -532,7 +532,7 @@ StaticRouter::GetLSA (uint32_t n, StaticRouterLSA &lsa) const // other end. This only makes sense with a point-to-point channel. // Ptr -StaticRouter::GetAdjacent(Ptr nd, Ptr ch) const +GlobalRouter::GetAdjacent(Ptr nd, Ptr ch) const { // // Double-check that channel agrees with device that it's a point-to-point @@ -541,7 +541,7 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) const uint32_t nDevices = ch->GetNDevices(); NS_ASSERT_MSG(nDevices == 2, - "StaticRouter::GetAdjacent (): Channel with other than two devices"); + "GlobalRouter::GetAdjacent (): Channel with other than two devices"); // // This is a point to point channel with two endpoints. Get both of them. // @@ -563,7 +563,7 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) const else { NS_ASSERT_MSG(false, - "StaticRouter::GetAdjacent (): Wrong or confused channel?"); + "GlobalRouter::GetAdjacent (): Wrong or confused channel?"); return 0; } } @@ -573,7 +573,7 @@ StaticRouter::GetAdjacent(Ptr nd, Ptr ch) const // corresponds to that net device. // uint32_t -StaticRouter::FindIfIndexForDevice(Ptr node, Ptr nd) const +GlobalRouter::FindIfIndexForDevice(Ptr node, Ptr nd) const { Ptr ipv4 = node->QueryInterface (Ipv4::iid); NS_ASSERT_MSG(ipv4, "QI for interface failed"); diff --git a/src/routing/static-router.h b/src/routing/global/global-router-interface.h similarity index 72% rename from src/routing/static-router.h rename to src/routing/global/global-router-interface.h index 9465c1319..fed346b49 100644 --- a/src/routing/static-router.h +++ b/src/routing/global/global-router-interface.h @@ -15,8 +15,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef STATIC_ROUTER_H -#define STATIC_ROUTER_H +#ifndef GLOBAL_ROUTER_H +#define GLOBAL_ROUTER_H #include #include @@ -32,16 +32,16 @@ namespace ns3 { /** * @brief A single link record for a link state advertisement. * - * The StaticRouterLinkRecord is modeled after the OSPF link record field of + * The GlobalRouterLinkRecord is modeled after the OSPF link record field of * a Link State Advertisement. Right now we will only see two types of link * records corresponding to a stub network and a point-to-point link (channel). */ -class StaticRouterLinkRecord +class GlobalRouterLinkRecord { public: /** * @enum LinkType - * @brief Enumeration of the possible types of Static Router Link Records. + * @brief Enumeration of the possible types of Global Router Link Records. * * These values are defined in the OSPF spec. We currently only use * PointToPoint and StubNetwork types. @@ -54,15 +54,15 @@ public: VirtualLink /**< Unused -- for future OSPF compatibility */ }; /** - * @brief Construct an empty ("uninitialized") Static Router Link Record. + * @brief Construct an empty ("uninitialized") Global Router Link Record. * * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0"; * The Link Type is set to Unknown; * The metric is set to 0. */ - StaticRouterLinkRecord (); + GlobalRouterLinkRecord (); /** - * Construct an initialized Static Router Link Record. + * Construct an initialized Global Router Link Record. * * @param linkType The type of link record to construct. * @param linkId The link ID for the record. @@ -72,19 +72,19 @@ public: * @see SetLinkId * @see SetLinkData */ - StaticRouterLinkRecord ( + GlobalRouterLinkRecord ( LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, uint32_t metric); /** - * @brief Destroy a Static Router Link Record. + * @brief Destroy a Global Router Link Record. * * Currently does nothing. Here as a placeholder only. */ - ~StaticRouterLinkRecord (); + ~GlobalRouterLinkRecord (); /** - * Get the Link ID field of the Static Router Link Record. + * Get the Link ID field of the Global Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID * of the neighboring router. @@ -96,7 +96,7 @@ public: */ Ipv4Address GetLinkId(void) const; /** - * @brief Set the Link ID field of the Static Router Link Record. + * @brief Set the Link ID field of the Global Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID * of the neighboring router. @@ -108,7 +108,7 @@ public: */ void SetLinkId(Ipv4Address addr); /** - * @brief Get the Link Data field of the Static Router Link Record. + * @brief Get the Link Data field of the Global Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP * address of the node of the local side of the link. @@ -120,7 +120,7 @@ public: */ Ipv4Address GetLinkData(void) const; /** - * @brief Set the Link Data field of the Static Router Link Record. + * @brief Set the Link Data field of the Global Router Link Record. * * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP * address of the node of the local side of the link. @@ -132,27 +132,27 @@ public: */ void SetLinkData(Ipv4Address addr); /** - * @brief Get the Link Type field of the Static Router Link Record. + * @brief Get the Link Type field of the Global Router Link Record. * * The Link Type describes the kind of link a given record represents. The * values are defined by OSPF. * * @see LinkType - * @returns The LinkType of the current Static Router Link Record. + * @returns The LinkType of the current Global Router Link Record. */ LinkType GetLinkType(void) const; /** - * @brief Set the Link Type field of the Static Router Link Record. + * @brief Set the Link Type field of the Global Router Link Record. * * The Link Type describes the kind of link a given record represents. The * values are defined by OSPF. * * @see LinkType - * @param linkType The new LinkType for the current Static Router Link Record. + * @param linkType The new LinkType for the current Global Router Link Record. */ void SetLinkType(LinkType linkType); /** - * @brief Get the Metric Data field of the Static Router Link Record. + * @brief Get the Metric Data field of the Global Router Link Record. * * The metric is an abstract cost associated with forwarding a packet across * a link. A sum of metrics must have a well-defined meaning. That is, you @@ -160,11 +160,11 @@ public: * two hops relate to the cost of sending a packet); rather you should use * something like delay. * - * @returns The metric field of the Static Router Link Record. + * @returns The metric field of the Global Router Link Record. */ uint32_t GetMetric(void) const; /** - * @brief Set the Metric Data field of the Static Router Link Record. + * @brief Set the Metric Data field of the Global Router Link Record. * * The metric is an abstract cost associated with forwarding a packet across * a link. A sum of metrics must have a well-defined meaning. That is, you @@ -172,7 +172,7 @@ public: * two hops relate to the cost of sending a packet); rather you should use * something like delay. * - * @param metric The new metric for the current Static Router Link Record. + * @param metric The new metric for the current Global Router Link Record. */ void SetMetric(uint32_t metric); @@ -199,7 +199,7 @@ private: */ Ipv4Address m_linkData; // for links to RouterLSA, /** - * The type of the Static Router Link Record. Defined in the OSPF spec. + * The type of the Global Router Link Record. Defined in the OSPF spec. * We currently only use PointToPoint and StubNetwork types. */ LinkType m_linkType; @@ -216,14 +216,14 @@ private: }; /** - * @brief a Link State Advertisement (LSA) for a router, used in static + * @brief a Link State Advertisement (LSA) for a router, used in global * routing. * - * Roughly equivalent to a static incarnation of the OSPF link state header - * combined with a list of Link Records. Since it's static, there's + * Roughly equivalent to a global incarnation of the OSPF link state header + * combined with a list of Link Records. Since it's global, there's * no need for age or sequence number. See RFC 2328, Appendix A. */ -class StaticRouterLSA +class GlobalRouterLSA { public: /** @@ -237,14 +237,14 @@ public: LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */ }; /** - * @brief Create a blank Static Router Link State Advertisement. + * @brief Create a blank Global Router Link State Advertisement. * * On completion Ipv4Address variables initialized to 0.0.0.0 and the * list of Link State Records is empty. */ - StaticRouterLSA(); + GlobalRouterLSA(); /** - * @brief Create an initialized Static Router Link State Advertisement. + * @brief Create an initialized Global Router Link State Advertisement. * * On completion the list of Link State Records is empty. * @@ -252,38 +252,38 @@ public: * @param linkStateId The Ipv4Address for the link state ID field. * @param advertisingRtr The Ipv4Address for the advertising router field. */ - StaticRouterLSA(SPFStatus status, Ipv4Address linkStateId, + GlobalRouterLSA(SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr); /** - * @brief Copy constructor for a Static Router Link State Advertisement. + * @brief Copy constructor for a Global Router Link State Advertisement. * * Takes a piece of memory and constructs a semantically identical copy of * the given LSA. * * @param lsa The existing LSA to be used as the source. */ - StaticRouterLSA (StaticRouterLSA& lsa); + GlobalRouterLSA (GlobalRouterLSA& lsa); /** - * @brief Destroy an existing Static Router Link State Advertisement. + * @brief Destroy an existing Global Router Link State Advertisement. * - * Any Static Router Link Records present in the list are freed. + * Any Global Router Link Records present in the list are freed. */ - ~StaticRouterLSA(); + ~GlobalRouterLSA(); /** - * @brief Assignment operator for a Static Router Link State Advertisement. + * @brief Assignment operator for a Global Router Link State Advertisement. * - * Takes an existing Static Router Link State Advertisement and overwrites + * Takes an existing Global Router Link State Advertisement and overwrites * it to make a semantically identical copy of a given prototype LSA. * - * If there are any Static Router Link Records present in the existing + * If there are any Global Router Link Records present in the existing * LSA, they are freed before the assignment happens. * * @param lsa The existing LSA to be used as the source. * @returns Reference to the overwritten LSA. */ - StaticRouterLSA& operator= (const StaticRouterLSA& lsa); + GlobalRouterLSA& operator= (const GlobalRouterLSA& lsa); /** - * @brief Copy any Static Router Link Records in a given Static Router Link + * @brief Copy any Global Router Link Records in a given Global Router Link * State Advertisement to the current LSA. * * Existing Link Records are not deleted -- this is a concatenation of Link @@ -292,42 +292,42 @@ public: * @see ClearLinkRecords () * @param lsa The LSA to copy the Link Records from. */ - void CopyLinkRecords (const StaticRouterLSA& lsa); + void CopyLinkRecords (const GlobalRouterLSA& lsa); /** - * @brief Add a given Static Router Link Record to the LSA. + * @brief Add a given Global Router Link Record to the LSA. * - * @param lr The Static Router Link Record to be added. + * @param lr The Global Router Link Record to be added. * @returns The number of link records in the list. */ - uint32_t AddLinkRecord (StaticRouterLinkRecord* lr); + uint32_t AddLinkRecord (GlobalRouterLinkRecord* lr); /** - * @brief Return the number of Static Router Link Records in the LSA. + * @brief Return the number of Global Router Link Records in the LSA. * * @returns The number of link records in the list. */ uint32_t GetNLinkRecords (void) const; /** - * @brief Return a pointer to the specified Static Router Link Record. + * @brief Return a pointer to the specified Global Router Link Record. * * @param n The LSA number desired. * @returns The number of link records in the list. */ - StaticRouterLinkRecord* GetLinkRecord (uint32_t n) const; + GlobalRouterLinkRecord* GetLinkRecord (uint32_t n) const; /** - * @brief Release all of the Static Router Link Records present in the Static + * @brief Release all of the Global Router Link Records present in the Global * Router Link State Advertisement and make the list of link records empty. */ void ClearLinkRecords(void); /** - * @brief Check to see if the list of Static Router Link Records present in the - * Static Router Link State Advertisement is empty. + * @brief Check to see if the list of Global Router Link Records present in the + * Global Router Link State Advertisement is empty. * * @returns True if the list is empty, false otherwise. */ bool IsEmpty(void) const; /** - * @brief Print the contents of the Static Router Link State Advertisement and - * any Static Router Link Records present in the list. Quite verbose. + * @brief Print the contents of the Global Router Link State Advertisement and + * any Global Router Link Records present in the list. Quite verbose. */ void Print (std::ostream &os) const; /** @@ -335,7 +335,7 @@ public: * to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () + * @see GlobalRouter::GetRouterId () * @returns The Ipv4Address stored as the link state ID. */ Ipv4Address GetLinkStateId (void) const; @@ -344,7 +344,7 @@ public: * to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () + * @see GlobalRouter::GetRouterId () */ void SetLinkStateId (Ipv4Address addr); /** @@ -352,7 +352,7 @@ public: * set it to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () + * @see GlobalRouter::GetRouterId () * @returns The Ipv4Address stored as the advetising router. */ Ipv4Address GetAdvertisingRouter (void) const; @@ -361,7 +361,7 @@ public: * set it to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () + * @see GlobalRouter::GetRouterId () */ void SetAdvertisingRouter (Ipv4Address rtr); /** @@ -384,7 +384,7 @@ private: * router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () + * @see GlobalRouter::GetRouterId () */ Ipv4Address m_linkStateId; /** @@ -392,13 +392,13 @@ private: * the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see StaticRouter::GetRouterId () + * @see GlobalRouter::GetRouterId () */ Ipv4Address m_advertisingRtr; /** * A convenience typedef to avoid too much writers cramp. */ - typedef std::list ListOfLinkRecords_t; + typedef std::list ListOfLinkRecords_t; /** * Each Link State Advertisement contains a number of Link Records that * describe the kinds of links that are attached to a given node. We @@ -407,7 +407,7 @@ private: * m_linkRecords is an STL list container to hold the Link Records that have * been discovered and prepared for the advertisement. * - * @see StaticRouter::DiscoverLSAs () + * @see GlobalRouter::DiscoverLSAs () */ ListOfLinkRecords_t m_linkRecords; /** @@ -419,99 +419,99 @@ private: SPFStatus m_status; }; -std::ostream& operator<< (std::ostream& os, StaticRouterLSA& lsa); +std::ostream& operator<< (std::ostream& os, GlobalRouterLSA& lsa); /** - * @brief An interface aggregated to a node to provide static routing info + * @brief An interface aggregated to a node to provide global routing info * - * An interface aggregated to a node that provides static routing information + * An interface aggregated to a node that provides global routing information * to a global route manager. The presence of the interface indicates that * the node is a router. The interface is the mechanism by which the router * advertises its connections to neighboring routers. We're basically * allowing the route manager to query for link state advertisements. */ -class StaticRouter : public Object +class GlobalRouter : public Object { public: /** - * @brief The Interface ID of the Static Router interface. + * @brief The Interface ID of the Global Router interface. * * @see Object::QueryInterface () */ static const InterfaceId iid; /** - * @brief Create a Static Router class and aggregate its interface onto the + * @brief Create a Global Router class and aggregate its interface onto the * Node provided. * * @param node The existing Node onto which this router will be aggregated. */ - StaticRouter (Ptr node); + GlobalRouter (Ptr node); /** - * @brief Get the Router ID associated with this Static Router. + * @brief Get the Router ID associated with this Global Router. * * The Router IDs are allocated in the RoutingEnvironment -- one per Router, * starting at 0.0.0.1 and incrementing with each instantiation of a router. * * @see RoutingEnvironment::AllocateRouterId () - * @returns The Router ID associated with the Static Router. + * @returns The Router ID associated with the Global Router. */ Ipv4Address GetRouterId (void) const; /** * @brief Walk the connected channels, discover the adjacent routers and build - * the associated number of Static Router Link State Advertisements that + * the associated number of Global Router Link State Advertisements that * this router can export. * * This is a fairly expensive operation in that every time it is called * the current list of LSAs is built by walking connected point-to-point * channels and peeking into adjacent IPV4 stacks to get address information. - * This is done to allow for limited dymanics of the Static Routing + * This is done to allow for limited dymanics of the Global Routing * environment. By that we mean that you can discover new link state * advertisements after a network topology change by calling DiscoverLSAs * and then by reading those advertisements. * - * @see StaticRouterLSA - * @see StaticRouter::GetLSA () - * @returns The number of Static Router Link State Advertisements. + * @see GlobalRouterLSA + * @see GlobalRouter::GetLSA () + * @returns The number of Global Router Link State Advertisements. */ uint32_t DiscoverLSAs (void); /** - * @brief Get the Number of Static Router Link State Advertisements that this + * @brief Get the Number of Global Router Link State Advertisements that this * router can export. * * To get meaningful information you must have previously called DiscoverLSAs. * After you know how many LSAs are present in the router, you may call * GetLSA () to retrieve the actual advertisement. * - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @see StaticRouter::GetLSA () - * @returns The number of Static Router Link State Advertisements. + * @see GlobalRouterLSA + * @see GlobalRouter::DiscoverLSAs () + * @see GlobalRouter::GetLSA () + * @returns The number of Global Router Link State Advertisements. */ uint32_t GetNumLSAs (void) const; /** - * @brief Get a Static Router Link State Advertisements that this router has + * @brief Get a Global Router Link State Advertisements that this router has * said that it can export. * * This is a fairly inexpensive expensive operation in that the hard work - * was done in GetNumLSAs. We just copy the indicated Static Router Link - * State Advertisement into the requested StaticRouterLSA object. + * was done in GetNumLSAs. We just copy the indicated Global Router Link + * State Advertisement into the requested GlobalRouterLSA object. * - * You must call StaticRouter::GetNumLSAs before calling this method in + * You must call GlobalRouter::GetNumLSAs before calling this method in * order to discover the adjacent routers and build the advertisements. * GetNumLSAs will return the number of LSAs this router advertises. * The parameter n (requested LSA number) must be in the range 0 to * GetNumLSAs() - 1. * - * @see StaticRouterLSA - * @see StaticRouter::GetNumLSAs () + * @see GlobalRouterLSA + * @see GlobalRouter::GetNumLSAs () * @param n The index number of the LSA you want to read. - * @param lsa The StaticRouterLSA class to receive the LSA information. - * @returns The number of Static Router Link State Advertisements. + * @param lsa The GlobalRouterLSA class to receive the LSA information. + * @returns The number of Global Router Link State Advertisements. */ - bool GetLSA (uint32_t n, StaticRouterLSA &lsa) const; + bool GetLSA (uint32_t n, GlobalRouterLSA &lsa) const; protected: - virtual ~StaticRouter (); + virtual ~GlobalRouter (); void ClearLSAs (void); Ptr GetAdjacent(Ptr nd, Ptr ch) const; @@ -519,22 +519,22 @@ protected: Ptr m_node; - typedef std::list ListOfLSAs_t; + typedef std::list ListOfLSAs_t; ListOfLSAs_t m_LSAs; Ipv4Address m_routerId; private: /** - * @brief Static Router copy construction is disallowed. + * @brief Global Router copy construction is disallowed. */ - StaticRouter (StaticRouter& sr); + GlobalRouter (GlobalRouter& sr); /** - * @brief Static Router assignment operator is disallowed. + * @brief Global Router assignment operator is disallowed. */ - StaticRouter& operator= (StaticRouter& sr); + GlobalRouter& operator= (GlobalRouter& sr); }; } // namespace ns3 -#endif /* STATIC_ROUTER_H */ +#endif /* GLOBAL_ROUTER_H */ diff --git a/src/routing/routing-environment.cc b/src/routing/global/routing-environment.cc similarity index 85% rename from src/routing/routing-environment.cc rename to src/routing/global/routing-environment.cc index 33eeafbe5..ca075512c 100644 --- a/src/routing/routing-environment.cc +++ b/src/routing/global/routing-environment.cc @@ -26,13 +26,13 @@ NS_DEBUG_COMPONENT_DEFINE ("RoutingEnvironment"); namespace ns3 { namespace RoutingEnvironment { -BooleanDefaultValue g_doStaticRoutingDefaultValue ("DoStaticRouting", - "Enable global static routing", false); +BooleanDefaultValue g_doGlobalRoutingDefaultValue ("DoGlobalRouting", + "Enable global global routing", false); bool -StaticRoutingEnabled(void) +GlobalRoutingEnabled(void) { - return g_doStaticRoutingDefaultValue.GetValue(); + return g_doGlobalRoutingDefaultValue.GetValue(); } uint32_t diff --git a/src/routing/routing-environment.h b/src/routing/global/routing-environment.h similarity index 97% rename from src/routing/routing-environment.h rename to src/routing/global/routing-environment.h index b233c821a..5b305a0e3 100644 --- a/src/routing/routing-environment.h +++ b/src/routing/global/routing-environment.h @@ -23,14 +23,15 @@ namespace ns3 { namespace RoutingEnvironment { - + /** * @brief This function tests the value of the global default value * "DoStaticRouting". This approach puts everything in one compilation * unit, as opposed to explicitly testing the value of the underlying * static variable. */ -bool StaticRoutingEnabled(void); +bool GlobalRoutingEnabled(void); + /** * @brief Allocate a 32-bit router ID from monotonically increasing counter. */ diff --git a/src/routing/wscript b/src/routing/wscript deleted file mode 100644 index 8cdee7644..000000000 --- a/src/routing/wscript +++ /dev/null @@ -1,26 +0,0 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-routing') - - -def build(bld): - module = bld.create_obj('cpp', 'shlib') - module.name = 'ns3-routing' - module.target = module.name - module.uselib_local = ['ns3-node'] - module.source = [ - 'routing-environment.cc', - 'static-router.cc', - 'static-route-manager.cc', - 'static-route-manager-impl.cc', - 'candidate-queue.cc', - ] - - headers = bld.create_obj('ns3header') - headers.source = [ - 'routing-environment.h', - 'static-router.h', - 'static-route-manager.h', - 'candidate-queue.h', - ] diff --git a/src/wscript b/src/wscript index 33032283b..9f6a7a2be 100644 --- a/src/wscript +++ b/src/wscript @@ -17,7 +17,7 @@ all_modules = [ 'internet-node', 'devices/p2p', 'applications', - 'routing', + 'routing/global', ] From ef462dbb5e4e03862b0b6ed64c853d74c5517e98 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 27 Jul 2007 14:09:02 -0700 Subject: [PATCH 100/278] copywrongs --- examples/simple-static-routing.cc | 190 ------------------ .../global/global-route-manager-impl.h | 1 + src/routing/global/global-router-interface.h | 1 - src/routing/global/routing-environment.cc | 2 - src/routing/global/routing-environment.h | 1 + 5 files changed, 2 insertions(+), 193 deletions(-) delete mode 100644 examples/simple-static-routing.cc diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc deleted file mode 100644 index 9a7d66dcf..000000000 --- a/examples/simple-static-routing.cc +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ns-2 simple.tcl script (ported from ns-2) - * Originally authored by Steve McCanne, 12/19/1996 - */ - -// Port of ns-2/tcl/ex/simple.tcl to ns-3 -// -// Network topology -// -// n0 -// \ 5 Mb/s, 2ms -// \ 1.5Mb/s, 10ms -// n2 -------------------------n3 -// / -// / 5 Mb/s, 2ms -// n1 -// -// - all links are point-to-point links with indicated one-way BW/delay -// - CBR/UDP flows from n0 to n3, and from n3 to n1 -// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. -// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. -// (i.e., DataRate of 448,000 bps) -// - DropTail queues -// - Tracing of queues and packet receptions to file "simple-static-routing.tr" - -#include -#include -#include -#include - -#include "ns3/debug.h" - -#include "ns3/command-line.h" -#include "ns3/default-value.h" -#include "ns3/ptr.h" -#include "ns3/random-variable.h" - -#include "ns3/simulator.h" -#include "ns3/nstime.h" -#include "ns3/data-rate.h" - -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" -#include "ns3/internet-node.h" -#include "ns3/p2p-channel.h" -#include "ns3/p2p-net-device.h" -#include "ns3/mac-address.h" -#include "ns3/ipv4-address.h" -#include "ns3/ipv4.h" -#include "ns3/socket.h" -#include "ns3/ipv4-route.h" -#include "ns3/p2p-topology.h" -#include "ns3/onoff-application.h" -#include "ns3/routing-environment.h" -#include "ns3/static-route-manager.h" - -using namespace ns3; - -int main (int argc, char *argv[]) -{ - - // Users may find it convenient to turn on explicit debugging - // for selected modules; the below lines suggest how to do this -#if 0 - DebugComponentEnable ("Object"); - DebugComponentEnable ("Queue"); - DebugComponentEnable ("DropTailQueue"); - DebugComponentEnable ("Channel"); - DebugComponentEnable ("PointToPointChannel"); - DebugComponentEnable ("PointToPointNetDevice"); - DebugComponentEnable ("StaticRouter"); - DebugComponentEnable ("StaticRouteManager"); -#endif - - // Set up some default values for the simulation. Use the Bind () - // technique to tell the system what subclass of Queue to use, - // and what the queue limit is - - // The below Bind command tells the queue factory which class to - // instantiate, when the queue factory is invoked in the topology code - Bind ("Queue", "DropTailQueue"); - - // This bind tells the system to use global static routing. It results in - // a StaticRouter interface being aggregated to the internet nodes and the - // creation of a Route Manager component to oversee the route generation. - Bind ("DoStaticRouting", "true"); - - Bind ("OnOffApplicationPacketSize", "210"); - Bind ("OnOffApplicationDataRate", "448kb/s"); - - //Bind ("DropTailQueue::m_maxPackets", 30); - - // Allow the user to override any of the defaults and the above - // Bind ()s at run-time, via command-line arguments - CommandLine::Parse (argc, argv); - - // Here, we will explicitly create four nodes. In more sophisticated - // topologies, we could configure a node factory. - Ptr n0 = Create (); - Ptr n1 = Create (); - Ptr n2 = Create (); - Ptr n3 = Create (); - - // We create the channels first without any IP addressing information - Ptr channel0 = - PointToPointTopology::AddPointToPointLink ( - n0, n2, DataRate (5000000), MilliSeconds (2)); - - Ptr channel1 = - PointToPointTopology::AddPointToPointLink ( - n1, n2, DataRate (5000000), MilliSeconds (2)); - - Ptr channel2 = - PointToPointTopology::AddPointToPointLink ( - n2, n3, DataRate (1500000), MilliSeconds (10)); - - // Later, we add IP addresses. - PointToPointTopology::AddIpv4Addresses ( - channel0, n0, Ipv4Address ("10.1.1.1"), - n2, Ipv4Address ("10.1.1.2")); - - PointToPointTopology::AddIpv4Addresses ( - channel1, n1, Ipv4Address ("10.1.2.1"), - n2, Ipv4Address ("10.1.2.2")); - - PointToPointTopology::AddIpv4Addresses ( - channel2, n2, Ipv4Address ("10.1.3.1"), - n3, Ipv4Address ("10.1.3.2")); - - if (RoutingEnvironment::StaticRoutingEnabled ()) - { - StaticRouteManager::PopulateRoutingTables (); - } - - // Create the OnOff application to send UDP datagrams of size - // 210 bytes at a rate of 448 Kb/s - Ptr ooff = Create ( - n0, - Ipv4Address ("10.1.3.2"), - 80, - "Udp", - ConstantVariable (1), - ConstantVariable (0)); - // Start the application - ooff->Start (Seconds (1.0)); - ooff->Stop (Seconds (10.0)); - - // Create a similar flow from n3 to n1, starting at time 1.1 seconds - ooff = Create ( - n3, - Ipv4Address ("10.1.2.1"), - 80, - "Udp", - ConstantVariable (1), - ConstantVariable (0)); - // Start the application - ooff->Start (Seconds (1.1)); - ooff->Stop (Seconds (10.0)); - - // Configure tracing of all enqueue, dequeue, and NetDevice receive events - // Trace output will be sent to the simple-static-routing.tr file - AsciiTrace asciitrace ("simple-static-routing.tr"); - asciitrace.TraceAllQueues (); - asciitrace.TraceAllNetDeviceRx (); - - // Also configure some tcpdump traces; each interface will be traced - // The output files will be named simple-p2p.pcap-- - // and can be read by the "tcpdump -r" command (use "-tt" option to - // display timestamps correctly) - PcapTrace pcaptrace ("simple-static-routing.pcap"); - pcaptrace.TraceAllIp (); - - Simulator::Run (); - - Simulator::Destroy (); -} diff --git a/src/routing/global/global-route-manager-impl.h b/src/routing/global/global-route-manager-impl.h index a355cdfb0..ee9ad5b3b 100644 --- a/src/routing/global/global-route-manager-impl.h +++ b/src/routing/global/global-route-manager-impl.h @@ -13,6 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef GLOBAL_ROUTE_MANAGER_IMPL_H #define GLOBAL_ROUTE_MANAGER_IMPL_H diff --git a/src/routing/global/global-router-interface.h b/src/routing/global/global-router-interface.h index fed346b49..c1d2f5bad 100644 --- a/src/routing/global/global-router-interface.h +++ b/src/routing/global/global-router-interface.h @@ -1,4 +1,3 @@ - /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * This program is free software; you can redistribute it and/or modify diff --git a/src/routing/global/routing-environment.cc b/src/routing/global/routing-environment.cc index ca075512c..cea926fc1 100644 --- a/src/routing/global/routing-environment.cc +++ b/src/routing/global/routing-environment.cc @@ -1,7 +1,5 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * All rights reserved. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; diff --git a/src/routing/global/routing-environment.h b/src/routing/global/routing-environment.h index 5b305a0e3..24c4450df 100644 --- a/src/routing/global/routing-environment.h +++ b/src/routing/global/routing-environment.h @@ -13,6 +13,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef ROUTING_ENVIRONMENT_H #define ROUTING_ENVIRONMENT_H From 510083f0ea4c8f7c527d7f04d58819785e33e57f Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 27 Jul 2007 20:34:25 -0700 Subject: [PATCH 101/278] remove routing environment, move router interface creation to global-route-manager --- src/internet-node/internet-node.cc | 13 ----- .../global/global-route-manager-impl.cc | 25 +++++++++ .../global/global-route-manager-impl.h | 51 ++++++++++++++++--- src/routing/global/global-route-manager.cc | 20 +++++++- src/routing/global/global-route-manager.h | 14 ++++- src/routing/global/global-router-interface.cc | 2 +- src/routing/global/global-router-interface.h | 2 +- src/routing/global/routing-environment.cc | 44 ---------------- src/routing/global/routing-environment.h | 44 ---------------- src/routing/global/wscript | 24 +++++++++ 10 files changed, 127 insertions(+), 112 deletions(-) delete mode 100644 src/routing/global/routing-environment.cc delete mode 100644 src/routing/global/routing-environment.h create mode 100644 src/routing/global/wscript diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index c6eb92f43..f7519a6a2 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -23,8 +23,6 @@ #include "ns3/composite-trace-resolver.h" #include "ns3/net-device.h" -#include "ns3/routing-environment.h" -#include "ns3/global-router-interface.h" #include "l3-demux.h" #include "ipv4-l4-demux.h" @@ -77,17 +75,6 @@ InternetNode::Construct (void) Object::AddInterface (udpImpl); Object::AddInterface (l3Demux); Object::AddInterface (ipv4L4Demux); -// -// If static routing has been enabled via bind(), all nodes will have the -// capacity to participate in the global static routing scheme. The presence -// of the StaticRouter interface tells the route manager that it needs to -// ask a given node about any link state records that it may want to advertise. -// - if (RoutingEnvironment::GlobalRoutingEnabled()) - { - Ptr globalRouter = Create (this); - Object::AddInterface (globalRouter); - } } TraceResolver * diff --git a/src/routing/global/global-route-manager-impl.cc b/src/routing/global/global-route-manager-impl.cc index df6ad3ad5..03578cb96 100644 --- a/src/routing/global/global-route-manager-impl.cc +++ b/src/routing/global/global-route-manager-impl.cc @@ -291,6 +291,31 @@ GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb) m_lsdb = lsdb; } +// +// In order to build the routing database, we need at least one of the nodes +// to participate as a router. Eventually we expect to provide a mechanism +// for selecting a subset of the nodes to participate; for now, we just make +// all nodes routers. We do this by walking the list of nodes in the system +// and aggregating a Global Router Interface to each of the nodes. +// + void +GlobalRouteManagerImpl::SelectRouterNodes () +{ + NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes ()"); + + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + { + Ptr node = *i; + NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes (): " + "Adding GlobalRouter interface to node " << + node->GetId ()); + + Ptr globalRouter = Create (node); + node->AddInterface (globalRouter); + } +} + // // In order to build the routing database, we need to walk the list of nodes // in the system and look for those that support the GlobalRouter interface. diff --git a/src/routing/global/global-route-manager-impl.h b/src/routing/global/global-route-manager-impl.h index ee9ad5b3b..87e64919b 100644 --- a/src/routing/global/global-route-manager-impl.h +++ b/src/routing/global/global-route-manager-impl.h @@ -71,6 +71,7 @@ public: VertexRouter, /**< Vertex representing a router in the topology */ VertexNetwork /**< Vertex representing a network in the topology */ }; + /** * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First * Vertex). @@ -85,6 +86,7 @@ public: * @see VertexType */ SPFVertex(); + /** * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). * @@ -101,6 +103,7 @@ public: * @param lsa The Link State Advertisement used for finding initial values. */ SPFVertex(GlobalRouterLSA* lsa); + /** * @brief Destroy an SPFVertex (Shortest Path First Vertex). * @@ -109,6 +112,7 @@ public: * @see SPFVertex::SPFVertex () */ ~SPFVertex(); + /** * @brief Get the Vertex Type field of a SPFVertex object. * @@ -119,6 +123,7 @@ public: * @returns The VertexType of the current SPFVertex object. */ VertexType GetVertexType (void) const; + /** * @brief Set the Vertex Type field of a SPFVertex object. * @@ -129,6 +134,7 @@ public: * @param type The new VertexType for the current SPFVertex object. */ void SetVertexType (VertexType type); + /** * @brief Get the Vertex ID field of a SPFVertex object. * @@ -143,6 +149,7 @@ public: * @returns The Ipv4Address Vertex ID of the current SPFVertex object. */ Ipv4Address GetVertexId (void) const; + /** * @brief Set the Vertex ID field of a SPFVertex object. * @@ -158,6 +165,7 @@ public: * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. */ void SetVertexId (Ipv4Address id); + /** * @brief Get the Global Router Link State Advertisement returned by the * Global Router represented by this SPFVertex during the route discovery @@ -170,6 +178,7 @@ public: * by this SPFVertex object. */ GlobalRouterLSA* GetLSA (void) const; + /** * @brief Set the Global Router Link State Advertisement returned by the * Global Router represented by this SPFVertex during the route discovery @@ -184,6 +193,7 @@ public: * @param lsa A pointer to the GlobalRouterLSA. */ void SetLSA (GlobalRouterLSA* lsa); + /** * @brief Get the distance from the root vertex to "this" SPFVertex object. * @@ -205,6 +215,7 @@ public: * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex. */ uint32_t GetDistanceFromRoot (void) const; + /** * @brief Set the distance from the root vertex to "this" SPFVertex object. * @@ -224,6 +235,7 @@ public: * SPFVertex. */ void SetDistanceFromRoot (uint32_t distance); + /** * @brief Get the interface ID that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. @@ -264,6 +276,7 @@ public: * or network represented by "this" SPFVertex. */ uint32_t GetOutgoingInterfaceId (void) const; + /** * @brief Set the interface ID that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. @@ -304,6 +317,7 @@ public: * network represented by "this" SPFVertex. */ void SetOutgoingInterfaceId (uint32_t id); + /** * @brief Get the IP address that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. @@ -345,6 +359,7 @@ public: * or network represented by "this" SPFVertex. */ Ipv4Address GetNextHop (void) const; + /** * @brief Set the IP address that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. @@ -386,6 +401,7 @@ public: * or network represented by "this" SPFVertex. */ void SetNextHop (Ipv4Address nextHop); + /** * @brief Get a pointer to the SPFVector that is the parent of "this" * SPFVertex. @@ -405,6 +421,7 @@ public: * in the SPF tree. */ SPFVertex* GetParent (void) const; + /** * @brief Set the pointer to the SPFVector that is the parent of "this" * SPFVertex. @@ -424,6 +441,7 @@ public: * SPFVertex* in the SPF tree. */ void SetParent (SPFVertex* parent); + /** * @brief Get the number of children of "this" SPFVertex. * @@ -444,6 +462,7 @@ public: * SPF tree). */ uint32_t GetNChildren (void) const; + /** * @brief Get a borrowed SPFVertex pointer to the specified child of "this" * SPFVertex. @@ -471,6 +490,7 @@ public: * SPF tree). */ SPFVertex* GetChild (uint32_t n) const; + /** * @brief Get a borrowed SPFVertex pointer to the specified child of "this" * SPFVertex. @@ -509,11 +529,13 @@ private: SPFVertex* m_parent; typedef std::list ListOfSPFVertex_t; ListOfSPFVertex_t m_children; + /** * @brief The SPFVertex copy construction is disallowed. There's no need for * it and a compiler provided shallow copy would be wrong. */ SPFVertex (SPFVertex& v); + /** * @brief The SPFVertex copy assignment operator is disallowed. There's no * need for it and a compiler provided shallow copy would be wrong. @@ -544,6 +566,7 @@ public: * this constructor. */ GlobalRouteManagerLSDB (); + /** * @brief Destroy an empty Global Router Manager Link State Database. * @@ -552,6 +575,7 @@ public: * release any remaining resources. */ ~GlobalRouteManagerLSDB (); + /** * @brief Insert an IP address / Link State Advertisement pair into the Link * State Database. @@ -566,6 +590,7 @@ public: * @param lsa A pointer to the Link State Advertisement for the router. */ void Insert(Ipv4Address addr, GlobalRouterLSA* lsa); + /** * @brief Look up the Link State Advertisement associated with the given * IP Address. @@ -581,6 +606,7 @@ public: * by the IP address addr. */ GlobalRouterLSA* GetLSA (Ipv4Address addr) const; + /** * @brief Set all LSA flags to an initialized state, for SPF computation * @@ -604,6 +630,7 @@ private: * need for it and a compiler provided shallow copy would be wrong. */ GlobalRouteManagerLSDB (GlobalRouteManagerLSDB& lsdb); + /** * @brief The SPFVertex copy assignment operator is disallowed. There's no * need for it and a compiler provided shallow copy would be wrong. @@ -627,25 +654,36 @@ class GlobalRouteManagerImpl public: GlobalRouteManagerImpl (); virtual ~GlobalRouteManagerImpl (); +/** + * @brief Select which nodes in the system are to be router nodes and + * aggregate the appropriate interfaces onto those nodes. + * + */ + virtual void SelectRouterNodes (); + /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a GlobalRouter interface. * */ - virtual void BuildGlobalRoutingDatabase(); + virtual void BuildGlobalRoutingDatabase (); + /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables */ - virtual void InitializeRoutes(); + virtual void InitializeRoutes (); + /** * @brief Debugging routine; allow client code to supply a pre-built LSDB */ void DebugUseLsdb (GlobalRouteManagerLSDB*); + /** * @brief Debugging routine; call the core SPF from the unit tests */ void DebugSPFCalculate (Ipv4Address root); + private: /** * @brief GlobalRouteManagerImpl copy construction is disallowed. @@ -653,6 +691,7 @@ private: * wrong. */ GlobalRouteManagerImpl (GlobalRouteManagerImpl& srmi); + /** * @brief Global Route Manager Implementation assignment operator is * disallowed. There's no need for it and a compiler provided shallow copy @@ -666,11 +705,11 @@ private: void SPFNext (SPFVertex*, CandidateQueue&); int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, GlobalRouterLinkRecord* l, uint32_t distance); - void SPFVertexAddParent(SPFVertex* v); - GlobalRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, + void SPFVertexAddParent (SPFVertex* v); + GlobalRouterLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w, GlobalRouterLinkRecord* prev_link); - void SPFIntraAddRouter(SPFVertex* v); - uint32_t FindOutgoingInterfaceId(Ipv4Address a); + void SPFIntraAddRouter (SPFVertex* v); + uint32_t FindOutgoingInterfaceId (Ipv4Address a); }; } // namespace ns3 diff --git a/src/routing/global/global-route-manager.cc b/src/routing/global/global-route-manager.cc index ce9e891c0..c166da015 100644 --- a/src/routing/global/global-route-manager.cc +++ b/src/routing/global/global-route-manager.cc @@ -31,22 +31,38 @@ namespace ns3 { void GlobalRouteManager::PopulateRoutingTables () { + SelectRouterNodes (); BuildGlobalRoutingDatabase (); InitializeRoutes (); } + void +GlobalRouteManager::SelectRouterNodes () +{ + SimulationSingleton::Get ()-> + SelectRouterNodes (); +} + void GlobalRouteManager::BuildGlobalRoutingDatabase () { - return SimulationSingleton::Get ()-> + SimulationSingleton::Get ()-> BuildGlobalRoutingDatabase (); } void GlobalRouteManager::InitializeRoutes () { - return SimulationSingleton::Get ()-> + SimulationSingleton::Get ()-> InitializeRoutes (); } + uint32_t +GlobalRouteManager::AllocateRouterId () +{ + static uint32_t routerId = 0; + return routerId++; +} + + } // namespace ns3 diff --git a/src/routing/global/global-route-manager.h b/src/routing/global/global-route-manager.h index 3a695dcdf..b4f8d53b8 100644 --- a/src/routing/global/global-route-manager.h +++ b/src/routing/global/global-route-manager.h @@ -14,7 +14,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef STATIC_ROUTE_MANAGER_H +#ifndef GLOBAL_ROUTE_MANAGER_H #define GLOBAL_ROUTE_MANAGER_H namespace ns3 { @@ -45,7 +45,19 @@ public: */ static void PopulateRoutingTables (); +/** + * @brief Allocate a 32-bit router ID from monotonically increasing counter. + */ + static uint32_t AllocateRouterId (); + private: +/** + * @brief Select which nodes in the system are to be router nodes and + * aggregate the appropriate interfaces onto those nodes. + * + */ + static void SelectRouterNodes (); + /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a GlobalRouter interface. diff --git a/src/routing/global/global-router-interface.cc b/src/routing/global/global-router-interface.cc index ff1f06318..7df422ec3 100644 --- a/src/routing/global/global-router-interface.cc +++ b/src/routing/global/global-router-interface.cc @@ -323,7 +323,7 @@ GlobalRouter::GlobalRouter (Ptr node) { NS_DEBUG("GlobalRouter::GlobalRouter ()"); SetInterfaceId (GlobalRouter::iid); - m_routerId.Set(RoutingEnvironment::AllocateRouterId()); + m_routerId.Set(GlobalRouteManager::AllocateRouterId ()); } GlobalRouter::~GlobalRouter () diff --git a/src/routing/global/global-router-interface.h b/src/routing/global/global-router-interface.h index c1d2f5bad..d5ddbb3e2 100644 --- a/src/routing/global/global-router-interface.h +++ b/src/routing/global/global-router-interface.h @@ -24,7 +24,7 @@ #include "ns3/node.h" #include "ns3/channel.h" #include "ns3/ipv4-address.h" -#include "ns3/routing-environment.h" +#include "ns3/global-route-manager.h" namespace ns3 { diff --git a/src/routing/global/routing-environment.cc b/src/routing/global/routing-environment.cc deleted file mode 100644 index cea926fc1..000000000 --- a/src/routing/global/routing-environment.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ns3/debug.h" -#include "ns3/default-value.h" - -#include "routing-environment.h" - -NS_DEBUG_COMPONENT_DEFINE ("RoutingEnvironment"); - -namespace ns3 { -namespace RoutingEnvironment { - -BooleanDefaultValue g_doGlobalRoutingDefaultValue ("DoGlobalRouting", - "Enable global global routing", false); - - bool -GlobalRoutingEnabled(void) -{ - return g_doGlobalRoutingDefaultValue.GetValue(); -} - - uint32_t -AllocateRouterId(void) -{ - static uint32_t routerId = 0; - return routerId++; -} - -} // namespace RoutingEnvironment -} // namespace ns3 diff --git a/src/routing/global/routing-environment.h b/src/routing/global/routing-environment.h deleted file mode 100644 index 24c4450df..000000000 --- a/src/routing/global/routing-environment.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef ROUTING_ENVIRONMENT_H -#define ROUTING_ENVIRONMENT_H - -#include -#include "ns3/object.h" -#include "ns3/ptr.h" -#include "ns3/ipv4-address.h" - -namespace ns3 { -namespace RoutingEnvironment { - -/** - * @brief This function tests the value of the global default value - * "DoStaticRouting". This approach puts everything in one compilation - * unit, as opposed to explicitly testing the value of the underlying - * static variable. - */ -bool GlobalRoutingEnabled(void); - -/** - * @brief Allocate a 32-bit router ID from monotonically increasing counter. - */ -uint32_t AllocateRouterId(void); - -} // namespace RoutingEnvironment -} // namespace ns3 - -#endif /* ROUTING_ENVIRONMENT_H */ diff --git a/src/routing/global/wscript b/src/routing/global/wscript new file mode 100644 index 000000000..130b633f2 --- /dev/null +++ b/src/routing/global/wscript @@ -0,0 +1,24 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def configure(conf): + conf.env.append_value('NS3_MODULES', 'ns3-routing') + + +def build(bld): + module = bld.create_obj('cpp', 'shlib') + module.name = 'ns3-routing' + module.target = module.name + module.uselib_local = ['ns3-node'] + module.source = [ + 'global-router-interface.cc', + 'global-route-manager.cc', + 'global-route-manager-impl.cc', + 'candidate-queue.cc', + ] + + headers = bld.create_obj('ns3header') + headers.source = [ + 'global-router-interface.h', + 'global-route-manager.h', + 'candidate-queue.h', + ] From b4698b7ccaff722497491241a009a9698b77dd45 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 27 Jul 2007 20:48:21 -0700 Subject: [PATCH 102/278] doxygen update (@internal) --- src/routing/global/candidate-queue.h | 202 ++++++++++-------- .../global/global-route-manager-impl.h | 32 ++- src/routing/global/global-route-manager.h | 3 + 3 files changed, 147 insertions(+), 90 deletions(-) diff --git a/src/routing/global/candidate-queue.h b/src/routing/global/candidate-queue.h index 1c01cb2ec..09b3a5c22 100644 --- a/src/routing/global/candidate-queue.h +++ b/src/routing/global/candidate-queue.h @@ -43,94 +43,117 @@ namespace ns3 { class CandidateQueue { public: - /** - * Create an empty SPF Candidate Queue. - * - * @see SPFVertex - */ +/** + * @brief Create an empty SPF Candidate Queue. + * @internal + * + * @see SPFVertex + */ CandidateQueue (); - /** - * Destroy an SPF Candidate Queue and release any resources held by the - * contents. - * - * @see SPFVertex - */ + +/** + * @internal Destroy an SPF Candidate Queue and release any resources held + * by the contents. + * @internal + * + * @see SPFVertex + */ virtual ~CandidateQueue (); - /** - * Empty the Candidate Queue and release all of the resources associated - * with the Shortest Path First Vertex pointers in the queue. - * - * @see SPFVertex - */ + +/** + * @brief Empty the Candidate Queue and release all of the resources + * associated with the Shortest Path First Vertex pointers in the queue. + * @internal + * + * @see SPFVertex + */ void Clear (void); - /** - * Push a Shortest Path First Vertex pointer onto the queue according to the - * priority scheme. - * - * On completion, the top of the queue will hold the Shortest Path First - * Vertex pointer that points to a vertex having lowest value of the field - * m_distanceFromRoot. Remaining vertices are ordered according to - * increasing distance. - * - * @see SPFVertex - * @param vNew The Shortest Path First Vertex to add to the queue. - */ + +/** + * @brief Push a Shortest Path First Vertex pointer onto the queue according + * to the priority scheme. + * @internal + * + * On completion, the top of the queue will hold the Shortest Path First + * Vertex pointer that points to a vertex having lowest value of the field + * m_distanceFromRoot. Remaining vertices are ordered according to + * increasing distance. + * + * @see SPFVertex + * @param vNew The Shortest Path First Vertex to add to the queue. + */ void Push (SPFVertex *vNew); - /** - * Pop the Shortest Path First Vertex pointer at the top of the queue. - * The caller is given the responsiblity for releasing the resources - * associated with the vertex. - * - * @see SPFVertex - * @see Top () - * @returns The Shortest Path First Vertex pointer at the top of the queue. - */ + +/** + * @brief Pop the Shortest Path First Vertex pointer at the top of the queue. + * @internal + * + * The caller is given the responsiblity for releasing the resources + * associated with the vertex. + * + * @see SPFVertex + * @see Top () + * @returns The Shortest Path First Vertex pointer at the top of the queue. + */ SPFVertex* Pop (void); - /** - * Return the Shortest Path First Vertex pointer at the top of the queue. - * This method does not pop the SPFVertex* off of the queue, it simply - * returns the pointer. - * - * @see SPFVertex - * @see Pop () - * @returns The Shortest Path First Vertex pointer at the top of the queue. - */ + +/** + * @brief Return the Shortest Path First Vertex pointer at the top of the + * queue. + * @internal + * + * This method does not pop the SPFVertex* off of the queue, it simply + * returns the pointer. + * + * @see SPFVertex + * @see Pop () + * @returns The Shortest Path First Vertex pointer at the top of the queue. + */ SPFVertex* Top (void) const; - /** - * Test the Candidate Queue to determine if it is empty. - * - * @returns True if the queue is empty, false otherwise. - */ + +/** + * @brief Test the Candidate Queue to determine if it is empty. + * @internal + * + * @returns True if the queue is empty, false otherwise. + */ bool Empty (void) const; - /** - * Return the number of Shortest Path First Vertex pointers presently - * stored in the Candidate Queue. - * - * @see SPFVertex - * @returns The number of SPFVertex* pointers in the Candidate Queue. - */ + +/** + * @brief Return the number of Shortest Path First Vertex pointers presently + * stored in the Candidate Queue. + * @internal + * + * @see SPFVertex + * @returns The number of SPFVertex* pointers in the Candidate Queue. + */ uint32_t Size (void) const; - /** - * Searches the Candidate Queue for a Shortest Path First Vertex pointer - * that points to a vertex having the given IP address. - * - * @see SPFVertex - * @param addr The IP address to search for. - * @returns The SPFVertex* pointer corresponding to the given IP address. - */ + +/** + * @brief Searches the Candidate Queue for a Shortest Path First Vertex + * pointer that points to a vertex having the given IP address. + * @internal + * + * @see SPFVertex + * @param addr The IP address to search for. + * @returns The SPFVertex* pointer corresponding to the given IP address. + */ SPFVertex* Find (const Ipv4Address addr) const; - /** - * Reorders the Candidate Queue according to the priority scheme. On - * completion, the top of the queue will hold the Shortest Path First - * Vertex pointer that points to a vertex having lowest value of the field - * m_distanceFromRoot. Remaining vertices are ordered according to - * increasing distance. - * - * This method is provided in case the values of m_distanceFromRoot change - * during the routing calculations. - * - * @see SPFVertex - */ + +/** + * @brief Reorders the Candidate Queue according to the priority scheme. + * @internal + * + * On completion, the top of the queue will hold the Shortest Path First + * Vertex pointer that points to a vertex having lowest value of the field + * m_distanceFromRoot. Remaining vertices are ordered according to + * increasing distance. + * + * This method is provided in case the values of m_distanceFromRoot change + * during the routing calculations. + * + * @see SPFVertex + */ void Reorder (void); protected: @@ -138,17 +161,18 @@ protected: CandidateList_t m_candidates; private: - /** - * Candidate Queue copy construction is disallowed (not implemented) to - * prevent the compiler from slipping in incorrect versions that don't - * properly deal with deep copies. - */ +/** + * Candidate Queue copy construction is disallowed (not implemented) to + * prevent the compiler from slipping in incorrect versions that don't + * properly deal with deep copies. + */ CandidateQueue (CandidateQueue& sr); - /** - * Candidate Queue assignment operator is disallowed (not implemented) to - * prevent the compiler from slipping in incorrect versions that don't - * properly deal with deep copies. - */ + +/** + * Candidate Queue assignment operator is disallowed (not implemented) to + * prevent the compiler from slipping in incorrect versions that don't + * properly deal with deep copies. + */ CandidateQueue& operator= (CandidateQueue& sr); }; diff --git a/src/routing/global/global-route-manager-impl.h b/src/routing/global/global-route-manager-impl.h index 87e64919b..7979cb4a2 100644 --- a/src/routing/global/global-route-manager-impl.h +++ b/src/routing/global/global-route-manager-impl.h @@ -61,6 +61,7 @@ class SPFVertex public: /** * @brief Enumeration of the possible types of SPFVertex objects. + * @internal * * Currently we use VertexRouter to identify objects that represent a router * in the simulation topology, and VertexNetwork to identify objects that @@ -75,6 +76,7 @@ public: /** * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First * Vertex). + * @internal * * The Vertex Type is set to VertexUnknown, the Vertex ID is set to * 255.255.255.255, and the distance from root is set to infinity @@ -89,6 +91,7 @@ public: /** * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). + * @internal * * The Vertex Type is initialized to VertexRouter and the Vertex ID is found * from the Link State ID of the Link State Advertisement (LSA) passed as a @@ -106,6 +109,7 @@ public: /** * @brief Destroy an SPFVertex (Shortest Path First Vertex). + * @internal * * The children vertices of the SPFVertex are recursively deleted. * @@ -115,6 +119,7 @@ public: /** * @brief Get the Vertex Type field of a SPFVertex object. + * @internal * * The Vertex Type describes the kind of simulation object a given SPFVertex * represents. @@ -126,6 +131,7 @@ public: /** * @brief Set the Vertex Type field of a SPFVertex object. + * @internal * * The Vertex Type describes the kind of simulation object a given SPFVertex * represents. @@ -137,6 +143,7 @@ public: /** * @brief Get the Vertex ID field of a SPFVertex object. + * @internal * * The Vertex ID uniquely identifies the simulation object a given SPFVertex * represents. Typically, this is the Router ID for SPFVertex objects @@ -152,6 +159,7 @@ public: /** * @brief Set the Vertex ID field of a SPFVertex object. + * @internal * * The Vertex ID uniquely identifies the simulation object a given SPFVertex * represents. Typically, this is the Router ID for SPFVertex objects @@ -170,6 +178,7 @@ public: * @brief Get the Global Router Link State Advertisement returned by the * Global Router represented by this SPFVertex during the route discovery * process. + * @internal * * @see GlobalRouter * @see GlobalRouterLSA @@ -183,6 +192,7 @@ public: * @brief Set the Global Router Link State Advertisement returned by the * Global Router represented by this SPFVertex during the route discovery * process. + * @internal * * @see SPFVertex::GetLSA () * @see GlobalRouter @@ -196,6 +206,7 @@ public: /** * @brief Get the distance from the root vertex to "this" SPFVertex object. + * @internal * * Each router in the simulation is associated with an SPFVertex object. When * calculating routes, each of these routers is, in turn, chosen as the "root" @@ -218,6 +229,7 @@ public: /** * @brief Set the distance from the root vertex to "this" SPFVertex object. + * @internal * * Each router in the simulation is associated with an SPFVertex object. When * calculating routes, each of these routers is, in turn, chosen as the "root" @@ -239,6 +251,7 @@ public: /** * @brief Get the interface ID that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -280,6 +293,7 @@ public: /** * @brief Set the interface ID that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -321,6 +335,7 @@ public: /** * @brief Get the IP address that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -363,6 +378,7 @@ public: /** * @brief Set the IP address that should be used to begin forwarding packets * from the root SPFVertex to "this" SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -405,6 +421,7 @@ public: /** * @brief Get a pointer to the SPFVector that is the parent of "this" * SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -425,6 +442,7 @@ public: /** * @brief Set the pointer to the SPFVector that is the parent of "this" * SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -444,6 +462,7 @@ public: /** * @brief Get the number of children of "this" SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -466,6 +485,7 @@ public: /** * @brief Get a borrowed SPFVertex pointer to the specified child of "this" * SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -494,6 +514,7 @@ public: /** * @brief Get a borrowed SPFVertex pointer to the specified child of "this" * SPFVertex. + * @internal * * Each router node in the simulation is associated with an SPFVertex object. * When calculating routes, each of these routers is, in turn, chosen as the @@ -561,6 +582,7 @@ class GlobalRouteManagerLSDB public: /** * @brief Construct an empty Global Router Manager Link State Database. + * @internal * * The database map composing the Link State Database is initialized in * this constructor. @@ -569,6 +591,7 @@ public: /** * @brief Destroy an empty Global Router Manager Link State Database. + * @internal * * The database map is walked and all of the Link State Advertisements stored * in the database are freed; then the database map itself is clear ()ed to @@ -579,6 +602,7 @@ public: /** * @brief Insert an IP address / Link State Advertisement pair into the Link * State Database. + * @internal * * The IPV4 address and the GlobalRouterLSA given as parameters are converted * to an STL pair and are inserted into the database map. @@ -594,6 +618,7 @@ public: /** * @brief Look up the Link State Advertisement associated with the given * IP Address. + * @internal * * The database map is searched for the given IPV4 address and corresponding * GlobalRouterLSA is returned. @@ -609,6 +634,7 @@ public: /** * @brief Set all LSA flags to an initialized state, for SPF computation + * @internal * * This function walks the database and resets the status flags of all of the * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done @@ -657,6 +683,7 @@ public: /** * @brief Select which nodes in the system are to be router nodes and * aggregate the appropriate interfaces onto those nodes. + * @internal * */ virtual void SelectRouterNodes (); @@ -664,23 +691,26 @@ public: /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a GlobalRouter interface. - * + * @internal */ virtual void BuildGlobalRoutingDatabase (); /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables + * @internal */ virtual void InitializeRoutes (); /** * @brief Debugging routine; allow client code to supply a pre-built LSDB + * @internal */ void DebugUseLsdb (GlobalRouteManagerLSDB*); /** * @brief Debugging routine; call the core SPF from the unit tests + * @internal */ void DebugSPFCalculate (Ipv4Address root); diff --git a/src/routing/global/global-route-manager.h b/src/routing/global/global-route-manager.h index b4f8d53b8..7562da67d 100644 --- a/src/routing/global/global-route-manager.h +++ b/src/routing/global/global-route-manager.h @@ -54,6 +54,7 @@ private: /** * @brief Select which nodes in the system are to be router nodes and * aggregate the appropriate interfaces onto those nodes. + * @internal * */ static void SelectRouterNodes (); @@ -61,6 +62,7 @@ private: /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a GlobalRouter interface. + * @internal * */ static void BuildGlobalRoutingDatabase (); @@ -68,6 +70,7 @@ private: /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables + * @internal */ static void InitializeRoutes (); From d5086e07a099fd2acd4187813c0a08278eb9a6a2 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 27 Jul 2007 21:58:19 -0700 Subject: [PATCH 103/278] small readability change --- src/routing/global/global-router-interface.h | 47 ++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/routing/global/global-router-interface.h b/src/routing/global/global-router-interface.h index d5ddbb3e2..b2927d631 100644 --- a/src/routing/global/global-router-interface.h +++ b/src/routing/global/global-router-interface.h @@ -14,8 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef GLOBAL_ROUTER_H -#define GLOBAL_ROUTER_H +#ifndef GLOBAL_ROUTER_INTERFACE_H +#define GLOBAL_ROUTER_INTERFACE_H #include #include @@ -52,6 +52,7 @@ public: StubNetwork, /**< Record represents a leaf node network */ VirtualLink /**< Unused -- for future OSPF compatibility */ }; + /** * @brief Construct an empty ("uninitialized") Global Router Link Record. * @@ -60,6 +61,7 @@ public: * The metric is set to 0. */ GlobalRouterLinkRecord (); + /** * Construct an initialized Global Router Link Record. * @@ -76,12 +78,14 @@ public: Ipv4Address linkId, Ipv4Address linkData, uint32_t metric); + /** * @brief Destroy a Global Router Link Record. * * Currently does nothing. Here as a placeholder only. */ ~GlobalRouterLinkRecord (); + /** * Get the Link ID field of the Global Router Link Record. * @@ -94,6 +98,7 @@ public: * @returns The Ipv4Address corresponding to the Link ID field of the record. */ Ipv4Address GetLinkId(void) const; + /** * @brief Set the Link ID field of the Global Router Link Record. * @@ -106,6 +111,7 @@ public: * @param addr An Ipv4Address to store in the Link ID field of the record. */ void SetLinkId(Ipv4Address addr); + /** * @brief Get the Link Data field of the Global Router Link Record. * @@ -118,6 +124,7 @@ public: * @returns The Ipv4Address corresponding to the Link Data field of the record. */ Ipv4Address GetLinkData(void) const; + /** * @brief Set the Link Data field of the Global Router Link Record. * @@ -130,6 +137,7 @@ public: * @param addr An Ipv4Address to store in the Link Data field of the record. */ void SetLinkData(Ipv4Address addr); + /** * @brief Get the Link Type field of the Global Router Link Record. * @@ -140,6 +148,7 @@ public: * @returns The LinkType of the current Global Router Link Record. */ LinkType GetLinkType(void) const; + /** * @brief Set the Link Type field of the Global Router Link Record. * @@ -150,6 +159,7 @@ public: * @param linkType The new LinkType for the current Global Router Link Record. */ void SetLinkType(LinkType linkType); + /** * @brief Get the Metric Data field of the Global Router Link Record. * @@ -162,6 +172,7 @@ public: * @returns The metric field of the Global Router Link Record. */ uint32_t GetMetric(void) const; + /** * @brief Set the Metric Data field of the Global Router Link Record. * @@ -187,6 +198,7 @@ private: * For Type 3 link (Stub), set m_linkId to neighbor's IP address */ Ipv4Address m_linkId; + /** * m_linkId and m_linkData are defined by OSPF to have different meanings * depending on the type of link a given link records represents. They work @@ -197,11 +209,13 @@ private: * For Type 3 link (Stub), set m_linkData to mask */ Ipv4Address m_linkData; // for links to RouterLSA, + /** * The type of the Global Router Link Record. Defined in the OSPF spec. * We currently only use PointToPoint and StubNetwork types. */ LinkType m_linkType; + /** * The metric for a given link. * @@ -235,6 +249,7 @@ public: LSA_SPF_CANDIDATE, /**< Vertex is in the SPF candidate queue */ LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */ }; + /** * @brief Create a blank Global Router Link State Advertisement. * @@ -242,6 +257,7 @@ public: * list of Link State Records is empty. */ GlobalRouterLSA(); + /** * @brief Create an initialized Global Router Link State Advertisement. * @@ -253,6 +269,7 @@ public: */ GlobalRouterLSA(SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr); + /** * @brief Copy constructor for a Global Router Link State Advertisement. * @@ -262,12 +279,14 @@ public: * @param lsa The existing LSA to be used as the source. */ GlobalRouterLSA (GlobalRouterLSA& lsa); + /** * @brief Destroy an existing Global Router Link State Advertisement. * * Any Global Router Link Records present in the list are freed. */ ~GlobalRouterLSA(); + /** * @brief Assignment operator for a Global Router Link State Advertisement. * @@ -281,6 +300,7 @@ public: * @returns Reference to the overwritten LSA. */ GlobalRouterLSA& operator= (const GlobalRouterLSA& lsa); + /** * @brief Copy any Global Router Link Records in a given Global Router Link * State Advertisement to the current LSA. @@ -292,6 +312,7 @@ public: * @param lsa The LSA to copy the Link Records from. */ void CopyLinkRecords (const GlobalRouterLSA& lsa); + /** * @brief Add a given Global Router Link Record to the LSA. * @@ -299,12 +320,14 @@ public: * @returns The number of link records in the list. */ uint32_t AddLinkRecord (GlobalRouterLinkRecord* lr); + /** * @brief Return the number of Global Router Link Records in the LSA. * * @returns The number of link records in the list. */ uint32_t GetNLinkRecords (void) const; + /** * @brief Return a pointer to the specified Global Router Link Record. * @@ -312,11 +335,13 @@ public: * @returns The number of link records in the list. */ GlobalRouterLinkRecord* GetLinkRecord (uint32_t n) const; + /** * @brief Release all of the Global Router Link Records present in the Global * Router Link State Advertisement and make the list of link records empty. */ void ClearLinkRecords(void); + /** * @brief Check to see if the list of Global Router Link Records present in the * Global Router Link State Advertisement is empty. @@ -324,11 +349,13 @@ public: * @returns True if the list is empty, false otherwise. */ bool IsEmpty(void) const; + /** * @brief Print the contents of the Global Router Link State Advertisement and * any Global Router Link Records present in the list. Quite verbose. */ void Print (std::ostream &os) const; + /** * @brief Get the Link State ID as defined by the OSPF spec. We always set it * to the router ID of the router making the advertisement. @@ -338,6 +365,7 @@ public: * @returns The Ipv4Address stored as the link state ID. */ Ipv4Address GetLinkStateId (void) const; + /** * @brief Set the Link State ID is defined by the OSPF spec. We always set it * to the router ID of the router making the advertisement. @@ -346,6 +374,7 @@ public: * @see GlobalRouter::GetRouterId () */ void SetLinkStateId (Ipv4Address addr); + /** * @brief Get the Advertising Router as defined by the OSPF spec. We always * set it to the router ID of the router making the advertisement. @@ -355,6 +384,7 @@ public: * @returns The Ipv4Address stored as the advetising router. */ Ipv4Address GetAdvertisingRouter (void) const; + /** * @brief Set the Advertising Router as defined by the OSPF spec. We always * set it to the router ID of the router making the advertisement. @@ -363,6 +393,7 @@ public: * @see GlobalRouter::GetRouterId () */ void SetAdvertisingRouter (Ipv4Address rtr); + /** * @brief Get the SPF status of the advertisement. * @@ -370,6 +401,7 @@ public: * @returns The SPFStatus of the LSA. */ SPFStatus GetStatus (void) const; + /** * @brief Set the SPF status of the advertisement * @@ -386,6 +418,7 @@ private: * @see GlobalRouter::GetRouterId () */ Ipv4Address m_linkStateId; + /** * The Advertising Router is defined by the OSPF spec. We always set it to * the router ID of the router making the advertisement. @@ -394,10 +427,12 @@ private: * @see GlobalRouter::GetRouterId () */ Ipv4Address m_advertisingRtr; + /** * A convenience typedef to avoid too much writers cramp. */ typedef std::list ListOfLinkRecords_t; + /** * Each Link State Advertisement contains a number of Link Records that * describe the kinds of links that are attached to a given node. We @@ -409,6 +444,7 @@ private: * @see GlobalRouter::DiscoverLSAs () */ ListOfLinkRecords_t m_linkRecords; + /** * This is a tristate flag used internally in the SPF computation to mark * if an SPFVertex (a data structure representing a vertex in the SPF tree @@ -438,6 +474,7 @@ public: * @see Object::QueryInterface () */ static const InterfaceId iid; + /** * @brief Create a Global Router class and aggregate its interface onto the * Node provided. @@ -445,6 +482,7 @@ public: * @param node The existing Node onto which this router will be aggregated. */ GlobalRouter (Ptr node); + /** * @brief Get the Router ID associated with this Global Router. * @@ -455,6 +493,7 @@ public: * @returns The Router ID associated with the Global Router. */ Ipv4Address GetRouterId (void) const; + /** * @brief Walk the connected channels, discover the adjacent routers and build * the associated number of Global Router Link State Advertisements that @@ -473,6 +512,7 @@ public: * @returns The number of Global Router Link State Advertisements. */ uint32_t DiscoverLSAs (void); + /** * @brief Get the Number of Global Router Link State Advertisements that this * router can export. @@ -487,6 +527,7 @@ public: * @returns The number of Global Router Link State Advertisements. */ uint32_t GetNumLSAs (void) const; + /** * @brief Get a Global Router Link State Advertisements that this router has * said that it can export. @@ -536,4 +577,4 @@ private: } // namespace ns3 -#endif /* GLOBAL_ROUTER_H */ +#endif /* GLOBAL_ROUTER_INTERFACE_H */ From c80acdf88f8f77fc3bb72ce2326b925ac9799a37 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 10:35:40 +0200 Subject: [PATCH 104/278] remove dead files after merge --- src/devices/p2p/p2p-net-device.cc | 222 ---------------------- src/devices/p2p/p2p-net-device.h | 296 ------------------------------ 2 files changed, 518 deletions(-) delete mode 100644 src/devices/p2p/p2p-net-device.cc delete mode 100644 src/devices/p2p/p2p-net-device.h diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc deleted file mode 100644 index 3e0596d48..000000000 --- a/src/devices/p2p/p2p-net-device.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2005,2006 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Craig Dowell - * Revised: George Riley - */ - -#include -#include -#include "ns3/debug.h" -#include "ns3/queue.h" -#include "ns3/simulator.h" -#include "ns3/composite-trace-resolver.h" -#include "ns3/eui48-address.h" -#include "p2p-net-device.h" -#include "p2p-channel.h" - -NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice"); - -namespace ns3 { - -DataRateDefaultValue PointToPointNetDevice::g_defaultRate( - "PointToPointLinkDataRate", - "The default data rate for point to point links", - DataRate ("10Mb/s")); - -PointToPointNetDevice::PointToPointNetDevice (Ptr node, - const DataRate& rate) -: - NetDevice(node, Eui48Address::Allocate ().ConvertTo ()), - m_txMachineState (READY), - m_bps (rate), - m_tInterframeGap (Seconds(0)), - m_channel (0), - m_queue (0), - m_rxTrace () -{ - NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << node << ")"); - - // BUGBUG FIXME - // - // You _must_ support broadcast to get any sort of packet from the ARP layer. - EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff").ConvertTo ()); - EnableMulticast(); - EnablePointToPoint(); -} - -PointToPointNetDevice::~PointToPointNetDevice() -{ - NS_DEBUG ("PointToPointNetDevice::~PointToPointNetDevice ()"); - m_queue = 0; -} - -void PointToPointNetDevice::DoDispose() -{ - m_channel = 0; - NetDevice::DoDispose (); -} - - -void PointToPointNetDevice::SetDataRate(const DataRate& bps) -{ - m_bps = bps; -} - -void PointToPointNetDevice::SetInterframeGap(const Time& t) -{ - m_tInterframeGap = t; -} - -bool PointToPointNetDevice::SendTo (Packet& p, const Address& dest) -{ - NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); - NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); - - // GFR Comment. Why is this an assertion? Can't a link legitimately - // "go down" during the simulation? Shouldn't we just wait for it - // to come back up? - NS_ASSERT (IsLinkUp ()); - -// -// This class simulates a point to point device. In the case of a serial -// link, this means that we're simulating something like a UART. -// -// -// If there's a transmission in progress, we enque the packet for later -// trnsmission; otherwise we send it now. - if (m_txMachineState == READY) - { - return TransmitStart (p); - } - else - { - return m_queue->Enqueue(p); - } -} - - bool -PointToPointNetDevice::TransmitStart (Packet &p) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitStart (" << &p << ")"); - NS_DEBUG ( - "PointToPointNetDevice::TransmitStart (): UID is " << p.GetUid () << ")"); -// -// This function is called to start the process of transmitting a packet. -// We need to tell the channel that we've started wiggling the wire and -// schedule an event that will be executed when the transmission is complete. -// - NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); - m_txMachineState = BUSY; - Time txTime = Seconds (m_bps.CalculateTxTime(p.GetSize())); - Time txCompleteTime = txTime + m_tInterframeGap; - - NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " << - "Schedule TransmitCompleteEvent in " << - txCompleteTime.GetSeconds () << "sec"); - // Schedule the tx complete event - Simulator::Schedule (txCompleteTime, - &PointToPointNetDevice::TransmitComplete, - this); - return m_channel->TransmitStart(p, this, txTime); -} - -void PointToPointNetDevice::TransmitComplete (void) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); -// -// This function is called to finish the process of transmitting a packet. -// We need to tell the channel that we've stopped wiggling the wire and -// get the next packet from the queue. If the queue is empty, we are -// done, otherwise transmit the next packet. -// - NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = READY; - Packet p; - if (!m_queue->Dequeue(p)) return; // Nothing to do at this point - TransmitStart(p); -} - -TraceResolver* PointToPointNetDevice::DoCreateTraceResolver ( - TraceContext const &context) -{ - CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - resolver->Add ("queue", - MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)), - PointToPointNetDevice::QUEUE); - resolver->Add ("rx", - m_rxTrace, - PointToPointNetDevice::RX); - return resolver; -} - -bool PointToPointNetDevice::Attach (Ptr ch) -{ - NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")"); - - m_channel = ch; - - m_channel->Attach(this); - m_bps = m_channel->GetDataRate (); - // GFR Comment. Below is definitely wrong. Interframe gap - // is unrelated to channel delay. - //m_tInterframeGap = m_channel->GetDelay (); - - /* - * For now, this device is up whenever a channel is attached to it. - * In fact, it should become up only when the second device - * is attached to the channel. So, there should be a way for - * a PointToPointChannel to notify both of its attached devices - * that the channel is 'complete', hence that the devices are - * up, hence that they can call NotifyLinkUp. - */ - NotifyLinkUp (); - return true; -} - -void PointToPointNetDevice::AddQueue (Ptr q) -{ - NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")"); - - m_queue = q; -} - -void PointToPointNetDevice::Receive (Packet& p) -{ - NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); - - m_rxTrace (p); - ForwardUp (p); -} - -Ptr PointToPointNetDevice::GetQueue(void) const -{ - return m_queue; -} - -Ptr PointToPointNetDevice::DoGetChannel(void) const -{ - return m_channel; -} - -bool PointToPointNetDevice::DoNeedsArp (void) const -{ - return false; -} - -} // namespace ns3 diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h deleted file mode 100644 index 474a6383c..000000000 --- a/src/devices/p2p/p2p-net-device.h +++ /dev/null @@ -1,296 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 University of Washington - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Craig Dowell - */ - -#ifndef POINT_TO_POINT_NET_DEVICE_H -#define POINT_TO_POINT_NET_DEVICE_H - -#include -#include "ns3/address.h" -#include "ns3/node.h" -#include "ns3/net-device.h" -#include "ns3/callback.h" -#include "ns3/packet.h" -#include "ns3/callback-trace-source.h" -#include "ns3/nstime.h" -#include "ns3/data-rate.h" -#include "ns3/default-value.h" -#include "ns3/ptr.h" - -namespace ns3 { - -class Queue; -class PointToPointChannel; - -/** - * \class PointToPointNetDevice - * \brief A Device for a Point to Point Network Link. - * - * Ns-3 takes a four-layer view of a protocol stack. This is the same model - * that TCP uses. In this view, layers 5-7 of the OSI reference model are - * grouped together into an application layer; layer four (transport / TCP) is - * broken out; layer three (network / IP) is broken out; and layers 1-2 are - * grouped together. We call this grouping of layers one and two a NetDevice - * and represent it as a class in the system. - * - * The NetDevice class is specialized according to the needs of the specific - * kind of network link. In this case, the link is a PointToPoint link. The - * PointToPoint link is a family of classes that includes this class, the - * PointToPointNetDevice, a PointToPointChannel class that represents the - * actual medium across which bits are sent, a PointToPointIpv4Interface class - * that provides the hook to tie a general purpose node to this specific - * link, and finally, a PointToPointTopology object that is responsible for - * putting all of the pieces together. - * - * This is the PointToPointNetDevice class that represents, essentially, the - * PC card that is used to connect to the PointToPoint network. - */ -class PointToPointNetDevice : public NetDevice { -public: - /** - * Enumeration of the types of traces supported in the class. - * - */ - enum TraceType { - QUEUE, /**< Trace queue events on the attached queue */ - RX, /**< Trace packet reception events (from the channel) */ - }; - /** - * Construct a PointToPointNetDevice - * - * This is the constructor for the PointToPointNetDevice. It takes as a - * parameter the Node to which this device is connected. Ownership of the - * Node pointer is not implied and the node must not be deleded. - * - * @see PointToPointTopology::AddPointToPointLink () - * @param node the Node to which this device is connected. - */ - PointToPointNetDevice (Ptr node, - const DataRate& = g_defaultRate.GetValue()); - /** - * Destroy a PointToPointNetDevice - * - * This is the destructor for the PointToPointNetDevice. - */ - virtual ~PointToPointNetDevice(); - /** - * Set the Data Rate used for transmission of packets. The data rate is - * set in the Attach () method from the corresponding field in the channel - * to which the device is attached. It can be overridden using this method. - * - * @see Attach () - * @param bps the data rate at which this object operates - */ - void SetDataRate(const DataRate& bps); - /** - * Set the inteframe gap used to separate packets. The interframe gap - * defines the minimum space required between packets sent by this device. - * It is usually set in the Attach () method based on the speed of light - * delay of the channel to which the device is attached. It can be - * overridden using this method if desired. - * - * @see Attach () - * @param t the interframe gap time - */ - void SetInterframeGap(const Time& t); - /** - * Attach the device to a channel. - * - * The PointToPointTopology object creates a PointToPointChannel and two - * PointtoPointNetDevices. In order to introduce these components to each - * other, the topology object calls Attach () on each PointToPointNetDevice. - * Inside this method, the Net Device calls out to the PointToPointChannel - * to introduce itself. - * - * @see PointToPointTopology::AddPointToPointLink () - * @see SetDataRate () - * @see SetInterframeGap () - * @param ch a pointer to the channel to which this object is being attached. - */ - bool Attach(Ptr ch); - /** - * Attach a queue to the PointToPointNetDevice. - * - * The PointToPointNetDevice "owns" a queue. This queue is created by the - * PointToPointTopology object and implements a queueing method such as - * DropTail or RED. The PointToPointNetDevice assumes ownership of this - * queue and must delete it when the device is destroyed. - * - * @see PointToPointTopology::AddPointToPointLink () - * @see Queue - * @see DropTailQueue - * @param queue a pointer to the queue for which object is assuming - * ownership. - */ - void AddQueue(Ptr queue); - /** - * Receive a packet from a connected PointToPointChannel. - * - * The PointToPointNetDevice receives packets from its connected channel - * and forwards them up the protocol stack. This is the public method - * used by the channel to indicate that the last bit of a packet has - * arrived at the device. - * - * @see PointToPointChannel - * @param p a reference to the received packet - */ - void Receive (Packet& p); -protected: - virtual void DoDispose (void); - /** - * Get a copy of the attached Queue. - * - * This method is provided for any derived class that may need to get - * direct access to the underlying queue. - * - * @see PointToPointTopology - * @returns a pointer to the queue. - */ - Ptr GetQueue(void) const; - /** - * Get a copy of the attached Channel - * - * This method is provided for any derived class that may need to get - * direct access to the connected channel - * - * @see PointToPointChannel - * @returns a pointer to the channel - */ - virtual Ptr DoGetChannel(void) const; - /** - * Set a new default data rate - * @param Data rate to set for new default - */ - static void SetDefaultRate(const DataRate&); - - /** - * Get the current default rate. - * @returns a const reference to current default - */ - - static const DataRate& GetDefaultRate(); - -private: - // unimplemented methods to make it impossible - // to copy these objects. - PointToPointNetDevice (const PointToPointNetDevice& nd); - PointToPointNetDevice& operator = (const PointToPointNetDevice&o); - - /** - * Send a Packet Down the Wire. - * - * The SendTo method is defined as the standard way that the level three - * protocol uses to tell a NetDevice to send a packet. SendTo is declared - * as abstract in the NetDevice class and we declare it here. - * - * @see NetDevice - * @param p a reference to the packet to send - * @param dest a reference to the Address of the destination device - * @returns true if success, false on failure - */ - virtual bool SendTo (Packet& p, const Address& dest); - /** - * Start Sending a Packet Down the Wire. - * - * The TransmitStart method is the method that is used internally in the - * PointToPointNetDevice to begin the process of sending a packet out on - * the channel. The corresponding method is called on the channel to let - * it know that the physical device this class represents has virually - * started sending signals. An event is scheduled for the time at which - * the bits have been completely transmitted. - * - * @see PointToPointChannel::TransmitStart () - * @see TransmitCompleteEvent () - * @param p a reference to the packet to send - * @returns true if success, false on failure - */ - bool TransmitStart (Packet &p); - /** - * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. - * - * The TransmitComplete method is used internally to finish the process - * of sending a packet out on the channel. - * - */ - void TransmitComplete(void); - /** - * Create a Trace Resolver for events in the net device. - * - * @see class TraceResolver - */ - virtual TraceResolver* DoCreateTraceResolver (TraceContext const &context); - virtual bool DoNeedsArp (void) const; - /** - * Enumeration of the states of the transmit machine of the net device. - */ - enum TxMachineState - { - READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY /**< The transmitter is busy transmitting a packet */ - }; - /** - * The state of the Net Device transmit state machine. - * @see TxMachineState - */ - TxMachineState m_txMachineState; - /** - * The data rate that the Net Device uses to simulate packet transmission - * timing. - * @see class DataRate - */ - DataRate m_bps; - /** - * The interframe gap that the Net Device uses to throttle packet - * transmission - * @see class Time - */ - Time m_tInterframeGap; - /** - * The PointToPointChannel to which this PointToPointNetDevice has been - * attached. - * @see class PointToPointChannel - */ - Ptr m_channel; - /** - * The Queue which this PointToPointNetDevice uses as a packet source. - * Management of this Queue has been delegated to the PointToPointNetDevice - * and it has the responsibility for deletion. - * @see class Queue - * @see class DropTailQueue - */ - Ptr m_queue; - /** - * The trace source for the packet reception events that the device can - * fire. - * - * @see class CallBackTraceSource - * @see class TraceResolver - */ - CallbackTraceSource m_rxTrace; - /** - * Default data rate. Used for all newly created p2p net devices - */ - static DataRateDefaultValue g_defaultRate; - -}; - -}; // namespace ns3 - -#endif // POINT_TO_POINT_NET_DEVICE_H - From 034469197cfb5727b7bd169c301b693e21d3fa5c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 11:03:13 +0200 Subject: [PATCH 105/278] fix address deserialization --- src/node/address.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node/address.cc b/src/node/address.cc index 9bb67f4fb..d73f5790e 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -55,8 +55,9 @@ Address::CopyTo (uint8_t buffer[MAX_SIZE]) const void Address::CopyFrom (uint8_t *buffer, uint8_t len) { - NS_ASSERT (len == m_len); + NS_ASSERT (len <= MAX_SIZE); memcpy (m_data, buffer, len); + m_len = len; } bool Address::CheckCompatible (uint8_t type, uint8_t len) const From 41074331ed92b3f651b0adfeee852f43bebfd99c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 11:07:56 +0200 Subject: [PATCH 106/278] fix optimized build --- src/node/eui48-address.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index a5944d146..d83137e02 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -2,6 +2,7 @@ #include "address.h" #include "ns3/assert.h" #include +#include namespace ns3 { From df7f115415d5a2c2f4a434a2333fc6c57ea835ca Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 13:29:36 +0200 Subject: [PATCH 107/278] InetAddress -> InetSocketAddress --- examples/csma-cd-one-subnet.cc | 6 ++-- examples/simple-p2p.cc | 6 ++-- examples/simple-point-to-point.cc | 6 ++-- samples/main-simple.cc | 6 ++-- src/internet-node/udp-socket.cc | 12 ++++---- ...inet-address.cc => inet-socket-address.cc} | 30 +++++++++---------- .../{inet-address.h => inet-socket-address.h} | 18 +++++------ src/node/wscript | 4 +-- 8 files changed, 44 insertions(+), 44 deletions(-) rename src/node/{inet-address.cc => inet-socket-address.cc} (54%) rename src/node/{inet-address.h => inet-socket-address.h} (78%) diff --git a/examples/csma-cd-one-subnet.cc b/examples/csma-cd-one-subnet.cc index f93337823..ceaf88810 100644 --- a/examples/csma-cd-one-subnet.cc +++ b/examples/csma-cd-one-subnet.cc @@ -52,7 +52,7 @@ #include "ns3/csma-cd-ipv4-topology.h" #include "ns3/eui48-address.h" #include "ns3/ipv4-address.h" -#include "ns3/inet-address.h" +#include "ns3/inet-socket-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" #include "ns3/ipv4-route.h" @@ -132,7 +132,7 @@ int main (int argc, char *argv[]) // from n0 to n1 Ptr ooff = Create ( n0, - InetAddress (Ipv4Address("10.1.1.2"), 80).ConvertTo (), + InetSocketAddress (Ipv4Address("10.1.1.2"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -143,7 +143,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n0, starting at time 1.1 seconds ooff = Create ( n3, - InetAddress (Ipv4Address("10.1.1.1"), 80).ConvertTo (), + InetSocketAddress (Ipv4Address("10.1.1.1"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc index 5d1bb545e..d06ef329f 100644 --- a/examples/simple-p2p.cc +++ b/examples/simple-p2p.cc @@ -57,7 +57,7 @@ #include "ns3/p2p-channel.h" #include "ns3/p2p-net-device.h" #include "ns3/ipv4-address.h" -#include "ns3/inet-address.h" +#include "ns3/inet-socket-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" #include "ns3/ipv4-route.h" @@ -143,7 +143,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - InetAddress("10.1.3.2", 80).ConvertTo (), + InetSocketAddress("10.1.3.2", 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -154,7 +154,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - InetAddress("10.1.2.1", 80).ConvertTo (), + InetSocketAddress("10.1.2.1", 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/examples/simple-point-to-point.cc b/examples/simple-point-to-point.cc index 2398cc22b..806c4d120 100644 --- a/examples/simple-point-to-point.cc +++ b/examples/simple-point-to-point.cc @@ -58,7 +58,7 @@ #include "ns3/point-to-point-channel.h" #include "ns3/point-to-point-net-device.h" #include "ns3/ipv4-address.h" -#include "ns3/inet-address.h" +#include "ns3/inet-socket-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" #include "ns3/ipv4-route.h" @@ -144,7 +144,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - InetAddress (Ipv4Address("10.1.3.2"), 80).ConvertTo (), + InetSocketAddress (Ipv4Address("10.1.3.2"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -155,7 +155,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - InetAddress (Ipv4Address("10.1.2.1"), 80).ConvertTo (), + InetSocketAddress (Ipv4Address("10.1.2.1"), 80).ConvertTo (), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/samples/main-simple.cc b/samples/main-simple.cc index 4c709b4c5..e3567e0b1 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -4,7 +4,7 @@ #include "ns3/simulator.h" #include "ns3/socket-factory.h" #include "ns3/socket.h" -#include "ns3/inet-address.h" +#include "ns3/inet-socket-address.h" #include "ns3/nstime.h" using namespace ns3; @@ -45,11 +45,11 @@ RunSimulation (void) Ptr socketFactory = a->QueryInterface (iid); Ptr sink = socketFactory->CreateSocket (); - InetAddress local = InetAddress (Ipv4Address::GetAny (), 80); + InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80); sink->Bind (local.ConvertTo ()); Ptr source = socketFactory->CreateSocket (); - InetAddress remote = InetAddress (Ipv4Address::GetLoopback (), 80); + InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80); source->Connect (remote.ConvertTo ()); GenerateTraffic (source, 500); diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 9ae438f6b..020076cb5 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -19,7 +19,7 @@ * Author: Mathieu Lacage */ #include "ns3/node.h" -#include "ns3/inet-address.h" +#include "ns3/inet-socket-address.h" #include "udp-socket.h" #include "udp-l4-protocol.h" #include "ipv4-end-point.h" @@ -91,7 +91,7 @@ UdpSocket::Bind (void) int UdpSocket::Bind (const Address &address) { - InetAddress transport = InetAddress::ConvertFrom (address); + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); if (ipv4 == Ipv4Address::GetAny () && port == 0) @@ -147,7 +147,7 @@ UdpSocket::DoConnect(const Address & address, ns3::Callback > connectionFailed, ns3::Callback > halfClose) { - InetAddress transport = InetAddress::ConvertFrom (address); + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); m_defaultAddress = transport.GetIpv4 (); m_defaultPort = transport.GetPort (); if (!connectionSucceeded.IsNull ()) @@ -190,7 +190,7 @@ int UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, ns3::Callback, uint32_t> dataSent) { - InetAddress transport = InetAddress::ConvertFrom (address); + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -241,7 +241,7 @@ UdpSocket::DoSendTo(const Address &address, { p = Packet (buffer, size); } - InetAddress transport = InetAddress::ConvertFrom (address); + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -265,7 +265,7 @@ UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) return; } - Address address = InetAddress (ipv4, port).ConvertTo (); + Address address = InetSocketAddress (ipv4, port).ConvertTo (); Packet p = packet; if (!m_dummyRxCallback.IsNull ()) { diff --git a/src/node/inet-address.cc b/src/node/inet-socket-address.cc similarity index 54% rename from src/node/inet-address.cc rename to src/node/inet-socket-address.cc index bf82cfc83..b8d0e10cf 100644 --- a/src/node/inet-address.cc +++ b/src/node/inet-socket-address.cc @@ -1,52 +1,52 @@ -#include "inet-address.h" +#include "inet-socket-address.h" #include "ns3/assert.h" namespace ns3 { -InetAddress::InetAddress (Ipv4Address ipv4, uint16_t port) +InetSocketAddress::InetSocketAddress (Ipv4Address ipv4, uint16_t port) : m_ipv4 (ipv4), m_port (port) {} -InetAddress::InetAddress (Ipv4Address ipv4) +InetSocketAddress::InetSocketAddress (Ipv4Address ipv4) : m_ipv4 (ipv4), m_port (0) {} -InetAddress::InetAddress (const char *ipv4, uint16_t port) +InetSocketAddress::InetSocketAddress (const char *ipv4, uint16_t port) : m_ipv4 (Ipv4Address (ipv4)), m_port (port) {} -InetAddress::InetAddress (const char * ipv4) +InetSocketAddress::InetSocketAddress (const char * ipv4) : m_ipv4 (Ipv4Address (ipv4)), m_port (0) {} -InetAddress::InetAddress (uint16_t port) +InetSocketAddress::InetSocketAddress (uint16_t port) : m_ipv4 (Ipv4Address::GetAny ()), m_port (port) {} uint16_t -InetAddress::GetPort (void) const +InetSocketAddress::GetPort (void) const { return m_port; } Ipv4Address -InetAddress::GetIpv4 (void) const +InetSocketAddress::GetIpv4 (void) const { return m_ipv4; } void -InetAddress::SetPort (uint16_t port) +InetSocketAddress::SetPort (uint16_t port) { m_port = port; } void -InetAddress::SetIpv4 (Ipv4Address address) +InetSocketAddress::SetIpv4 (Ipv4Address address) { m_ipv4 = address; } Address -InetAddress::ConvertTo (void) const +InetSocketAddress::ConvertTo (void) const { uint8_t buf[6]; m_ipv4.Serialize (buf); @@ -54,18 +54,18 @@ InetAddress::ConvertTo (void) const buf[5] = (m_port >> 8) & 0xff; return Address (GetType (), buf, 6); } -InetAddress -InetAddress::ConvertFrom (const Address &address) +InetSocketAddress +InetSocketAddress::ConvertFrom (const Address &address) { NS_ASSERT (address.CheckCompatible (GetType (), 6)); uint8_t buf[6]; address.CopyTo (buf); Ipv4Address ipv4 = Ipv4Address::Deserialize (buf); uint16_t port = buf[0] | (buf[1] << 8); - return InetAddress (ipv4, port); + return InetSocketAddress (ipv4, port); } uint8_t -InetAddress::GetType (void) +InetSocketAddress::GetType (void) { static uint8_t type = Address::Register (); return type; diff --git a/src/node/inet-address.h b/src/node/inet-socket-address.h similarity index 78% rename from src/node/inet-address.h rename to src/node/inet-socket-address.h index 577974325..35fe52863 100644 --- a/src/node/inet-address.h +++ b/src/node/inet-socket-address.h @@ -15,37 +15,37 @@ namespace ns3 { * API. i.e., this class holds an Ipv4Address and a port number * to form an ipv4 transport endpoint. */ -class InetAddress +class InetSocketAddress { public: /** * \param ipv4 the ipv4 address * \param port the port number */ - InetAddress (Ipv4Address ipv4, uint16_t port); + InetSocketAddress (Ipv4Address ipv4, uint16_t port); /** * \param ipv4 the ipv4 address * * The port number is set to zero by default. */ - InetAddress (Ipv4Address ipv4); + InetSocketAddress (Ipv4Address ipv4); /** * \param port the port number * * The ipv4 address is set to the "Any" address by default. */ - InetAddress (uint16_t port); + InetSocketAddress (uint16_t port); /** * \param ipv4 string which represents an ipv4 address * \param port the port number */ - InetAddress (const char *ipv4, uint16_t port); + InetSocketAddress (const char *ipv4, uint16_t port); /** * \param ipv4 string which represents an ipv4 address * * The port number is set to zero. */ - InetAddress (const char *ipv4); + InetSocketAddress (const char *ipv4); /** * \returns the port number */ @@ -66,15 +66,15 @@ public: /** * \returns an Address instance which represents this - * InetAddress instance. + * InetSocketAddress instance. */ Address ConvertTo (void) const; /** * \param address the Address instance to convert from. - * \returns an InetAddress which corresponds to the input + * \returns an InetSocketAddress which corresponds to the input * Address */ - static InetAddress ConvertFrom (const Address &address); + static InetSocketAddress ConvertFrom (const Address &address); private: static uint8_t GetType (void); Ipv4Address m_ipv4; diff --git a/src/node/wscript b/src/node/wscript index 47f5b09a2..9cc3d3daf 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -8,7 +8,7 @@ def build(bld): node.source = [ 'address.cc', 'eui48-address.cc', - 'inet-address.cc', + 'inet-socket-address.cc', 'node.cc', 'ipv4-address.cc', 'net-device.cc', @@ -32,7 +32,7 @@ def build(bld): headers.source = [ 'address.h', 'eui48-address.h', - 'inet-address.h', + 'inet-socket-address.h', 'node.h', 'ipv4-address.h', 'net-device.h', From f2084098e2270e67821ecdc2a4567fc700a52541 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 13:55:28 +0200 Subject: [PATCH 108/278] add InetSocketAddress::IsMatchingType and use it --- src/internet-node/udp-socket.cc | 4 ++++ src/node/inet-socket-address.cc | 6 ++++++ src/node/inet-socket-address.h | 2 ++ src/node/socket.h | 1 + 4 files changed, 13 insertions(+) diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 020076cb5..bc83c942c 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -91,6 +91,10 @@ UdpSocket::Bind (void) int UdpSocket::Bind (const Address &address) { + if (!InetSocketAddress::IsMatchingType (address)) + { + return ERROR_INVAL; + } InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); diff --git a/src/node/inet-socket-address.cc b/src/node/inet-socket-address.cc index b8d0e10cf..232e9215f 100644 --- a/src/node/inet-socket-address.cc +++ b/src/node/inet-socket-address.cc @@ -45,6 +45,12 @@ InetSocketAddress::SetIpv4 (Ipv4Address address) m_ipv4 = address; } +bool +InetSocketAddress::IsMatchingType (const Address &address) +{ + return address.CheckCompatible (GetType (), 6); +} + Address InetSocketAddress::ConvertTo (void) const { diff --git a/src/node/inet-socket-address.h b/src/node/inet-socket-address.h index 35fe52863..bb91d0ff5 100644 --- a/src/node/inet-socket-address.h +++ b/src/node/inet-socket-address.h @@ -64,6 +64,8 @@ public: */ void SetIpv4 (Ipv4Address address); + static bool IsMatchingType (const Address &address); + /** * \returns an Address instance which represents this * InetSocketAddress instance. diff --git a/src/node/socket.h b/src/node/socket.h index 3cba7fd59..547ed4320 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -52,6 +52,7 @@ public: ERROR_AGAIN, ERROR_SHUTDOWN, ERROR_OPNOTSUPP, + ERROR_INVAL, SOCKET_ERRNO_LAST }; From 22cf3afdfa07fc0495249f6aee1f555f04561fc5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 13:58:39 +0200 Subject: [PATCH 109/278] add Ipv4Address::IsMatchingType and Eui48Address::IsMatchingType --- src/node/eui48-address.cc | 5 +++++ src/node/eui48-address.h | 4 ++++ src/node/ipv4-address.cc | 5 +++++ src/node/ipv4-address.h | 1 + 4 files changed, 15 insertions(+) diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index d83137e02..8196d7ba3 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -71,6 +71,11 @@ Eui48Address::CopyTo (uint8_t buffer[6]) const memcpy (buffer, m_address, 6); } +bool +Eui48Address::IsMatchingType (const Address &address) +{ + return address.CheckCompatible (GetType (), 6); +} Address Eui48Address::ConvertTo (void) const { diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h index ad045f078..1d6c37da1 100644 --- a/src/node/eui48-address.h +++ b/src/node/eui48-address.h @@ -42,6 +42,10 @@ public: * Convert an instance of this class to a polymorphic Address instance. */ Address ConvertTo (void) const; + /** + * \returns true if the address matches, false otherwise. + */ + static bool IsMatchingType (const Address &address); /** * \param address a polymorphic address * diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 67028125d..aae53c65f 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -206,6 +206,11 @@ Ipv4Address::Print (std::ostream &os) const << ((m_address >> 0) & 0xff); } +bool +Ipv4Address::IsMatchingType (const Address &address) +{ + return address.CheckCompatible (GetType (), 4); +} Address Ipv4Address::ConvertTo (void) const { diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index 9911d24c4..8e8976a18 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -104,6 +104,7 @@ public: */ Ipv4Address CombineMask (Ipv4Mask const &mask) const; + static bool IsMatchingType (const Address &address); Address ConvertTo (void) const; static Ipv4Address ConvertFrom (const Address &address); From 80bf1491e122cb3d0bda6ede5dde6186526387d7 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 13:59:13 +0200 Subject: [PATCH 110/278] add doxygen --- src/node/inet-socket-address.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/node/inet-socket-address.h b/src/node/inet-socket-address.h index bb91d0ff5..6734f1496 100644 --- a/src/node/inet-socket-address.h +++ b/src/node/inet-socket-address.h @@ -64,6 +64,9 @@ public: */ void SetIpv4 (Ipv4Address address); + /** + * \returns true if the address matches, false otherwise. + */ static bool IsMatchingType (const Address &address); /** From 2641f7fe88c7ad5d3b89851ba36a839685b0e389 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 14:07:39 +0200 Subject: [PATCH 111/278] InetSocketAddress: replace explicit conversion to implicit conversion --- examples/csma-cd-one-subnet.cc | 4 ++-- examples/simple-point-to-point.cc | 4 ++-- samples/main-simple.cc | 4 ++-- src/internet-node/udp-socket.cc | 10 +++++----- src/node/inet-socket-address.cc | 10 ++++++++++ src/node/inet-socket-address.h | 10 +++++++--- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/examples/csma-cd-one-subnet.cc b/examples/csma-cd-one-subnet.cc index ceaf88810..83b5b2259 100644 --- a/examples/csma-cd-one-subnet.cc +++ b/examples/csma-cd-one-subnet.cc @@ -132,7 +132,7 @@ int main (int argc, char *argv[]) // from n0 to n1 Ptr ooff = Create ( n0, - InetSocketAddress (Ipv4Address("10.1.1.2"), 80).ConvertTo (), + InetSocketAddress ("10.1.1.2", 80), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -143,7 +143,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n0, starting at time 1.1 seconds ooff = Create ( n3, - InetSocketAddress (Ipv4Address("10.1.1.1"), 80).ConvertTo (), + InetSocketAddress ("10.1.1.1", 80), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/examples/simple-point-to-point.cc b/examples/simple-point-to-point.cc index 806c4d120..fa826ab5c 100644 --- a/examples/simple-point-to-point.cc +++ b/examples/simple-point-to-point.cc @@ -144,7 +144,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - InetSocketAddress (Ipv4Address("10.1.3.2"), 80).ConvertTo (), + InetSocketAddress ("10.1.3.2", 80), "Udp", ConstantVariable(1), ConstantVariable(0)); @@ -155,7 +155,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - InetSocketAddress (Ipv4Address("10.1.2.1"), 80).ConvertTo (), + InetSocketAddress ("10.1.2.1", 80), "Udp", ConstantVariable(1), ConstantVariable(0)); diff --git a/samples/main-simple.cc b/samples/main-simple.cc index e3567e0b1..3be286c46 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -46,11 +46,11 @@ RunSimulation (void) Ptr sink = socketFactory->CreateSocket (); InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80); - sink->Bind (local.ConvertTo ()); + sink->Bind (local); Ptr source = socketFactory->CreateSocket (); InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80); - source->Connect (remote.ConvertTo ()); + source->Connect (remote); GenerateTraffic (source, 500); PrintTraffic (sink); diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index bc83c942c..438e59a53 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -95,7 +95,7 @@ UdpSocket::Bind (const Address &address) { return ERROR_INVAL; } - InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + InetSocketAddress transport = address; Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); if (ipv4 == Ipv4Address::GetAny () && port == 0) @@ -151,7 +151,7 @@ UdpSocket::DoConnect(const Address & address, ns3::Callback > connectionFailed, ns3::Callback > halfClose) { - InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + InetSocketAddress transport = address; m_defaultAddress = transport.GetIpv4 (); m_defaultPort = transport.GetPort (); if (!connectionSucceeded.IsNull ()) @@ -194,7 +194,7 @@ int UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, ns3::Callback, uint32_t> dataSent) { - InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + InetSocketAddress transport = address; Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -245,7 +245,7 @@ UdpSocket::DoSendTo(const Address &address, { p = Packet (buffer, size); } - InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); + InetSocketAddress transport = address; Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -269,7 +269,7 @@ UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) return; } - Address address = InetSocketAddress (ipv4, port).ConvertTo (); + Address address = InetSocketAddress (ipv4, port); Packet p = packet; if (!m_dummyRxCallback.IsNull ()) { diff --git a/src/node/inet-socket-address.cc b/src/node/inet-socket-address.cc index 232e9215f..43c32dcd1 100644 --- a/src/node/inet-socket-address.cc +++ b/src/node/inet-socket-address.cc @@ -51,6 +51,16 @@ InetSocketAddress::IsMatchingType (const Address &address) return address.CheckCompatible (GetType (), 6); } +InetSocketAddress::operator Address () const +{ + return ConvertTo (); +} + +InetSocketAddress::InetSocketAddress (const Address &address) +{ + *this = ConvertFrom (address); +} + Address InetSocketAddress::ConvertTo (void) const { diff --git a/src/node/inet-socket-address.h b/src/node/inet-socket-address.h index 6734f1496..c09a6c761 100644 --- a/src/node/inet-socket-address.h +++ b/src/node/inet-socket-address.h @@ -73,14 +73,18 @@ public: * \returns an Address instance which represents this * InetSocketAddress instance. */ - Address ConvertTo (void) const; + operator Address () const; + /** * \param address the Address instance to convert from. - * \returns an InetSocketAddress which corresponds to the input + * + * Construct an InetSocketAddress which corresponds to the input * Address */ - static InetSocketAddress ConvertFrom (const Address &address); + InetSocketAddress (const Address &address); private: + Address ConvertTo (void) const; + static InetSocketAddress ConvertFrom (const Address &address); static uint8_t GetType (void); Ipv4Address m_ipv4; uint16_t m_port; From 2e723a700d126db76e9109b269236af6ce1a60f5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 14:17:12 +0200 Subject: [PATCH 112/278] add implicit conversion to Eui48Address --- src/devices/csma-cd/csma-cd-net-device.cc | 14 ++++++------- .../point-to-point-net-device.cc | 4 ++-- src/node/eui48-address.cc | 8 ++++++++ src/node/eui48-address.h | 20 +++++++++++++------ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index ea4855f05..c07b8a438 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -37,7 +37,7 @@ namespace ns3 { CsmaCdNetDevice::CsmaCdNetDevice (Ptr node, Eui48Address addr, CsmaCdEncapsulationMode encapMode) - : NetDevice(node, addr.ConvertTo ()), + : NetDevice(node, addr), m_bps (DataRate (0xffffffff)) { NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); @@ -49,7 +49,7 @@ CsmaCdNetDevice::CsmaCdNetDevice (Ptr node, Eui48Address addr, CsmaCdNetDevice::CsmaCdNetDevice (Ptr node, Eui48Address addr, CsmaCdEncapsulationMode encapMode, bool sendEnable, bool receiveEnable) - : NetDevice(node, addr.ConvertTo ()), + : NetDevice(node, addr), m_bps (DataRate (0xffffffff)) { NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); @@ -96,7 +96,7 @@ CsmaCdNetDevice::Init(bool sendEnable, bool receiveEnable) m_channel = 0; m_queue = 0; - EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff").ConvertTo ()); + EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff")); EnableMulticast(); EnablePointToPoint(); @@ -160,7 +160,7 @@ CsmaCdNetDevice::AddHeader (Packet& p, Eui48Address dest, } EthernetHeader header (false); EthernetTrailer trailer; - Eui48Address source = Eui48Address::ConvertFrom (GetAddress ()); + Eui48Address source = GetAddress (); header.SetSource(source); header.SetDestination(dest); @@ -201,8 +201,8 @@ CsmaCdNetDevice::ProcessHeader (Packet& p, uint16_t & param) trailer.CheckFcs(p); p.RemoveHeader(header); - Eui48Address broadcast = Eui48Address::ConvertFrom (GetBroadcast ()); - Eui48Address destination = Eui48Address::ConvertFrom (GetAddress ()); + Eui48Address broadcast = GetBroadcast (); + Eui48Address destination = GetAddress (); if ((header.GetDestination() != broadcast) && (header.GetDestination() != destination)) { @@ -252,7 +252,7 @@ CsmaCdNetDevice::SendTo (Packet& p, const Address& dest, uint16_t protocolNumber if (!IsSendEnabled()) return false; - Eui48Address address = Eui48Address::ConvertFrom (dest); + Eui48Address address = dest; AddHeader(p, address, protocolNumber); // Place the packet to be sent on the send queue diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 4b4157b26..1fe15f424 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -43,7 +43,7 @@ DataRateDefaultValue PointToPointNetDevice::g_defaultRate( PointToPointNetDevice::PointToPointNetDevice (Ptr node, const DataRate& rate) : - NetDevice(node, Eui48Address::Allocate ().ConvertTo ()), + NetDevice(node, Eui48Address::Allocate ()), m_txMachineState (READY), m_bps (rate), m_tInterframeGap (Seconds(0)), @@ -56,7 +56,7 @@ PointToPointNetDevice::PointToPointNetDevice (Ptr node, // BUGBUG FIXME // // You _must_ support broadcast to get any sort of packet from the ARP layer. - EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff").ConvertTo ()); + EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff")); EnableMulticast(); EnablePointToPoint(); } diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 8196d7ba3..165bcb718 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -76,6 +76,14 @@ Eui48Address::IsMatchingType (const Address &address) { return address.CheckCompatible (GetType (), 6); } +Eui48Address::operator Address () +{ + return ConvertTo (); +} +Eui48Address::Eui48Address (const Address &address) +{ + *this = ConvertFrom (address); +} Address Eui48Address::ConvertTo (void) const { diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h index 1d6c37da1..3e693f73c 100644 --- a/src/node/eui48-address.h +++ b/src/node/eui48-address.h @@ -36,28 +36,36 @@ public: * Copy the internal address to the input buffer. */ void CopyTo (uint8_t buffer[6]) const; + /** * \returns a new Address instance * * Convert an instance of this class to a polymorphic Address instance. */ - Address ConvertTo (void) const; - /** - * \returns true if the address matches, false otherwise. - */ - static bool IsMatchingType (const Address &address); + operator Address (); /** * \param address a polymorphic address * * Convert a polymorphic address to an Eui48Address instance. * The conversion performs a type check. */ - static Eui48Address ConvertFrom (const Address &address); + Eui48Address (const Address &address); + /** + * \returns true if the address matches, false otherwise. + */ + static bool IsMatchingType (const Address &address); /** * Allocate a new Eui48Address. */ static Eui48Address Allocate (void); private: + /** + * \returns a new Address instance + * + * Convert an instance of this class to a polymorphic Address instance. + */ + Address ConvertTo (void) const; + static Eui48Address ConvertFrom (const Address &address); static uint8_t GetType (void); uint8_t m_address[6]; }; From 497b9deadceef24de05b545b09523ffa26d325d5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 14:20:10 +0200 Subject: [PATCH 113/278] add implicit conversion to Ipv4Address --- src/node/ipv4-address.cc | 9 +++++++++ src/node/ipv4-address.h | 6 ++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index aae53c65f..91d4d0bc1 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -211,6 +211,15 @@ Ipv4Address::IsMatchingType (const Address &address) { return address.CheckCompatible (GetType (), 4); } +Ipv4Address::operator Address () +{ + return ConvertTo (); +} +Ipv4Address::Ipv4Address (const Address &address) +{ + *this = ConvertFrom (address); +} + Address Ipv4Address::ConvertTo (void) const { diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index 8e8976a18..d17854742 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -105,14 +105,16 @@ public: Ipv4Address CombineMask (Ipv4Mask const &mask) const; static bool IsMatchingType (const Address &address); - Address ConvertTo (void) const; - static Ipv4Address ConvertFrom (const Address &address); + operator Address (); + Ipv4Address (const Address &address); static Ipv4Address GetZero (void); static Ipv4Address GetAny (void); static Ipv4Address GetBroadcast (void); static Ipv4Address GetLoopback (void); private: + Address ConvertTo (void) const; + static Ipv4Address ConvertFrom (const Address &address); static uint8_t GetType (void); uint32_t m_address; }; From f1b93271230a12cd02417211a8e54a08178c0391 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 30 Jul 2007 14:57:49 +0200 Subject: [PATCH 114/278] remove implicit conversion from Address to Eui48Address, to Ipv4Address and to InetSocketAddress --- src/devices/csma-cd/csma-cd-net-device.cc | 12 +++++------- src/internet-node/udp-socket.cc | 8 ++++---- src/node/eui48-address.h | 11 ++++++----- src/node/inet-socket-address.cc | 5 ----- src/node/inet-socket-address.h | 6 +++--- src/node/ipv4-address.cc | 4 ---- src/node/ipv4-address.h | 3 +-- 7 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index c07b8a438..f5936cb8b 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -160,7 +160,7 @@ CsmaCdNetDevice::AddHeader (Packet& p, Eui48Address dest, } EthernetHeader header (false); EthernetTrailer trailer; - Eui48Address source = GetAddress (); + Eui48Address source = Eui48Address::ConvertFrom (GetAddress ()); header.SetSource(source); header.SetDestination(dest); @@ -201,10 +201,8 @@ CsmaCdNetDevice::ProcessHeader (Packet& p, uint16_t & param) trailer.CheckFcs(p); p.RemoveHeader(header); - Eui48Address broadcast = GetBroadcast (); - Eui48Address destination = GetAddress (); - if ((header.GetDestination() != broadcast) && - (header.GetDestination() != destination)) + if ((header.GetDestination() != GetBroadcast ()) && + (header.GetDestination() != GetAddress ())) { return false; } @@ -252,8 +250,8 @@ CsmaCdNetDevice::SendTo (Packet& p, const Address& dest, uint16_t protocolNumber if (!IsSendEnabled()) return false; - Eui48Address address = dest; - AddHeader(p, address, protocolNumber); + Eui48Address destination = Eui48Address::ConvertFrom (dest); + AddHeader(p, destination, protocolNumber); // Place the packet to be sent on the send queue if (m_queue->Enqueue(p) == false ) diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 438e59a53..01ac89c64 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -95,7 +95,7 @@ UdpSocket::Bind (const Address &address) { return ERROR_INVAL; } - InetSocketAddress transport = address; + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); if (ipv4 == Ipv4Address::GetAny () && port == 0) @@ -151,7 +151,7 @@ UdpSocket::DoConnect(const Address & address, ns3::Callback > connectionFailed, ns3::Callback > halfClose) { - InetSocketAddress transport = address; + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); m_defaultAddress = transport.GetIpv4 (); m_defaultPort = transport.GetPort (); if (!connectionSucceeded.IsNull ()) @@ -194,7 +194,7 @@ int UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, ns3::Callback, uint32_t> dataSent) { - InetSocketAddress transport = address; + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); @@ -245,7 +245,7 @@ UdpSocket::DoSendTo(const Address &address, { p = Packet (buffer, size); } - InetSocketAddress transport = address; + InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); return DoSendPacketTo (p, ipv4, port, dataSent); diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h index 3e693f73c..85f3e2202 100644 --- a/src/node/eui48-address.h +++ b/src/node/eui48-address.h @@ -45,11 +45,13 @@ public: operator Address (); /** * \param address a polymorphic address - * - * Convert a polymorphic address to an Eui48Address instance. - * The conversion performs a type check. + * \returns a new Eui48Address from the polymorphic address + * + * This function performs a type check and asserts if the + * type of the input address is not compatible with an + * Eui48Address. */ - Eui48Address (const Address &address); + static Eui48Address ConvertFrom (const Address &address); /** * \returns true if the address matches, false otherwise. */ @@ -65,7 +67,6 @@ private: * Convert an instance of this class to a polymorphic Address instance. */ Address ConvertTo (void) const; - static Eui48Address ConvertFrom (const Address &address); static uint8_t GetType (void); uint8_t m_address[6]; }; diff --git a/src/node/inet-socket-address.cc b/src/node/inet-socket-address.cc index 43c32dcd1..3b2ad5ba8 100644 --- a/src/node/inet-socket-address.cc +++ b/src/node/inet-socket-address.cc @@ -56,11 +56,6 @@ InetSocketAddress::operator Address () const return ConvertTo (); } -InetSocketAddress::InetSocketAddress (const Address &address) -{ - *this = ConvertFrom (address); -} - Address InetSocketAddress::ConvertTo (void) const { diff --git a/src/node/inet-socket-address.h b/src/node/inet-socket-address.h index c09a6c761..0a00172ba 100644 --- a/src/node/inet-socket-address.h +++ b/src/node/inet-socket-address.h @@ -78,13 +78,13 @@ public: /** * \param address the Address instance to convert from. * - * Construct an InetSocketAddress which corresponds to the input + * Returns an InetSocketAddress which corresponds to the input * Address */ - InetSocketAddress (const Address &address); + static InetSocketAddress ConvertFrom (const Address &address); private: Address ConvertTo (void) const; - static InetSocketAddress ConvertFrom (const Address &address); + static uint8_t GetType (void); Ipv4Address m_ipv4; uint16_t m_port; diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 91d4d0bc1..4cf95aa22 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -215,10 +215,6 @@ Ipv4Address::operator Address () { return ConvertTo (); } -Ipv4Address::Ipv4Address (const Address &address) -{ - *this = ConvertFrom (address); -} Address Ipv4Address::ConvertTo (void) const diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index d17854742..a2f94592c 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -106,7 +106,7 @@ public: static bool IsMatchingType (const Address &address); operator Address (); - Ipv4Address (const Address &address); + static Ipv4Address ConvertFrom (const Address &address); static Ipv4Address GetZero (void); static Ipv4Address GetAny (void); @@ -114,7 +114,6 @@ public: static Ipv4Address GetLoopback (void); private: Address ConvertTo (void) const; - static Ipv4Address ConvertFrom (const Address &address); static uint8_t GetType (void); uint32_t m_address; }; From 833462a84e4c1b9725f4b0582e9ce8403dc7cbe0 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 30 Jul 2007 15:50:20 -0700 Subject: [PATCH 115/278] add simple-global-routing.cc --- examples/simple-global-routing.cc | 191 ++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 examples/simple-global-routing.cc diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc new file mode 100644 index 000000000..54db2cd10 --- /dev/null +++ b/examples/simple-global-routing.cc @@ -0,0 +1,191 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ns-2 simple.tcl script (ported from ns-2) + * Originally authored by Steve McCanne, 12/19/1996 + */ + +// Port of ns-2/tcl/ex/simple.tcl to ns-3 +// +// Network topology +// +// n0 +// \ 5 Mb/s, 2ms +// \ 1.5Mb/s, 10ms +// n2 -------------------------n3 +// / +// / 5 Mb/s, 2ms +// n1 +// +// - all links are point-to-point links with indicated one-way BW/delay +// - CBR/UDP flows from n0 to n3, and from n3 to n1 +// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. +// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. +// (i.e., DataRate of 448,000 bps) +// - DropTail queues +// - Tracing of queues and packet receptions to file "simple-global-routing.tr" + +#include +#include +#include +#include + +#include "ns3/debug.h" + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/p2p-channel.h" +#include "ns3/p2p-net-device.h" +#include "ns3/mac-address.h" +#include "ns3/ipv4-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/p2p-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/global-route-manager.h" + +using namespace ns3; + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + DebugComponentEnable ("Object"); + DebugComponentEnable ("Queue"); + DebugComponentEnable ("DropTailQueue"); + DebugComponentEnable ("Channel"); + DebugComponentEnable ("PointToPointChannel"); + DebugComponentEnable ("PointToPointNetDevice"); + DebugComponentEnable ("GlobalRouter"); + DebugComponentEnable ("GlobalRouteManager"); +#endif + + // Set up some default values for the simulation. Use the Bind () + // technique to tell the system what subclass of Queue to use, + // and what the queue limit is + + // The below Bind command tells the queue factory which class to + // instantiate, when the queue factory is invoked in the topology code + Bind ("Queue", "DropTailQueue"); + + Bind ("OnOffApplicationPacketSize", "210"); + Bind ("OnOffApplicationDataRate", "448kb/s"); + + //Bind ("DropTailQueue::m_maxPackets", 30); + + // Allow the user to override any of the defaults and the above + // Bind ()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n2, DataRate (5000000), MilliSeconds (2)); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate (5000000), MilliSeconds (2)); + + Ptr channel2 = + PointToPointTopology::AddPointToPointLink ( + n2, n3, DataRate (1500000), MilliSeconds (10)); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address ("10.1.1.1"), + n2, Ipv4Address ("10.1.1.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address ("10.1.2.1"), + n2, Ipv4Address ("10.1.2.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel2, n2, Ipv4Address ("10.1.3.1"), + n3, Ipv4Address ("10.1.3.2")); + + // Create router nodes, initialize routing database and set up the routing + // tables in the nodes. + GlobalRouteManager::PopulateRoutingTables (); + + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + Ptr ooff = Create ( + n0, + Ipv4Address ("10.1.3.2"), + 80, + "Udp", + ConstantVariable (1), + ConstantVariable (0)); + // Start the application + ooff->Start (Seconds (1.0)); + ooff->Stop (Seconds (10.0)); + + // Create a similar flow from n3 to n1, starting at time 1.1 seconds + ooff = Create ( + n3, + Ipv4Address ("10.1.2.1"), + 80, + "Udp", + ConstantVariable (1), + ConstantVariable (0)); + // Start the application + ooff->Start (Seconds (1.1)); + ooff->Stop (Seconds (10.0)); + + // Here, finish off packet routing configuration + // This will likely set by some GlobalRouting object in the future + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); + ipv4 = n3->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-global-routing.tr file + AsciiTrace asciitrace ("simple-global-routing.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named simple-p2p.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("simple-global-routing.pcap"); + pcaptrace.TraceAllIp (); + + Simulator::Run (); + + Simulator::Destroy (); +} From 7af432c3131955940fe659ccb32c6fa60b09b467 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 07:54:26 +0200 Subject: [PATCH 116/278] small cleanups --- src/node/node.h | 50 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/node/node.h b/src/node/node.h index 4e4e7b8c7..4492a23dd 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -1,29 +1,25 @@ -// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// - -// Define the basic Node object for ns3. -// George F. Riley, Georgia Tech, Fall 2006 - -#ifndef I_NODE_H -#define I_NODE_H +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation, INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: George F. Riley + * Mathieu Lacage + */ +#ifndef NODE_H +#define NODE_H #include @@ -170,4 +166,4 @@ private: } //namespace ns3 -#endif /* I_NODE_H */ +#endif /* NODE_H */ From b4237e51dcc22a8ca402fa41fcac6b41e57cd560 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 09:09:31 +0200 Subject: [PATCH 117/278] implement the Node::ProtocolHandler support. --- src/internet-node/arp-l3-protocol.cc | 12 +- src/internet-node/arp-l3-protocol.h | 7 +- src/internet-node/internet-node.cc | 44 ++----- src/internet-node/internet-node.h | 1 - src/internet-node/ipv4-l3-protocol.cc | 11 +- src/internet-node/ipv4-l3-protocol.h | 6 +- src/internet-node/ipv4-loopback-interface.cc | 6 +- src/internet-node/ipv4-private.cc | 67 ----------- src/internet-node/ipv4-private.h | 58 --------- src/internet-node/ipv4-static-routing.h | 1 - src/internet-node/l3-demux.cc | 90 -------------- src/internet-node/l3-demux.h | 93 --------------- src/internet-node/l3-protocol.cc | 54 --------- src/internet-node/l3-protocol.h | 73 ------------ src/internet-node/udp-l4-protocol.cc | 4 +- src/internet-node/wscript | 3 - src/node/node.cc | 117 +++++++++++++++---- src/node/node.h | 51 +++++++- 18 files changed, 174 insertions(+), 524 deletions(-) delete mode 100644 src/internet-node/ipv4-private.cc delete mode 100644 src/internet-node/ipv4-private.h delete mode 100644 src/internet-node/l3-demux.cc delete mode 100644 src/internet-node/l3-demux.h delete mode 100644 src/internet-node/l3-protocol.cc delete mode 100644 src/internet-node/l3-protocol.h diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index 947d5fc42..1e2d7030f 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -24,11 +24,11 @@ #include "ns3/node.h" #include "ns3/net-device.h" +#include "ipv4-l3-protocol.h" #include "arp-l3-protocol.h" #include "arp-header.h" #include "arp-cache.h" #include "ipv4-interface.h" -#include "ipv4-private.h" NS_DEBUG_COMPONENT_DEFINE ("ArpL3Protocol"); @@ -37,8 +37,7 @@ namespace ns3 { const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806; ArpL3Protocol::ArpL3Protocol (Ptr node) - : L3Protocol (PROT_NUMBER, 0/* XXX: correct version number ? */ ), - m_node (node) + : m_node (node) {} ArpL3Protocol::~ArpL3Protocol () @@ -53,7 +52,7 @@ ArpL3Protocol::DoDispose (void) } m_cacheList.clear (); m_node = 0; - L3Protocol::DoDispose (); + Object::DoDispose (); } TraceResolver * @@ -72,7 +71,7 @@ ArpL3Protocol::FindCache (Ptr device) return *i; } } - Ptr ipv4 = m_node->QueryInterface (Ipv4Private::iid); + Ptr ipv4 = m_node->QueryInterface (Ipv4L3Protocol::iid); Ipv4Interface *interface = ipv4->FindInterfaceForDevice (device); ArpCache * cache = new ArpCache (device, interface); NS_ASSERT (device->IsBroadcast ()); @@ -82,10 +81,11 @@ ArpL3Protocol::FindCache (Ptr device) } void -ArpL3Protocol::Receive(Packet& packet, Ptr device) +ArpL3Protocol::Receive(const Packet& p, uint16_t protocol, Ptr device) { ArpCache *cache = FindCache (device); ArpHeader arp; + Packet packet = p; packet.RemoveHeader (arp); NS_DEBUG ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") << diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index 082bbebb5..ea61ec8af 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -25,7 +25,6 @@ #include "ns3/ipv4-address.h" #include "ns3/address.h" #include "ns3/ptr.h" -#include "l3-protocol.h" namespace ns3 { @@ -38,7 +37,7 @@ class TraceContext; /** * \brief An implementation of the ARP protocol */ -class ArpL3Protocol : public L3Protocol +class ArpL3Protocol : public Object { public: static const uint16_t PROT_NUMBER; @@ -47,13 +46,13 @@ public: * \param node The node which this ARP object is associated with */ ArpL3Protocol (Ptr node); - ~ArpL3Protocol (); + virtual ~ArpL3Protocol (); virtual TraceResolver *CreateTraceResolver (TraceContext const &context); /** * \brief Recieve a packet */ - virtual void Receive(Packet& p, Ptr device); + void Receive(const Packet& p, uint16_t protocol, Ptr device); /** * \brief Perform an ARP lookup * \param p diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index 0400e241f..128a3f332 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -23,8 +23,8 @@ #include "ns3/composite-trace-resolver.h" #include "ns3/net-device.h" +#include "ns3/callback.h" -#include "l3-demux.h" #include "ipv4-l4-demux.h" #include "internet-node.h" #include "udp-l4-protocol.h" @@ -33,7 +33,6 @@ #include "udp-impl.h" #include "arp-private.h" #include "ipv4-impl.h" -#include "ipv4-private.h" namespace ns3 { @@ -56,25 +55,25 @@ InternetNode::Construct (void) { Ptr ipv4 = Create (this); Ptr arp = Create (this); - Ptr udp = Create (this); + // XXX remove the PeekPointer below. + RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, PeekPointer (ipv4)), + Ipv4L3Protocol::PROT_NUMBER, 0); + RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (arp)), + ArpL3Protocol::PROT_NUMBER, 0); + - Ptr l3Demux = Create (this); Ptr ipv4L4Demux = Create (this); - - l3Demux->Insert (ipv4); - l3Demux->Insert (arp); + Ptr udp = Create (this); ipv4L4Demux->Insert (udp); Ptr udpImpl = Create (udp); Ptr arpPrivate = Create (arp); Ptr ipv4Impl = Create (ipv4); - Ptr ipv4Private = Create (ipv4); - Object::AddInterface (ipv4Private); + Object::AddInterface (ipv4); Object::AddInterface (ipv4Impl); Object::AddInterface (arpPrivate); Object::AddInterface (udpImpl); - Object::AddInterface (l3Demux); Object::AddInterface (ipv4L4Demux); } @@ -83,9 +82,9 @@ TraceResolver * InternetNode::DoCreateTraceResolver (TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - Ptr ipv4 = QueryInterface (Ipv4Private::iid); + Ptr ipv4 = QueryInterface (Ipv4L3Protocol::iid); resolver->Add ("ipv4", - MakeCallback (&Ipv4Private::CreateTraceResolver, PeekPointer (ipv4)), + MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)), InternetNode::IPV4); return resolver; @@ -97,25 +96,4 @@ InternetNode::DoDispose() Node::DoDispose (); } -void -InternetNode::DoAddDevice (Ptr device) -{ - device->SetReceiveCallback (MakeCallback (&InternetNode::ReceiveFromDevice, this)); -} - -bool -InternetNode::ReceiveFromDevice (Ptr device, const Packet &p, uint16_t protocolNumber) const -{ - Ptr demux = QueryInterface (L3Demux::iid); - Ptr target = demux->GetProtocol (protocolNumber); - if (target != 0) - { - Packet packet = p; - target->Receive(packet, device); - return true; - } - return false; -} - - }//namespace ns3 diff --git a/src/internet-node/internet-node.h b/src/internet-node/internet-node.h index b577f6b6b..1d63edae5 100644 --- a/src/internet-node/internet-node.h +++ b/src/internet-node/internet-node.h @@ -46,7 +46,6 @@ public: protected: virtual void DoDispose(void); private: - virtual void DoAddDevice (Ptr device); virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); bool ReceiveFromDevice (Ptr device, const Packet &p, uint16_t protocolNumber) const; void Construct (void); diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index 077acb3f7..5718c0b89 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -41,11 +41,11 @@ NS_DEBUG_COMPONENT_DEFINE ("Ipv4L3Protocol"); namespace ns3 { +const InterfaceId Ipv4L3Protocol::iid = MakeInterfaceId ("Ipv4L3Protocol", Object::iid); const uint16_t Ipv4L3Protocol::PROT_NUMBER = 0x0800; Ipv4L3Protocol::Ipv4L3Protocol(Ptr node) - : L3Protocol (PROT_NUMBER, 4), - m_nInterfaces (0), + : m_nInterfaces (0), m_defaultTtl (64), m_identification (0), m_node (node) @@ -66,9 +66,9 @@ Ipv4L3Protocol::DoDispose (void) } m_interfaces.clear (); m_node = 0; - L3Protocol::DoDispose (); m_staticRouting->Dispose (); m_staticRouting = 0; + Object::DoDispose (); } void @@ -240,18 +240,19 @@ Ipv4L3Protocol::FindInterfaceForDevice (Ptr device) } void -Ipv4L3Protocol::Receive(Packet& packet, Ptr device) +Ipv4L3Protocol::Receive(const Packet& p, uint16_t protocol, Ptr device) { uint32_t index = 0; for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) { if ((*i)->GetDevice () == device) { - m_rxTrace (packet, index); + m_rxTrace (p, index); break; } index++; } + Packet packet = p; Ipv4Header ipHeader; packet.RemoveHeader (ipHeader); diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index b41b6aefa..200a001d4 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -30,7 +30,6 @@ #include "ipv4-header.h" #include "ns3/ptr.h" #include "ns3/ipv4.h" -#include "l3-protocol.h" #include "ipv4-static-routing.h" namespace ns3 { @@ -46,9 +45,10 @@ class TraceResolver; class TraceContext; -class Ipv4L3Protocol : public L3Protocol +class Ipv4L3Protocol : public Object { public: + static const InterfaceId iid; static const uint16_t PROT_NUMBER; enum TraceType { @@ -95,7 +95,7 @@ public: * - implement a per-NetDevice ARP cache * - send back arp replies on the right device */ - virtual void Receive(Packet& p, Ptr device); + void Receive(const Packet& p, uint16_t protocol, Ptr device); /** * \param packet packet to send diff --git a/src/internet-node/ipv4-loopback-interface.cc b/src/internet-node/ipv4-loopback-interface.cc index 906c0a001..320a32ce4 100644 --- a/src/internet-node/ipv4-loopback-interface.cc +++ b/src/internet-node/ipv4-loopback-interface.cc @@ -23,7 +23,7 @@ #include "ns3/net-device.h" #include "ns3/node.h" #include "ipv4-loopback-interface.h" -#include "ipv4-private.h" +#include "ipv4-l3-protocol.h" namespace ns3 { @@ -43,8 +43,8 @@ Ipv4LoopbackInterface::DoCreateTraceResolver (TraceContext const &context) void Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest) { - Ptr ipv4 = m_node->QueryInterface (Ipv4Private::iid); - ipv4->Receive (packet, GetDevice ()); + Ptr ipv4 = m_node->QueryInterface (Ipv4L3Protocol::iid); + ipv4->Receive (packet, Ipv4L3Protocol::PROT_NUMBER, GetDevice ()); } }//namespace ns3 diff --git a/src/internet-node/ipv4-private.cc b/src/internet-node/ipv4-private.cc deleted file mode 100644 index 1b9314152..000000000 --- a/src/internet-node/ipv4-private.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ -#include "ipv4-private.h" -#include "ipv4-l3-protocol.h" -#include "ns3/assert.h" -#include "ns3/net-device.h" - -namespace ns3 { - -const InterfaceId Ipv4Private::iid = MakeInterfaceId ("Ipv4Private", Object::iid); - -Ipv4Private::Ipv4Private (Ptr ipv4) - : m_ipv4 (ipv4) -{ - SetInterfaceId (Ipv4Private::iid); -} -Ipv4Private::~Ipv4Private () -{ - NS_ASSERT (m_ipv4 == 0); -} -TraceResolver * -Ipv4Private::CreateTraceResolver (TraceContext const &context) -{ - return m_ipv4->CreateTraceResolver (context); -} -void -Ipv4Private::Send (Packet const &packet, Ipv4Address source, - Ipv4Address destination, uint8_t protocol) -{ - m_ipv4->Send (packet, source, destination, protocol); -} -Ipv4Interface * -Ipv4Private::FindInterfaceForDevice (Ptrdevice) -{ - return m_ipv4->FindInterfaceForDevice (device); -} -void -Ipv4Private::Receive(Packet& p, Ptr device) -{ - m_ipv4->Receive (p, device); -} -void -Ipv4Private::DoDispose (void) -{ - m_ipv4 = 0; - Object::DoDispose (); -} - -} // namespace ns3 diff --git a/src/internet-node/ipv4-private.h b/src/internet-node/ipv4-private.h deleted file mode 100644 index 3208d0f1a..000000000 --- a/src/internet-node/ipv4-private.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ -#ifndef IPV4_PRIVATE_H -#define IPV4_PRIVATE_H - -#include "ns3/object.h" -#include "ns3/ipv4-address.h" -#include "ns3/ptr.h" -#include - -namespace ns3 { - -class Packet; -class Ipv4L3Protocol; -class TraceContext; -class TraceResolver; -class Ipv4Interface; -class NetDevice; - -class Ipv4Private : public Object -{ -public: - static const InterfaceId iid; - Ipv4Private (Ptr ipv4); - virtual ~Ipv4Private (); - - TraceResolver *CreateTraceResolver (TraceContext const &context); - void Send (Packet const &packet, Ipv4Address source, - Ipv4Address destination, uint8_t protocol); - Ipv4Interface *FindInterfaceForDevice (Ptrdevice); - void Receive(Packet& p, Ptr device); -protected: - virtual void DoDispose (void); -private: - Ptr m_ipv4; -}; - -} // namespace ns3 - -#endif /* IPV4_PRIVATE_H */ diff --git a/src/internet-node/ipv4-static-routing.h b/src/internet-node/ipv4-static-routing.h index f7e6d52ab..8462f55a7 100644 --- a/src/internet-node/ipv4-static-routing.h +++ b/src/internet-node/ipv4-static-routing.h @@ -31,7 +31,6 @@ #include "ipv4-header.h" #include "ns3/ptr.h" #include "ns3/ipv4.h" -#include "l3-protocol.h" namespace ns3 { diff --git a/src/internet-node/l3-demux.cc b/src/internet-node/l3-demux.cc deleted file mode 100644 index 6e8416a50..000000000 --- a/src/internet-node/l3-demux.cc +++ /dev/null @@ -1,90 +0,0 @@ -// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// -// Implement the L3Protocols capability for ns3. -// George F. Riley, Georgia Tech, Fall 2006 -#include -#include -#include "ns3/composite-trace-resolver.h" -#include "ns3/node.h" -#include "l3-demux.h" -#include "l3-protocol.h" - -namespace ns3 { - -const InterfaceId L3Demux::iid = MakeInterfaceId ("L3Demux", Object::iid); - -L3Demux::L3Demux (Ptr node) - : m_node (node) -{ - SetInterfaceId (L3Demux::iid); -} - -L3Demux::~L3Demux() -{} - -void -L3Demux::DoDispose (void) -{ - for (L3Map_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) - { - i->second->Dispose (); - i->second = 0; - } - m_protocols.clear (); - m_node = 0; - Object::DoDispose (); -} - -TraceResolver * -L3Demux::CreateTraceResolver (TraceContext const &context) const -{ - CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - for (L3Map_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) - { - std::string protValue; - std::ostringstream oss (protValue); - oss << i->second->GetProtocolNumber (); - ProtocolTraceType context = i->second->GetProtocolNumber (); - resolver->Add (protValue, - MakeCallback (&L3Protocol::CreateTraceResolver, PeekPointer (i->second)), - context); - } - return resolver; -} - -void L3Demux::Insert(Ptr p) -{ - m_protocols.insert(L3Map_t::value_type(p->GetProtocolNumber (), p)); -} - -Ptr -L3Demux::GetProtocol (int p) -{ // Look up a protocol by protocol number - L3Map_t::iterator i = m_protocols.find(p); - if (i == m_protocols.end()) - { - return 0; - } - return i->second; // Return the protocol -} - -} //namespace ns3 - diff --git a/src/internet-node/l3-demux.h b/src/internet-node/l3-demux.h deleted file mode 100644 index 43a3e1b7d..000000000 --- a/src/internet-node/l3-demux.h +++ /dev/null @@ -1,93 +0,0 @@ -// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// -// Define the L3Protocols capability for ns3. -// George F. Riley, Georgia Tech, Fall 2006 - -// This object manages the different layer 3 protocols for any ns3 -// node that has this capability. - -#ifndef L3_DEMUX_H -#define L3_DEMUX_H - -#include -#include "ns3/object.h" -#include "ns3/ptr.h" - -namespace ns3 { - -class L3Protocol; -class Node; -class TraceResolver; -class TraceContext; - -/** - * \brief L3 Demux - */ -class L3Demux : public Object -{ -public: - static const InterfaceId iid; - typedef int ProtocolTraceType; - L3Demux(Ptr node); - virtual ~L3Demux(); - - /** - * \param context the trace context to use to construct the - * TraceResolver to return - * \returns a TraceResolver which can resolve all traces - * performed in this object. The caller must - * delete the returned object. - */ - TraceResolver *CreateTraceResolver (TraceContext const &context) const; - - - /** - * \param protocol a template for the protocol to add to this L3 Demux. - * - * Invoke Copy on the input template to get a copy of the input - * protocol which can be used on the Node on which this L3 Demux - * is running. The new L3Protocol is registered internally as - * a working L3 Protocol and returned from this method. - * The caller does not get ownership of the returned pointer. - */ - void Insert(Ptr protocol); - /** - * \param protocolNumber number of protocol to lookup - * in this L4 Demux - * \returns a matching L3 Protocol - * - * This method is typically called by lower layers - * to forward packets up the stack to the right protocol. - * It is also called from NodeImpl::GetIpv4 for example. - */ - Ptr GetProtocol (int protocolNumber); -protected: - virtual void DoDispose (void); -private: - typedef std::map > L3Map_t; - - Ptr m_node; - L3Map_t m_protocols; -}; - -} //namespace ns3 -#endif - diff --git a/src/internet-node/l3-protocol.cc b/src/internet-node/l3-protocol.cc deleted file mode 100644 index 71dbc2d46..000000000 --- a/src/internet-node/l3-protocol.cc +++ /dev/null @@ -1,54 +0,0 @@ -// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// - -// NS3 - Layer 3 Protocol base class -// George F. Riley, Georgia Tech, Spring 2007 - -#include "l3-protocol.h" - - -namespace ns3 { - -L3Protocol::L3Protocol(int protocolNumber, int version) - : m_protocolNumber (protocolNumber), - m_version (version) -{} -L3Protocol::~L3Protocol () -{} - -int -L3Protocol::GetProtocolNumber (void) const -{ - return m_protocolNumber; -} -int -L3Protocol::GetVersion() const -{ - return m_version; -} - -void -L3Protocol::DoDispose (void) -{ - Object::DoDispose (); -} - -}//namespace ns3 diff --git a/src/internet-node/l3-protocol.h b/src/internet-node/l3-protocol.h deleted file mode 100644 index e0c2a469a..000000000 --- a/src/internet-node/l3-protocol.h +++ /dev/null @@ -1,73 +0,0 @@ -// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// - -// NS3 - Layer 3 Protocol base class -// George F. Riley, Georgia Tech, Spring 2007 - -#ifndef L3_PROTOCOL_H -#define L3_PROTOCOL_H - -#include "ns3/object.h" -#include "ns3/ptr.h" - -namespace ns3 { - -class Packet; -class NetDevice; -class TraceResolver; -class TraceContext; - -/** - * ::Send is always defined in subclasses. - */ -class L3Protocol : public Object { -public: - L3Protocol(int protocolNumber, int version); - virtual ~L3Protocol (); - /** - * \return The protocol number of this Layer 3 protocol - */ - int GetProtocolNumber (void) const; - /** - * \return The version number of this protocol - */ - int GetVersion() const; - - virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0; - /** - * Lower layer calls this method after calling L3Demux::Lookup - * The ARP subclass needs to know from which NetDevice this - * packet is coming to: - * - implement a per-NetDevice ARP cache - * - send back arp replies on the right device - */ - virtual void Receive(Packet& p, Ptr device) = 0; - -protected: - virtual void DoDispose (void); -private: - int m_protocolNumber; - int m_version; -}; - -} // Namespace ns3 - -#endif diff --git a/src/internet-node/udp-l4-protocol.cc b/src/internet-node/udp-l4-protocol.cc index 90fb782b9..f0ef8569b 100644 --- a/src/internet-node/udp-l4-protocol.cc +++ b/src/internet-node/udp-l4-protocol.cc @@ -29,8 +29,6 @@ #include "ipv4-end-point-demux.h" #include "ipv4-end-point.h" #include "ipv4-l3-protocol.h" -#include "ipv4-private.h" -#include "l3-demux.h" #include "udp-socket.h" namespace ns3 { @@ -138,7 +136,7 @@ UdpL4Protocol::Send (Packet packet, packet.AddHeader (udpHeader); - Ptr ipv4 = m_node->QueryInterface (Ipv4Private::iid); + Ptr ipv4 = m_node->QueryInterface (Ipv4L3Protocol::iid); if (ipv4 != 0) { ipv4->Send (packet, saddr, daddr, PROT_NUMBER); diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 7a1b1c10e..b94277456 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -8,8 +8,6 @@ def build(bld): obj.uselib_local = ['ns3-node', 'ns3-applications'] obj.source = [ 'internet-node.cc', - 'l3-demux.cc', - 'l3-protocol.cc', 'ipv4-l4-demux.cc', 'ipv4-l4-protocol.cc', 'ipv4-header.cc', @@ -29,7 +27,6 @@ def build(bld): 'ipv4-end-point-demux.cc', 'arp-private.cc', 'ipv4-impl.cc', - 'ipv4-private.cc', 'ascii-trace.cc', 'pcap-trace.cc', 'udp-impl.cc', diff --git a/src/node/node.cc b/src/node/node.cc index fa33ff7df..5c3d7c6f3 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -1,32 +1,29 @@ -// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// - -// Implement the basic Node object for ns3. -// George F. Riley, Georgia Tech, Fall 2006 - +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation, INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: George F. Riley + * Mathieu Lacage + */ #include "node.h" #include "node-list.h" #include "net-device.h" #include "application.h" #include "ns3/simulator.h" +#include "ns3/empty-trace-resolver.h" namespace ns3{ @@ -74,8 +71,9 @@ Node::AddDevice (Ptr device) { uint32_t index = m_devices.size (); m_devices.push_back (device); - DoAddDevice (device); device->SetIfIndex(index); + device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this)); + NotifyDeviceAdded (device); return index; } Ptr @@ -129,4 +127,73 @@ void Node::DoDispose() Object::DoDispose (); } +TraceResolver * +Node::DoCreateTraceResolver (TraceContext const &context) +{ + return new EmptyTraceResolver (context); +} +void +Node::NotifyDeviceAdded (Ptr device) +{} + +void +Node::RegisterProtocolHandler (ProtocolHandler handler, + uint16_t protocolType, + Ptr device) +{ + struct Node::ProtocolHandlerEntry entry; + entry.handler = handler; + entry.isSpecificProtocol = true; + entry.protocol = protocolType; + entry.device = device; + m_handlers.push_back (entry); +} + +void +Node::RegisterProtocolHandler (ProtocolHandler handler, + Ptr device) +{ + struct Node::ProtocolHandlerEntry entry; + entry.handler = handler; + entry.isSpecificProtocol = false; + entry.protocol = 0; + entry.device = device; + m_handlers.push_back (entry); +} + +void +Node::UnregisterProtocolHandler (ProtocolHandler handler) +{ + for (ProtocolHandlerList::iterator i = m_handlers.begin (); + i != m_handlers.end (); i++) + { + if (i->handler.IsEqual (handler)) + { + m_handlers.erase (i); + break; + } + } +} + +bool +Node::ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol) +{ + bool found = false; + for (ProtocolHandlerList::iterator i = m_handlers.begin (); + i != m_handlers.end (); i++) + { + if (i->device == 0 || + (i->device != 0 && i->device == device)) + { + if (!i->isSpecificProtocol || + (i->isSpecificProtocol && i->protocol == protocol)) + { + i->handler (packet, protocol, device); + found = true; + } + } + } + return found; +} + }//namespace ns3 diff --git a/src/node/node.h b/src/node/node.h index 4492a23dd..2e3953458 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -24,6 +24,7 @@ #include #include "ns3/object.h" +#include "ns3/callback.h" namespace ns3 { @@ -31,6 +32,7 @@ class TraceContext; class TraceResolver; class NetDevice; class Application; +class Packet; /** * \brief A network Node. @@ -123,6 +125,41 @@ public: */ uint32_t GetNApplications (void) const; + /** + * A protocol handler + */ + typedef Callback > ProtocolHandler; + /** + * \param handler the handler to register + * \param protocolType the type of protocol this handler is + * interested in. + * \param device the device attached to this handler. If the + * value is zero, the handler is attached to all + * devices on this node. + */ + void RegisterProtocolHandler (ProtocolHandler handler, + uint16_t protocolType, + Ptr device); + /** + * \param handler the handler to register + * \param device the device attached to this handler. If the + * value is zero, the handler is attached to all + * devices on this node. + * + * Register a handler to receive all packets for all + * protocols. + */ + void RegisterProtocolHandler (ProtocolHandler handler, + Ptr device); + + /** + * \param handler the handler to unregister + * + * After this call returns, the input handler will never + * be invoked anymore. + */ + void UnregisterProtocolHandler (ProtocolHandler handler); + protected: /** * Must be invoked by subclasses only. @@ -147,7 +184,7 @@ private: * * Subclasses must implement this method. */ - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0; + virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); /** * \param device the device added to this Node. * @@ -156,12 +193,22 @@ private: * at this point to setup the node's receive function for * the NetDevice packets. */ - virtual void DoAddDevice (Ptr device) = 0; + virtual void NotifyDeviceAdded (Ptr device); + bool ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol); + + struct ProtocolHandlerEntry { + ProtocolHandler handler; + bool isSpecificProtocol; + uint16_t protocol; + Ptr device; + }; + typedef std::vector ProtocolHandlerList; uint32_t m_id; // Node id for this node uint32_t m_sid; // System id for this node std::vector > m_devices; std::vector > m_applications; + ProtocolHandlerList m_handlers; }; } //namespace ns3 From 8c80e6c2f8c3540374e53f6b170f26803eb276d7 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 09:17:05 +0200 Subject: [PATCH 118/278] remove now-unused ArpPrivate class --- src/internet-node/arp-ipv4-interface.cc | 9 ++-- src/internet-node/arp-l3-protocol.cc | 1 + src/internet-node/arp-l3-protocol.h | 1 + src/internet-node/arp-private.cc | 56 ------------------------- src/internet-node/arp-private.h | 51 ---------------------- src/internet-node/internet-node.cc | 4 +- src/internet-node/wscript | 1 - 7 files changed, 7 insertions(+), 116 deletions(-) delete mode 100644 src/internet-node/arp-private.cc delete mode 100644 src/internet-node/arp-private.h diff --git a/src/internet-node/arp-ipv4-interface.cc b/src/internet-node/arp-ipv4-interface.cc index d5a9105fe..313bb5851 100644 --- a/src/internet-node/arp-ipv4-interface.cc +++ b/src/internet-node/arp-ipv4-interface.cc @@ -28,8 +28,8 @@ #include "ns3/address.h" #include "arp-ipv4-interface.h" -#include "arp-private.h" #include "ipv4-l3-protocol.h" +#include "arp-l3-protocol.h" namespace ns3 { @@ -60,18 +60,17 @@ ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest) NS_ASSERT (GetDevice () != 0); if (GetDevice ()->NeedsArp ()) { - Ptr arp = m_node->QueryInterface (ArpPrivate::iid); + Ptr arp = m_node->QueryInterface (ArpL3Protocol::iid); Address hardwareDestination; bool found; if (dest.IsBroadcast ()) { - hardwareDestination = GetDevice ()->GetBroadcast (); - found = true; + hardwareDestination = GetDevice ()->GetBroadcast (); + found = true; } else { - Ptr arp = m_node->QueryInterface (ArpPrivate::iid); found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination); } diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index 1e2d7030f..130f3a1b4 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -34,6 +34,7 @@ NS_DEBUG_COMPONENT_DEFINE ("ArpL3Protocol"); namespace ns3 { +const InterfaceId ArpL3Protocol::iid = MakeInterfaceId ("ArpL3Protocol", Object::iid); const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806; ArpL3Protocol::ArpL3Protocol (Ptr node) diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index ea61ec8af..d3ae7441d 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -40,6 +40,7 @@ class TraceContext; class ArpL3Protocol : public Object { public: + static const InterfaceId iid; static const uint16_t PROT_NUMBER; /** * \brief Constructor diff --git a/src/internet-node/arp-private.cc b/src/internet-node/arp-private.cc deleted file mode 100644 index 4f60dac99..000000000 --- a/src/internet-node/arp-private.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ -#include "arp-private.h" -#include "arp-l3-protocol.h" -#include "ns3/assert.h" -#include "ns3/net-device.h" - -namespace ns3 { - -const InterfaceId ArpPrivate::iid = MakeInterfaceId ("ArpPrivate", Object::iid); - -ArpPrivate::ArpPrivate (Ptr arp) - : m_arp (arp) -{ - SetInterfaceId (ArpPrivate::iid); -} -ArpPrivate::~ArpPrivate () -{ - NS_ASSERT (m_arp == 0); -} - -bool -ArpPrivate::Lookup (Packet &p, Ipv4Address destination, - Ptr device, - Address *hardwareDestination) -{ - return m_arp->Lookup (p, destination, device, hardwareDestination); -} - -void -ArpPrivate::DoDispose (void) -{ - m_arp = 0; - Object::DoDispose (); -} - - -} // namespace ns3 diff --git a/src/internet-node/arp-private.h b/src/internet-node/arp-private.h deleted file mode 100644 index af0b8b7a3..000000000 --- a/src/internet-node/arp-private.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ -#ifndef ARP_PRIVATE_H -#define ARP_PRIVATE_H - -#include "ns3/object.h" -#include "ns3/ipv4-address.h" - -namespace ns3 { - -class NetDevice; -class Address; -class Packet; -class ArpL3Protocol; - -class ArpPrivate : public Object -{ -public: - static const InterfaceId iid; - ArpPrivate (Ptr arp); - virtual ~ArpPrivate (); - bool Lookup (Packet &p, Ipv4Address destination, - Ptr device, - Address *hardwareDestination); -protected: - virtual void DoDispose (void); -private: - Ptr m_arp; -}; - -} // namespace ns3 - -#endif /* ARP_PRIVATE_H */ diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index 128a3f332..fa0bb1471 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -31,7 +31,6 @@ #include "ipv4-l3-protocol.h" #include "arp-l3-protocol.h" #include "udp-impl.h" -#include "arp-private.h" #include "ipv4-impl.h" namespace ns3 { @@ -67,12 +66,11 @@ InternetNode::Construct (void) ipv4L4Demux->Insert (udp); Ptr udpImpl = Create (udp); - Ptr arpPrivate = Create (arp); Ptr ipv4Impl = Create (ipv4); Object::AddInterface (ipv4); + Object::AddInterface (arp); Object::AddInterface (ipv4Impl); - Object::AddInterface (arpPrivate); Object::AddInterface (udpImpl); Object::AddInterface (ipv4L4Demux); } diff --git a/src/internet-node/wscript b/src/internet-node/wscript index b94277456..e0af13434 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -25,7 +25,6 @@ def build(bld): 'ipv4-loopback-interface.cc', 'udp-socket.cc', 'ipv4-end-point-demux.cc', - 'arp-private.cc', 'ipv4-impl.cc', 'ascii-trace.cc', 'pcap-trace.cc', From 1454050eef632fc9ace836900cac488340631e04 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 09:21:40 +0200 Subject: [PATCH 119/278] forgot to set the interface id --- src/internet-node/arp-l3-protocol.cc | 4 +++- src/internet-node/ipv4-l3-protocol.cc | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index 130f3a1b4..a18b2ab5d 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -39,7 +39,9 @@ const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806; ArpL3Protocol::ArpL3Protocol (Ptr node) : m_node (node) -{} +{ + SetInterfaceId (ArpL3Protocol::iid); +} ArpL3Protocol::~ArpL3Protocol () {} diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index 5718c0b89..eaf2734a3 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -50,6 +50,7 @@ Ipv4L3Protocol::Ipv4L3Protocol(Ptr node) m_identification (0), m_node (node) { + SetInterfaceId (Ipv4L3Protocol::iid); m_staticRouting = Create (); AddRoutingProtocol (m_staticRouting, 0); SetupLoopback (); From f7f981d5496962e26554594286b6ecefc9a70054 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 10:45:15 +0200 Subject: [PATCH 120/278] fix bugless in address allocation --- src/node/eui48-address.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 8196d7ba3..5e552b59a 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -95,7 +95,7 @@ Eui48Address::Allocate (void) static uint64_t id = 0; id++; Eui48Address address; - address.m_address[0] = (id >> 48) & 0xff; + address.m_address[0] = (id >> 40) & 0xff; address.m_address[1] = (id >> 32) & 0xff; address.m_address[2] = (id >> 24) & 0xff; address.m_address[3] = (id >> 16) & 0xff; From af6bed499534d27ee0a226777d6f7b65cbd143b2 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 10:45:37 +0200 Subject: [PATCH 121/278] an eui 64 address type --- src/node/eui64-address.cc | 147 ++++++++++++++++++++++++++++++++++++++ src/node/eui64-address.h | 71 ++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 src/node/eui64-address.cc create mode 100644 src/node/eui64-address.h diff --git a/src/node/eui64-address.cc b/src/node/eui64-address.cc new file mode 100644 index 000000000..b883fb362 --- /dev/null +++ b/src/node/eui64-address.cc @@ -0,0 +1,147 @@ +#include "eui48-address.h" +#include "address.h" +#include "ns3/assert.h" +#include +#include + +namespace ns3 { + +#define ASCII_a (0x41) +#define ASCII_z (0x5a) +#define ASCII_A (0x61) +#define ASCII_Z (0x7a) +#define ASCII_COLON (0x3a) +#define ASCII_ZERO (0x30) + +static char +AsciiToLowCase (char c) +{ + if (c >= ASCII_a && c <= ASCII_z) { + return c; + } else if (c >= ASCII_A && c <= ASCII_Z) { + return c + (ASCII_a - ASCII_A); + } else { + return c; + } +} + + +Eui64Address::Eui64Address () +{ + memset (m_address, 0, 8); +} +Eui64Address::Eui64Address (const char *str) +{ + int i = 0; + while (*str != 0 && i < 8) + { + uint8_t byte = 0; + while (*str != ASCII_COLON && *str != 0) + { + byte <<= 4; + char low = AsciiToLowCase (*str); + if (low >= ASCII_a) + { + byte |= low - ASCII_a + 10; + } + else + { + byte |= low - ASCII_ZERO; + } + str++; + } + m_address[i] = byte; + i++; + if (*str == 0) + { + break; + } + str++; + } + NS_ASSERT (i == 6); +} +void +Eui64Address::CopyFrom (const uint8_t buffer[8]) +{ + memcpy (m_address, buffer, 8); +} +void +Eui64Address::CopyTo (uint8_t buffer[8]) const +{ + memcpy (buffer, m_address, 8); +} + +bool +Eui64Address::IsMatchingType (const Address &address) +{ + return address.CheckCompatible (GetType (), 8); +} +Address +Eui64Address::ConvertTo (void) const +{ + return Address (GetType (), m_address, 8); +} +Eui64Address +Eui64Address::ConvertFrom (const Address &address) +{ + NS_ASSERT (address.CheckCompatible (GetType (), 8)); + Eui64Address retval; + address.CopyTo (retval.m_address); + return retval; +} +Eui64Address +Eui64Address::Allocate (void) +{ + static uint64_t id = 0; + id++; + Eui64Address address; + address.m_address[0] = (id >> 56) & 0xff; + address.m_address[1] = (id >> 48) & 0xff; + address.m_address[2] = (id >> 40) & 0xff; + address.m_address[3] = (id >> 32) & 0xff; + address.m_address[4] = (id >> 24) & 0xff; + address.m_address[5] = (id >> 16) & 0xff; + address.m_address[6] = (id >> 8) & 0xff; + address.m_address[7] = (id >> 0) & 0xff; + return address; +} +uint8_t +Eui64Address::GetType (void) +{ + static uint8_t type = Address::Register (); + return type; +} + +bool operator == (const Eui64Address &a, const Eui64Address &b) +{ + uint8_t ada[8]; + uint8_t adb[8]; + a.CopyTo (ada); + b.CopyTo (adb); + return memcmp (ada, adb, 8) == 0; +} +bool operator != (const Eui64Address &a, const Eui64Address &b) +{ + return ! (a == b); +} + +std::ostream& operator<< (std::ostream& os, const Eui64Address & address) +{ + uint8_t ad[8]; + address.CopyTo (ad); + + os.setf (std::ios::hex, std::ios::basefield); + std::cout.fill('0'); + for (uint8_t i=0; i < 7; i++) + { + os << std::setw(2) << (uint32_t)ad[i] << ":"; + } + // Final byte not suffixed by ":" + os << std::setw(2) << (uint32_t)ad[7]; + os.setf (std::ios::dec, std::ios::basefield); + std::cout.fill(' '); + return os; +} + + +} // namespace ns3 diff --git a/src/node/eui64-address.h b/src/node/eui64-address.h new file mode 100644 index 000000000..fb2b38177 --- /dev/null +++ b/src/node/eui64-address.h @@ -0,0 +1,71 @@ +#ifndef EUI64_ADDRESS_H +#define EUI64_ADDRESS_H + +#include +#include + +namespace ns3 { + +class Address; + +/** + * \brief an EUI-48 address + * + * This class can contain 48 bit IEEE addresses. + */ +class Eui64Address +{ +public: + Eui64Address (); + /** + * \param str a string representing the new Eui64Address + * + * The format of the string is "xx:xx:xx:xx:xx:xx" + */ + Eui64Address (const char *str); + + /** + * \param buffer address in network order + * + * Copy the input address to our internal buffer. + */ + void CopyFrom (const uint8_t buffer[8]); + /** + * \param buffer address in network order + * + * Copy the internal address to the input buffer. + */ + void CopyTo (uint8_t buffer[8]) const; + /** + * \returns a new Address instance + * + * Convert an instance of this class to a polymorphic Address instance. + */ + Address ConvertTo (void) const; + /** + * \returns true if the address matches, false otherwise. + */ + static bool IsMatchingType (const Address &address); + /** + * \param address a polymorphic address + * + * Convert a polymorphic address to an Eui64Address instance. + * The conversion performs a type check. + */ + static Eui64Address ConvertFrom (const Address &address); + /** + * Allocate a new Eui64Address. + */ + static Eui64Address Allocate (void); +private: + static uint8_t GetType (void); + uint8_t m_address[8]; +}; + +bool operator == (const Eui64Address &a, const Eui64Address &b); +bool operator != (const Eui64Address &a, const Eui64Address &b); +std::ostream& operator<< (std::ostream& os, const Eui64Address & address); + +} // namespace ns3 + +#endif /* EUI64_ADDRESS_H */ From 530b65e51d961ed96f9d8931af708794f33f11ed Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 10:46:43 +0200 Subject: [PATCH 122/278] add license headers --- src/node/eui48-address.cc | 19 +++++++++++++++++++ src/node/eui48-address.h | 19 +++++++++++++++++++ src/node/eui64-address.cc | 19 +++++++++++++++++++ src/node/eui64-address.h | 19 +++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 5e552b59a..096a1cc38 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -1,3 +1,22 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ #include "eui48-address.h" #include "address.h" #include "ns3/assert.h" diff --git a/src/node/eui48-address.h b/src/node/eui48-address.h index 1d6c37da1..3156782ef 100644 --- a/src/node/eui48-address.h +++ b/src/node/eui48-address.h @@ -1,3 +1,22 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ #ifndef EUI48_ADDRESS_H #define EUI48_ADDRESS_H diff --git a/src/node/eui64-address.cc b/src/node/eui64-address.cc index b883fb362..31b6d3399 100644 --- a/src/node/eui64-address.cc +++ b/src/node/eui64-address.cc @@ -1,3 +1,22 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ #include "eui48-address.h" #include "address.h" #include "ns3/assert.h" diff --git a/src/node/eui64-address.h b/src/node/eui64-address.h index fb2b38177..6b407bfa0 100644 --- a/src/node/eui64-address.h +++ b/src/node/eui64-address.h @@ -1,3 +1,22 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ #ifndef EUI64_ADDRESS_H #define EUI64_ADDRESS_H From 3d9d4ce7be89df74ed297196fa07a31f52dfb803 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 10:47:29 +0200 Subject: [PATCH 123/278] I wonder what the point of that code was: why should you test for zero _after_ using the pointer ? It needs to be tested _before_. --- src/internet-node/udp-socket.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index bc83c942c..bdbc08887 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -73,12 +73,12 @@ UdpSocket::Destroy (void) int UdpSocket::FinishBind (void) { - m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this)); - m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this)); if (m_endPoint == 0) { return -1; } + m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this)); + m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this)); return 0; } From 354e017a33b4c488b092430c0fb2a735e2e5a1fe Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 11:33:44 +0200 Subject: [PATCH 124/278] fix build --- src/node/eui64-address.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/eui64-address.cc b/src/node/eui64-address.cc index 31b6d3399..342fd4d91 100644 --- a/src/node/eui64-address.cc +++ b/src/node/eui64-address.cc @@ -17,7 +17,7 @@ * * Author: Mathieu Lacage */ -#include "eui48-address.h" +#include "eui64-address.h" #include "address.h" #include "ns3/assert.h" #include From f8baaaf61702bd6dce9a676b2902b223ba44ed1e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 11:42:10 +0200 Subject: [PATCH 125/278] extra Address API to be used by packet socket address --- src/node/address.cc | 21 ++++++++++++++++++++- src/node/address.h | 13 ++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/node/address.cc b/src/node/address.cc index d73f5790e..2979239c4 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -53,15 +53,34 @@ Address::CopyTo (uint8_t buffer[MAX_SIZE]) const memcpy (buffer, m_data, m_len); } void -Address::CopyFrom (uint8_t *buffer, uint8_t len) +Address::CopyAllTo (uint8_t *buffer, uint8_t len) const +{ + NS_ASSERT (len >= m_len + 2); + buffer[0] = m_type; + buffer[1] = m_len; + memcpy (buffer + 2, m_data, m_len); +} + +void +Address::CopyFrom (const uint8_t *buffer, uint8_t len) { NS_ASSERT (len <= MAX_SIZE); memcpy (m_data, buffer, len); m_len = len; } +void +Address::CopyAllFrom (const uint8_t *buffer, uint8_t len) +{ + NS_ASSERT (len >= 2); + m_type = buffer[0]; + m_len = buffer[1]; + NS_ASSERT (len >= m_len + 2); + memcpy (m_data, buffer + 2, m_len); +} bool Address::CheckCompatible (uint8_t type, uint8_t len) const { + NS_ASSERT (len <= MAX_SIZE); return m_len == len && (m_type == type || m_type == 0); } diff --git a/src/node/address.h b/src/node/address.h index e6bbec026..20ea4b46f 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -94,6 +94,11 @@ public: * \param buffer buffer to copy the address bytes to. */ void CopyTo (uint8_t buffer[MAX_SIZE]) const; + /** + * \param buffer buffer to copy the whole address data structure to + * \param len the size of the buffer + */ + void CopyAllTo (uint8_t *buffer, uint8_t len) const; /** * \param buffer pointer to a buffer of bytes which contain * a serialized representation of the address in network @@ -103,7 +108,13 @@ public: * Copy the input buffer to the internal buffer of this address * instance. */ - void CopyFrom (uint8_t *buffer, uint8_t len); + void CopyFrom (const uint8_t *buffer, uint8_t len); + /** + * \param buffer pointer to a buffer of bytes which contain + * a copy of all the members of this Address class. + * \param len the length of the buffer + */ + void CopyAllFrom (const uint8_t *buffer, uint8_t len); /** * \param type a type id as returned by Address::Register * \param len the length associated to this type id. From 39633a0f0992fa173aa9f30bb58228bac10188cd Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 31 Jul 2007 11:42:25 +0200 Subject: [PATCH 126/278] packet socket address --- src/node/packet-socket-address.cc | 113 ++++++++++++++++++++++++++++++ src/node/packet-socket-address.h | 71 +++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 src/node/packet-socket-address.cc create mode 100644 src/node/packet-socket-address.h diff --git a/src/node/packet-socket-address.cc b/src/node/packet-socket-address.cc new file mode 100644 index 000000000..2d2288fca --- /dev/null +++ b/src/node/packet-socket-address.cc @@ -0,0 +1,113 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "packet-socket-address.h" +#include "net-device.h" + +namespace ns3 { + +PacketSocketAddress::PacketSocketAddress () +{} +void +PacketSocketAddress::SetProtocol (uint16_t protocol) +{ + m_protocol = protocol; +} +void +PacketSocketAddress::SetDevice (uint32_t index) +{ + m_device = index; +} +void +PacketSocketAddress::SetPhysicalAddress (const Address address) +{ + m_address = address; +} + +uint16_t +PacketSocketAddress::GetProtocol (void) const +{ + return m_protocol; +} +uint32_t +PacketSocketAddress::GetDevice (void) const +{ + return m_device; +} +Address +PacketSocketAddress::GetPhysicalAddress (void) const +{ + return m_address; +} + +Address +PacketSocketAddress::ConvertTo (void) const +{ + Address address; + uint8_t buffer[Address::MAX_SIZE]; + buffer[0] = m_protocol & 0xff; + buffer[1] = (m_protocol >> 8) & 0xff; + buffer[2] = (m_device >> 24) & 0xff; + buffer[3] = (m_device >> 16) & 0xff; + buffer[4] = (m_device >> 8) & 0xff; + buffer[5] = (m_device >> 0) & 0xff; + m_address.CopyAllTo (buffer + 6, Address::MAX_SIZE - 6); + return Address (GetType (), buffer, GetSize ()); +} +PacketSocketAddress +PacketSocketAddress::ConvertFrom (const Address &address) +{ + NS_ASSERT (IsMatchingType (address)); + uint8_t buffer[Address::MAX_SIZE]; + address.CopyTo (buffer); + uint16_t protocol = buffer[0] | (buffer[1] << 8); + uint32_t device = 0; + device |= buffer[2]; + device <<= 8; + device |= buffer[3]; + device <<= 8; + device |= buffer[4]; + device <<= 8; + device |= buffer[5]; + Address physical; + physical.CopyAllFrom (buffer + 6, Address::MAX_SIZE - 6); + PacketSocketAddress ad; + ad.SetProtocol (protocol); + ad.SetDevice (device); + ad.SetPhysicalAddress (physical); + return ad; +} +bool +PacketSocketAddress::IsMatchingType (const Address &address) +{ + return address.CheckCompatible (GetType (), GetSize ()); +} +uint8_t +PacketSocketAddress::GetType (void) +{ + static uint8_t type = Address::Register (); + return type; +} +uint8_t +PacketSocketAddress::GetSize (void) +{ + return 2 + sizeof (NetDevice *) + 1 + 1 + 8; +} + +} // namespace ns3 diff --git a/src/node/packet-socket-address.h b/src/node/packet-socket-address.h new file mode 100644 index 000000000..5e8265b4d --- /dev/null +++ b/src/node/packet-socket-address.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef PACKET_SOCKET_ADDRESS_H +#define PACKET_SOCKET_ADDRESS_H + +#include "address.h" +#include "eui48-address.h" +#include "eui64-address.h" + +namespace ns3 { + +class NetDevice; + +class PacketSocketAddress +{ + public: + PacketSocketAddress (); + void SetProtocol (uint16_t protocol); + void SetDevice (uint32_t index); + void SetPhysicalAddress (const Address address); + + uint16_t GetProtocol (void) const; + uint32_t GetDevice (void) const; + Address GetPhysicalAddress (void) const; + + /** + * \returns a new Address instance + * + * Convert an instance of this class to a polymorphic Address instance. + */ + Address ConvertTo (void) const; + /** + * \param address a polymorphic address + * + * Convert a polymorphic address to an Eui48Address instance. + * The conversion performs a type check. + */ + static PacketSocketAddress ConvertFrom (const Address &address); + /** + * \returns true if the address matches, false otherwise. + */ + static bool IsMatchingType (const Address &address); + private: + static uint8_t GetType (void); + static uint8_t GetSize (void); + uint16_t m_protocol; + uint32_t m_device; + Address m_address; +}; + + +} // namespace ns3 + +#endif /* PACKET_SOCKET_ADDRESS_H */ From 4886a7c0fece1f78043ad8b09d5ac36268be3ab3 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 31 Jul 2007 13:49:11 +0100 Subject: [PATCH 127/278] Add emacs C++ mode selection line, missing from some header files. --- src/mobility/position.h | 1 + src/mobility/random-position.h | 1 + src/mobility/speed.h | 1 + src/mobility/static-speed-helper.h | 1 + 4 files changed, 4 insertions(+) diff --git a/src/mobility/position.h b/src/mobility/position.h index 884ba50b0..d34fadfb2 100644 --- a/src/mobility/position.h +++ b/src/mobility/position.h @@ -1,3 +1,4 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ #ifndef POSITION_H #define POSITION_H diff --git a/src/mobility/random-position.h b/src/mobility/random-position.h index ee97a2286..8fcc54a6d 100644 --- a/src/mobility/random-position.h +++ b/src/mobility/random-position.h @@ -1,3 +1,4 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ #ifndef RANDOM_POSITION_H #define RANDOM_POSITION_H diff --git a/src/mobility/speed.h b/src/mobility/speed.h index 5e2ad3c45..317fc4333 100644 --- a/src/mobility/speed.h +++ b/src/mobility/speed.h @@ -1,3 +1,4 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ #ifndef SPEED_H #define SPEED_H diff --git a/src/mobility/static-speed-helper.h b/src/mobility/static-speed-helper.h index 0ba541b75..8737f2edd 100644 --- a/src/mobility/static-speed-helper.h +++ b/src/mobility/static-speed-helper.h @@ -1,3 +1,4 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ #ifndef STATIC_SPEED_HELPER_H #define STATIC_SPEED_HELPER_H From d3f1f2a3416a777a69c3a959f7267275143468c8 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 31 Jul 2007 09:45:13 -0700 Subject: [PATCH 128/278] remove manual routing commands from example script --- examples/simple-global-routing.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index 54db2cd10..d5038f389 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -164,14 +164,6 @@ int main (int argc, char *argv[]) ooff->Start (Seconds (1.1)); ooff->Stop (Seconds (10.0)); - // Here, finish off packet routing configuration - // This will likely set by some GlobalRouting object in the future - Ptr ipv4; - ipv4 = n0->QueryInterface (Ipv4::iid); - ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); - ipv4 = n3->QueryInterface (Ipv4::iid); - ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); - // Configure tracing of all enqueue, dequeue, and NetDevice receive events // Trace output will be sent to the simple-global-routing.tr file AsciiTrace asciitrace ("simple-global-routing.tr"); From e05f635db5cd521e3a737aaaaafda73b95727dfd Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 08:58:18 +0200 Subject: [PATCH 129/278] rework the NetDevice <-> Node interface --- src/devices/csma-cd/csma-cd-net-device.cc | 62 +++++++++++++++---- src/devices/csma-cd/csma-cd-net-device.h | 2 +- .../point-to-point-net-device.cc | 6 +- src/internet-node/arp-l3-protocol.cc | 2 +- src/internet-node/arp-l3-protocol.h | 2 +- src/internet-node/ipv4-l3-protocol.cc | 2 +- src/internet-node/ipv4-l3-protocol.h | 2 +- src/internet-node/ipv4-loopback-interface.cc | 2 +- src/internet-node/udp-socket.cc | 32 +++++----- src/internet-node/udp-socket.h | 28 ++++----- src/node/net-device.cc | 13 ++-- src/node/net-device.h | 21 +++++-- src/node/node.cc | 45 +++++++------- src/node/node.h | 51 ++++++++------- src/node/socket.cc | 8 +-- src/node/socket.h | 22 ++++--- 16 files changed, 178 insertions(+), 122 deletions(-) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index ea4855f05..3d2670fa4 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -457,26 +457,62 @@ CsmaCdNetDevice::AddQueue (Ptr q) } void -CsmaCdNetDevice::Receive (Packet& p) +CsmaCdNetDevice::Receive (const Packet& packet) { + EthernetHeader header (false); + EthernetTrailer trailer; + Eui48Address broadcast; + Eui48Address destination; + Packet p = packet; + NS_DEBUG ("CsmaCdNetDevice::Receive UID is (" << p.GetUid() << ")"); // Only receive if send side of net device is enabled if (!IsReceiveEnabled()) - return; - - uint16_t param = 0; - Packet packet = p; - - if (ProcessHeader(packet, param)) { - m_rxTrace (packet); - ForwardUp (packet, param); - } - else - { - m_dropTrace (packet); + goto drop; } + + if (m_encapMode == RAW) + { + ForwardUp (packet, 0, GetBroadcast ()); + goto drop; + } + p.RemoveTrailer(trailer); + trailer.CheckFcs(p); + p.RemoveHeader(header); + + broadcast = Eui48Address::ConvertFrom (GetBroadcast ()); + destination = Eui48Address::ConvertFrom (GetAddress ()); + if ((header.GetDestination() != broadcast) && + (header.GetDestination() != destination)) + { + // not for us. + goto drop; + } + + uint16_t protocol; + switch (m_encapMode) + { + case ETHERNET_V1: + case IP_ARP: + protocol = header.GetLengthType(); + break; + case LLC: { + LlcSnapHeader llc; + p.RemoveHeader (llc); + protocol = llc.GetType (); + } break; + case RAW: + NS_ASSERT (false); + break; + } + + m_rxTrace (p); + ForwardUp (p, protocol, header.GetSource ().ConvertTo ()); + return; + drop: + m_dropTrace (p); } Ptr diff --git a/src/devices/csma-cd/csma-cd-net-device.h b/src/devices/csma-cd/csma-cd-net-device.h index eb116f3e3..6b1341b89 100644 --- a/src/devices/csma-cd/csma-cd-net-device.h +++ b/src/devices/csma-cd/csma-cd-net-device.h @@ -173,7 +173,7 @@ enum CsmaCdEncapsulationMode { * @see CsmaCdChannel * \param p a reference to the received packet */ - void Receive (Packet& p); + void Receive (const Packet& p); bool IsSendEnabled (void); bool IsReceiveEnabled (void); diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 4b4157b26..b450421f5 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -220,12 +220,12 @@ void PointToPointNetDevice::AddQueue (Ptr q) void PointToPointNetDevice::Receive (Packet& p) { NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); - uint16_t param = 0; + uint16_t protocol = 0; Packet packet = p; - ProcessHeader(packet, param); + ProcessHeader(packet, protocol); m_rxTrace (packet); - ForwardUp (packet, param); + ForwardUp (packet, protocol, GetBroadcast ()); } Ptr PointToPointNetDevice::GetQueue(void) const diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index a18b2ab5d..100f1df88 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -84,7 +84,7 @@ ArpL3Protocol::FindCache (Ptr device) } void -ArpL3Protocol::Receive(const Packet& p, uint16_t protocol, Ptr device) +ArpL3Protocol::Receive(Ptr device, const Packet& p, uint16_t protocol, const Address &from) { ArpCache *cache = FindCache (device); ArpHeader arp; diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index d3ae7441d..a2ea8227e 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -53,7 +53,7 @@ public: /** * \brief Recieve a packet */ - void Receive(const Packet& p, uint16_t protocol, Ptr device); + void Receive(Ptr device, const Packet& p, uint16_t protocol, const Address &from); /** * \brief Perform an ARP lookup * \param p diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index eaf2734a3..31c3935f5 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -241,7 +241,7 @@ Ipv4L3Protocol::FindInterfaceForDevice (Ptr device) } void -Ipv4L3Protocol::Receive(const Packet& p, uint16_t protocol, Ptr device) +Ipv4L3Protocol::Receive( Ptr device, const Packet& p, uint16_t protocol, const Address &from) { uint32_t index = 0; for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index 200a001d4..d9abe535a 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -95,7 +95,7 @@ public: * - implement a per-NetDevice ARP cache * - send back arp replies on the right device */ - void Receive(const Packet& p, uint16_t protocol, Ptr device); + void Receive( Ptr device, const Packet& p, uint16_t protocol, const Address &from); /** * \param packet packet to send diff --git a/src/internet-node/ipv4-loopback-interface.cc b/src/internet-node/ipv4-loopback-interface.cc index 320a32ce4..47ddc9ee2 100644 --- a/src/internet-node/ipv4-loopback-interface.cc +++ b/src/internet-node/ipv4-loopback-interface.cc @@ -44,7 +44,7 @@ void Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest) { Ptr ipv4 = m_node->QueryInterface (Ipv4L3Protocol::iid); - ipv4->Receive (packet, Ipv4L3Protocol::PROT_NUMBER, GetDevice ()); + ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, GetDevice ()->GetAddress ()); } }//namespace ns3 diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index bdbc08887..61d32499e 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -136,20 +136,21 @@ UdpSocket::ShutdownRecv (void) return 0; } -void -UdpSocket::DoClose(ns3::Callback > closeCompleted) +int +UdpSocket::DoClose(Callback > closeCompleted) { // XXX: we should set the close state and check it in all API methods. if (!closeCompleted.IsNull ()) { closeCompleted (this); } + return 0; } -void +int UdpSocket::DoConnect(const Address & address, - ns3::Callback > connectionSucceeded, - ns3::Callback > connectionFailed, - ns3::Callback > halfClose) + Callback > connectionSucceeded, + Callback > connectionFailed, + Callback > halfClose) { InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); m_defaultAddress = transport.GetIpv4 (); @@ -159,11 +160,12 @@ UdpSocket::DoConnect(const Address & address, connectionSucceeded (this); } m_connected = true; + return 0; } int -UdpSocket::DoAccept(ns3::Callback, const Address&> connectionRequest, - ns3::Callback, const Address&> newConnectionCreated, - ns3::Callback > closeRequested) +UdpSocket::DoAccept(Callback, const Address&> connectionRequest, + Callback, const Address&> newConnectionCreated, + Callback > closeRequested) { // calling accept on a udp socket is a programming error. m_errno = ERROR_OPNOTSUPP; @@ -172,7 +174,7 @@ UdpSocket::DoAccept(ns3::Callback, const Address&> connectionR int UdpSocket::DoSend (const uint8_t* buffer, uint32_t size, - ns3::Callback, uint32_t> dataSent) + Callback, uint32_t> dataSent) { if (!m_connected) { @@ -192,7 +194,7 @@ UdpSocket::DoSend (const uint8_t* buffer, } int UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, - ns3::Callback, uint32_t> dataSent) + Callback, uint32_t> dataSent) { InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); @@ -201,7 +203,7 @@ UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, } int UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address ipv4, uint16_t port, - ns3::Callback, uint32_t> dataSent) + Callback, uint32_t> dataSent) { if (m_endPoint == 0) { @@ -229,7 +231,7 @@ int UdpSocket::DoSendTo(const Address &address, const uint8_t *buffer, uint32_t size, - ns3::Callback, uint32_t> dataSent) + Callback, uint32_t> dataSent) { if (m_connected) { @@ -251,12 +253,12 @@ UdpSocket::DoSendTo(const Address &address, return DoSendPacketTo (p, ipv4, port, dataSent); } void -UdpSocket::DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Address&> callback) +UdpSocket::DoRecv(Callback, const uint8_t*, uint32_t,const Address&> callback) { m_rxCallback = callback; } void -UdpSocket::DoRecvDummy(ns3::Callback, uint32_t,const Address&> callback) +UdpSocket::DoRecvDummy(Callback, uint32_t,const Address&> callback) { m_dummyRxCallback = callback; } diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket.h index 82d3cd6a3..8778aff84 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket.h @@ -51,23 +51,23 @@ public: virtual int ShutdownRecv (void); private: - virtual void DoClose(ns3::Callback > closeCompleted); - virtual void DoConnect(const Address & address, - ns3::Callback > connectionSucceeded, - ns3::Callback > connectionFailed, - ns3::Callback > halfClose); - virtual int DoAccept(ns3::Callback, const Address&> connectionRequest, - ns3::Callback, const Address&> newConnectionCreated, - ns3::Callback > closeRequested); + virtual int DoClose(Callback > closeCompleted); + virtual int DoConnect(const Address & address, + Callback > connectionSucceeded, + Callback > connectionFailed, + Callback > halfClose); + virtual int DoAccept(Callback, const Address&> connectionRequest, + Callback, const Address&> newConnectionCreated, + Callback > closeRequested); virtual int DoSend (const uint8_t* buffer, uint32_t size, - ns3::Callback, uint32_t> dataSent); + Callback, uint32_t> dataSent); virtual int DoSendTo(const Address &address, const uint8_t *buffer, uint32_t size, - ns3::Callback, uint32_t> dataSent); - virtual void DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Address&>); - virtual void DoRecvDummy(ns3::Callback, uint32_t,const Address&>); + Callback, uint32_t> dataSent); + virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Address&>); + virtual void DoRecvDummy(Callback, uint32_t,const Address&>); private: friend class Udp; @@ -76,9 +76,9 @@ private: void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port); void Destroy (void); int DoSendPacketTo (const Packet &p, const Address &daddr, - ns3::Callback, uint32_t> dataSent); + Callback, uint32_t> dataSent); int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, - ns3::Callback, uint32_t> dataSent); + Callback, uint32_t> dataSent); Ipv4EndPoint *m_endPoint; Ptr m_node; diff --git a/src/node/net-device.cc b/src/node/net-device.cc index a7ef06c7a..4fa2e8d51 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -197,18 +197,19 @@ NetDevice::GetChannel (void) const // Receive packets from below bool -NetDevice::ForwardUp(Packet& p, uint32_t param) +NetDevice::ForwardUp(const Packet& p, uint32_t param, const Address &from) { bool retval = false; - Packet packet = p; - NS_DEBUG ("NetDevice::ForwardUp: UID is " << packet.GetUid() + NS_DEBUG ("NetDevice::ForwardUp: UID is " << p.GetUid() << " device is: " << GetName()); if (!m_receiveCallback.IsNull ()) { - retval = m_receiveCallback (this, packet, param); - } else { + retval = m_receiveCallback (this, p, param, from); + } + else + { NS_DEBUG ("NetDevice::Receive call back is NULL"); } @@ -248,7 +249,7 @@ NetDevice::NeedsArp (void) const } void -NetDevice::SetReceiveCallback (Callback,const Packet &,uint16_t> cb) +NetDevice::SetReceiveCallback (ReceiveCallback cb) { m_receiveCallback = cb; } diff --git a/src/node/net-device.h b/src/node/net-device.h index 88109a894..dd590f39c 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -177,11 +177,24 @@ public: */ bool NeedsArp (void) const; + /** + * \param device a pointer to the net device which is calling this callback + * \param packet the packet received + * \param protocol the 16 bit protocol number associated with this packet. + * This protocol number is expected to be the same protocol number + * given to the Send method by the user on the sender side. + * \param address the address of the sender + * \returns true if the callback could handle the packet successfully, false + * otherwise. + */ + typedef Callback,const Packet &,uint16_t,const Address &> ReceiveCallback; + /** * \param cb callback to invoke whenever a packet has been received and must * be forwarded to the higher layers. + * */ - void SetReceiveCallback (Callback,const Packet &,uint16_t> cb); + void SetReceiveCallback (ReceiveCallback cb); protected: /** @@ -230,6 +243,7 @@ public: * \param p packet sent from below up to Network Device * \param param Extra parameter extracted from header and needed by * some protocols + * \param address the address of the sender of this packet. * \returns true if the packet was forwarded successfully, * false otherwise. * @@ -237,7 +251,7 @@ public: * forwards it to the higher layers by calling this method * which is responsible for passing it up to the Rx callback. */ - bool ForwardUp (Packet& p, uint32_t param); + bool ForwardUp (const Packet& p, uint32_t param, const Address &address); /** @@ -248,8 +262,6 @@ public: */ virtual void DoDispose (void); - Callback,const Packet &,uint16_t> m_receiveCallback; - private: /** * \param p packet to send @@ -297,6 +309,7 @@ public: bool m_isMulticast; bool m_isPointToPoint; Callback m_linkChangeCallback; + ReceiveCallback m_receiveCallback; }; }; // namespace ns3 diff --git a/src/node/node.cc b/src/node/node.cc index 5c3d7c6f3..7aaa0216a 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -22,6 +22,7 @@ #include "node-list.h" #include "net-device.h" #include "application.h" +#include "packet-socket-factory.h" #include "ns3/simulator.h" #include "ns3/empty-trace-resolver.h" @@ -33,16 +34,23 @@ Node::Node() : m_id(0), m_sid(0) { - SetInterfaceId (Node::iid); - m_id = NodeList::Add (this); + Construct (); } Node::Node(uint32_t sid) : m_id(0), m_sid(sid) { + Construct (); +} + +void +Node::Construct (void) +{ SetInterfaceId (Node::iid); m_id = NodeList::Add (this); + Ptr socketFactory = Create (); + AddInterface (socketFactory); } Node::~Node () @@ -69,8 +77,8 @@ Node::GetSystemId (void) const uint32_t Node::AddDevice (Ptr device) { - uint32_t index = m_devices.size (); m_devices.push_back (device); + uint32_t index = m_devices.size (); device->SetIfIndex(index); device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this)); NotifyDeviceAdded (device); @@ -79,7 +87,14 @@ Node::AddDevice (Ptr device) Ptr Node::GetDevice (uint32_t index) const { - return m_devices[index]; + if (index == 0) + { + return 0; + } + else + { + return m_devices[index - 1]; + } } uint32_t Node::GetNDevices (void) const @@ -143,24 +158,11 @@ Node::RegisterProtocolHandler (ProtocolHandler handler, { struct Node::ProtocolHandlerEntry entry; entry.handler = handler; - entry.isSpecificProtocol = true; entry.protocol = protocolType; entry.device = device; m_handlers.push_back (entry); } -void -Node::RegisterProtocolHandler (ProtocolHandler handler, - Ptr device) -{ - struct Node::ProtocolHandlerEntry entry; - entry.handler = handler; - entry.isSpecificProtocol = false; - entry.protocol = 0; - entry.device = device; - m_handlers.push_back (entry); -} - void Node::UnregisterProtocolHandler (ProtocolHandler handler) { @@ -176,7 +178,8 @@ Node::UnregisterProtocolHandler (ProtocolHandler handler) } bool -Node::ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol) +Node::ReceiveFromDevice (Ptr device, const Packet &packet, + uint16_t protocol, const Address &from) { bool found = false; for (ProtocolHandlerList::iterator i = m_handlers.begin (); @@ -185,10 +188,10 @@ Node::ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t p if (i->device == 0 || (i->device != 0 && i->device == device)) { - if (!i->isSpecificProtocol || - (i->isSpecificProtocol && i->protocol == protocol)) + if (i->protocol == 0 || + i->protocol == protocol) { - i->handler (packet, protocol, device); + i->handler (device, packet, protocol, from); found = true; } } diff --git a/src/node/node.h b/src/node/node.h index 2e3953458..eea8089a5 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -33,6 +33,7 @@ class TraceResolver; class NetDevice; class Application; class Packet; +class Address; /** * \brief A network Node. @@ -56,6 +57,17 @@ class Node : public Object public: static const InterfaceId iid; + /** + * Must be invoked by subclasses only. + */ + Node(); + /** + * \param systemId a unique integer used for parallel simulations. + * + * Must be invoked by subclasses only. + */ + Node(uint32_t systemId); + virtual ~Node(); /** @@ -91,11 +103,15 @@ public: * Associate this device to this node. * This method is called automatically from NetDevice::NetDevice * so the user has little reason to call this method himself. + * The index returned is always non-zero. */ uint32_t AddDevice (Ptr device); /** * \param index the index of the requested NetDevice * \returns the requested NetDevice associated to this Node. + * + * The indexes used by the GetDevice method start at one and + * end at GetNDevices () */ Ptr GetDevice (uint32_t index) const; /** @@ -128,11 +144,15 @@ public: /** * A protocol handler */ - typedef Callback > ProtocolHandler; + typedef Callback, const Packet &,uint16_t,const Address &> ProtocolHandler; /** * \param handler the handler to register * \param protocolType the type of protocol this handler is - * interested in. + * interested in. This protocol type is a so-called + * EtherType, as registered here: + * http://standards.ieee.org/regauth/ethertype/eth.txt + * the value zero is interpreted as matching all + * protocols. * \param device the device attached to this handler. If the * value is zero, the handler is attached to all * devices on this node. @@ -140,18 +160,6 @@ public: void RegisterProtocolHandler (ProtocolHandler handler, uint16_t protocolType, Ptr device); - /** - * \param handler the handler to register - * \param device the device attached to this handler. If the - * value is zero, the handler is attached to all - * devices on this node. - * - * Register a handler to receive all packets for all - * protocols. - */ - void RegisterProtocolHandler (ProtocolHandler handler, - Ptr device); - /** * \param handler the handler to unregister * @@ -161,16 +169,6 @@ public: void UnregisterProtocolHandler (ProtocolHandler handler); protected: - /** - * Must be invoked by subclasses only. - */ - Node(); - /** - * \param systemId a unique integer used for parallel simulations. - * - * Must be invoked by subclasses only. - */ - Node(uint32_t systemId); /** * The dispose method. Subclasses must override this method * and must chain up to it by calling Node::DoDispose at the @@ -195,11 +193,12 @@ private: */ virtual void NotifyDeviceAdded (Ptr device); - bool ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol); + bool ReceiveFromDevice (Ptr device, const Packet &packet, + uint16_t protocol, const Address &from); + void Construct (void); struct ProtocolHandlerEntry { ProtocolHandler handler; - bool isSpecificProtocol; uint16_t protocol; Ptr device; }; diff --git a/src/node/socket.cc b/src/node/socket.cc index b8995cfea..e3e573ab6 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -5,19 +5,19 @@ namespace ns3 { Socket::~Socket () {} -void +int Socket::Close(Callback > closeCompleted) { - DoClose (closeCompleted); + return DoClose (closeCompleted); } -void +int Socket::Connect(const Address & address, Callback > connectionSucceeded, Callback > connectionFailed, Callback > halfClose) { - DoConnect (address, connectionSucceeded, connectionFailed, halfClose); + return DoConnect (address, connectionSucceeded, connectionFailed, halfClose); } int Socket::Accept(Callback, const Address&> connectionRequest, diff --git a/src/node/socket.h b/src/node/socket.h index 547ed4320..991fb01b1 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -52,7 +52,9 @@ public: ERROR_AGAIN, ERROR_SHUTDOWN, ERROR_OPNOTSUPP, + ERROR_AFNOSUPPORT, ERROR_INVAL, + ERROR_BADF, SOCKET_ERRNO_LAST }; @@ -92,7 +94,7 @@ public: * After the Close call, the socket is no longer valid, and cannot * safely be used for subsequent operations. */ - void Close(Callback > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket)); + int Close(Callback > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket)); /** * \returns zero on success, -1 on failure. @@ -122,10 +124,10 @@ public: * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the * other side closes the connection ? Or when I call Close ? */ - void Connect(const Address &address, - Callback > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket), - Callback > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket), - Callback > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket)); + int Connect(const Address &address, + Callback > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket), + Callback > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket), + Callback > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket)); /** * \brief Accept connection requests from remote hosts @@ -201,11 +203,11 @@ public: MakeCallback (&Socket::DummyCallbackVoidSocketUi32Address)); private: - virtual void DoClose(Callback > closeCompleted) = 0; - virtual void DoConnect(const Address & address, - Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose) = 0; + virtual int DoClose(Callback > closeCompleted) = 0; + virtual int DoConnect(const Address & address, + Callback > connectionSucceeded, + Callback > connectionFailed, + Callback > halfClose) = 0; virtual int DoAccept(Callback, const Address&> connectionRequest, Callback, const Address&> newConnectionCreated, Callback > closeRequested) = 0; From 26875799868f3f91dd7e99628f71220ed3fd6002 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 09:01:54 +0200 Subject: [PATCH 130/278] add Address::IsInvalid --- src/node/address.cc | 6 ++++++ src/node/address.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/node/address.cc b/src/node/address.cc index 2979239c4..74993a0b4 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -40,6 +40,12 @@ Address::operator = (const Address &address) return *this; } +bool +Address::IsInvalid (void) const +{ + return m_len == 0 && m_type == 0; +} + uint8_t Address::GetLength (void) const { diff --git a/src/node/address.h b/src/node/address.h index 20ea4b46f..7d234fd72 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -86,6 +86,14 @@ public: Address (const Address & address); Address &operator = (const Address &address); + /** + * \returns true if this address is invalid, false otherwise. + * + * An address is invalid if and only if it was created + * through the default constructor and it was never + * re-initialized. + */ + bool IsInvalid (void); /** * \returns the length of the underlying address. */ From b835a6b564ea3db78c5d4bee000759015cccab66 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 09:02:03 +0200 Subject: [PATCH 131/278] a packet socket --- src/node/packet-socket-address.cc | 12 ++ src/node/packet-socket-address.h | 9 + src/node/packet-socket-factory.cc | 40 ++++ src/node/packet-socket-factory.h | 52 +++++ src/node/packet-socket.cc | 332 ++++++++++++++++++++++++++++++ src/node/packet-socket.h | 132 ++++++++++++ src/node/wscript | 7 + 7 files changed, 584 insertions(+) create mode 100644 src/node/packet-socket-factory.cc create mode 100644 src/node/packet-socket-factory.h create mode 100644 src/node/packet-socket.cc create mode 100644 src/node/packet-socket.h diff --git a/src/node/packet-socket-address.cc b/src/node/packet-socket-address.cc index 2d2288fca..ac5bded70 100644 --- a/src/node/packet-socket-address.cc +++ b/src/node/packet-socket-address.cc @@ -35,6 +35,18 @@ PacketSocketAddress::SetDevice (uint32_t index) m_device = index; } void +PacketSocketAddress::SetDevice (Ptr device) +{ + if (device == 0) + { + m_device = 0; + } + else + { + m_device = device->GetIfIndex (); + } +} +void PacketSocketAddress::SetPhysicalAddress (const Address address) { m_address = address; diff --git a/src/node/packet-socket-address.h b/src/node/packet-socket-address.h index 5e8265b4d..1e903d181 100644 --- a/src/node/packet-socket-address.h +++ b/src/node/packet-socket-address.h @@ -20,9 +20,11 @@ #ifndef PACKET_SOCKET_ADDRESS_H #define PACKET_SOCKET_ADDRESS_H +#include "ns3/ptr.h" #include "address.h" #include "eui48-address.h" #include "eui64-address.h" +#include "net-device.h" namespace ns3 { @@ -33,7 +35,14 @@ class PacketSocketAddress public: PacketSocketAddress (); void SetProtocol (uint16_t protocol); + /** + * \param index of NetDevice. + * + * index zero is reserved to identify _all_ + * Netdevices. + */ void SetDevice (uint32_t index); + void SetDevice (Ptr device); void SetPhysicalAddress (const Address address); uint16_t GetProtocol (void) const; diff --git a/src/node/packet-socket-factory.cc b/src/node/packet-socket-factory.cc new file mode 100644 index 000000000..3cd403a1a --- /dev/null +++ b/src/node/packet-socket-factory.cc @@ -0,0 +1,40 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 Emmanuelle Laprise + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Emmanuelle Laprise + */ +#include "packet-socket-factory.h" +#include "node.h" + +namespace ns3 { + +const InterfaceId PacketSocketFactory::iid = MakeInterfaceId ("Packet", + SocketFactory::iid); + +PacketSocketFactory::PacketSocketFactory () +{ + SetInterfaceId (PacketSocketFactory::iid); +} + +Ptr PacketSocketFactory::CreateSocket (void) +{ + Ptr node = QueryInterface (Node::iid); + Ptr socket = Create (node); + return socket; +} +} // namespace ns3 diff --git a/src/node/packet-socket-factory.h b/src/node/packet-socket-factory.h new file mode 100644 index 000000000..0f052ce6e --- /dev/null +++ b/src/node/packet-socket-factory.h @@ -0,0 +1,52 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 Emmanuelle Laprise + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Emmanuelle Laprise + */ +#ifndef PACKET_SOCKET_FACTORY_H +#define PACKET_SOCKET_FACTORY_H + +#include "socket-factory.h" +#include "packet-socket.h" + +namespace ns3 { + +class Socket; + +/** + * This can be used as an interface in a node in order for the node to + * generate PacketSockets that can connect to net devices. + */ +class PacketSocketFactory : public SocketFactory +{ +public: + static const InterfaceId iid; /// Interface identifier + + PacketSocketFactory (); + + /** + * Creates a PacketSocket and returns a pointer to it. + * + * \return a pointer to the created socket + */ + virtual Ptr CreateSocket (void); +}; + +} // namespace ns3 + +#endif /* PACKET_SOCKET_FACTORY_H */ diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc new file mode 100644 index 000000000..9bce9bafa --- /dev/null +++ b/src/node/packet-socket.cc @@ -0,0 +1,332 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 Emmanuelle Laprise, INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Emmanuelle Laprise + * Mathieu Lacage + */ + +#include "packet-socket.h" +#include "packet-socket-address.h" +#include "ns3/debug.h" +#include "ns3/node.h" + +NS_DEBUG_COMPONENT_DEFINE ("PacketSocket"); + +namespace ns3 { + +PacketSocket::PacketSocket (Ptr node) + : m_node (node) +{ + Init(); +} + +void +PacketSocket::Init() +{ + m_state = STATE_OPEN; + m_shutdownSend = false; + m_shutdownRecv = false; + m_errno = ERROR_NOTERROR; +} + +PacketSocket::~PacketSocket () +{} + +void +PacketSocket::DoDispose (void) +{ + m_device = 0; +} + +Ptr +PacketSocket::GetNode (void) const +{ + return m_node; +} + + +int +PacketSocket::Bind (void) +{ + PacketSocketAddress address; + address.SetProtocol (0); + address.SetDevice (0); + return DoBind (address); +} +int +PacketSocket::Bind (const Address &address) +{ + if (!PacketSocketAddress::IsMatchingType (address)) + { + m_errno = ERROR_INVAL; + return -1; + } + PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address); + return DoBind (ad); +} + +int +PacketSocket::DoBind (const PacketSocketAddress &address) +{ + if (m_state == STATE_BOUND || + m_state == STATE_CONNECTED) + { + m_errno = ERROR_INVAL; + return -1; + } + if (m_state == STATE_CLOSED) + { + m_errno = ERROR_BADF; + return -1; + } + Ptr dev = m_node->GetDevice (address.GetDevice ()); + m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this), + address.GetProtocol (), dev); + m_state = STATE_BOUND; + m_protocol = address.GetProtocol (); + m_device = address.GetDevice (); + return 0; +} + +enum Socket::SocketErrno +PacketSocket::GetErrno (void) const +{ + return m_errno; +} +int +PacketSocket::ShutdownSend (void) +{ + if (m_state == STATE_CLOSED) + { + m_errno = ERROR_BADF; + return -1; + } + m_shutdownSend = true; + return 0; +} +int +PacketSocket::ShutdownRecv (void) +{ + if (m_state == STATE_CLOSED) + { + m_errno = ERROR_BADF; + return -1; + } + m_shutdownRecv = false; + return 0; +} +int +PacketSocket::DoClose(ns3::Callback > closeCompleted) +{ + if (m_state == STATE_CLOSED) + { + m_errno = ERROR_BADF; + return -1; + } + if (!closeCompleted.IsNull ()) + { + closeCompleted (this); + } + m_state = STATE_CLOSED; + return 0; +} + +int +PacketSocket::DoConnect(const Address &ad, + ns3::Callback > connectionSucceeded, + ns3::Callback > connectionFailed, + ns3::Callback > halfClose) +{ + PacketSocketAddress address; + if (m_state == STATE_CLOSED) + { + m_errno = ERROR_BADF; + goto error; + } + if (m_state == STATE_OPEN) + { + // connect should happen _after_ bind. + m_errno = ERROR_INVAL; // generic error condition. + goto error; + } + if (m_state == STATE_CONNECTED) + { + m_errno = ERROR_ISCONN; + goto error; + } + if (!PacketSocketAddress::IsMatchingType (ad)) + { + m_errno = ERROR_AFNOSUPPORT; + goto error; + } + m_destAddr = ad; + m_state = STATE_CONNECTED; + if (!connectionSucceeded.IsNull ()) + { + connectionSucceeded (this); + } + return 0; + error: + if (!connectionFailed.IsNull ()) + { + connectionFailed (this); + } + return -1; +} + +int +PacketSocket::DoAccept(ns3::Callback, const Address &> connectionRequest, + ns3::Callback, const Address &> newConnectionCreated, + ns3::Callback > closeRequested) +{ + // calling accept on a packet socket is a programming error. + m_errno = ERROR_OPNOTSUPP; + return -1; +} + +int +PacketSocket::DoSend (const uint8_t* buffer, + uint32_t size, + ns3::Callback, uint32_t> dataSent) +{ + if (m_state == STATE_OPEN || + m_state == STATE_BOUND) + { + m_errno = ERROR_NOTCONN; + return -1; + } + return DoSendTo (m_destAddr, buffer, size, dataSent); +} + +int +PacketSocket::DoSendTo(const Address &address, + const uint8_t *buffer, + uint32_t size, + Callback, uint32_t> dataSent) +{ + PacketSocketAddress ad; + if (m_state == STATE_CLOSED) + { + m_errno = ERROR_BADF; + return -1; + } + if (m_state == STATE_OPEN) + { + // XXX should return another error here. + m_errno = ERROR_INVAL; + return -1; + } + if (m_shutdownSend) + { + m_errno = ERROR_SHUTDOWN; + return -1; + } + if (!PacketSocketAddress::IsMatchingType (address)) + { + m_errno = ERROR_AFNOSUPPORT; + return -1; + } + ad = PacketSocketAddress::ConvertFrom (address); + + Packet p; + if (buffer == 0) + { + p = Packet (size); + } + else + { + p = Packet (buffer, size); + } + + bool error = false; + Address dest = ad.GetPhysicalAddress (); + if (ad.GetDevice () == 0) + { + for (uint32_t i = 1; i <= m_node->GetNDevices (); i++) + { + Ptr device = m_node->GetDevice (i); + if (!device->Send (p, dest, ad.GetProtocol ())) + { + error = true; + } + } + } + else + { + Ptr device = m_node->GetDevice (ad.GetDevice ()); + if (!device->Send (p, dest, ad.GetProtocol ())) + { + error = true; + } + } + if (!error && !dataSent.IsNull ()) + { + dataSent (this, p.GetSize ()); + } + + if (error) + { + m_errno = ERROR_INVAL; + return -1; + } + else + { + return 0; + } +} + +void +PacketSocket::DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Address &> callback) +{ + m_rxCallback = callback; +} + +void +PacketSocket::DoRecvDummy(ns3::Callback, uint32_t, const Address &> callback) +{ + m_dummyRxCallback = callback; +} + +void +PacketSocket::ForwardUp (Ptr device, const Packet &packet, + uint16_t protocol, const Address &from) +{ + if (m_shutdownRecv) + { + return; + } + + Packet p = packet; + + PacketSocketAddress address; + address.SetPhysicalAddress (from); + address.SetDevice (device->GetIfIndex ()); + address.SetProtocol (protocol); + + NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid() + << " PacketSocket " << this); + if (!m_dummyRxCallback.IsNull ()) + { + m_dummyRxCallback (this, p.GetSize (), address.ConvertTo ()); + } + if (!m_rxCallback.IsNull ()) + { + m_rxCallback (this, p.PeekData (), p.GetSize (), address.ConvertTo ()); + } +} + +}//namespace ns3 diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h new file mode 100644 index 000000000..790420970 --- /dev/null +++ b/src/node/packet-socket.h @@ -0,0 +1,132 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 Emmanuelle Laprise, INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Emmanuelle Laprise , + * Mathieu Lacage + */ +#ifndef PACKET_SOCKET_H +#define PACKET_SOCKET_H + +#include +#include "ns3/callback.h" +#include "ns3/ptr.h" +#include "ns3/socket.h" + +namespace ns3 { + +class Node; +class Packet; +class NetDevice; +class PacketSocketAddress; + +/** + * \brief A PacketSocket is a link between an application and a net device. + * + * A PacketSocket can be used to connect an application to a net + * device. The application provides the buffers of data, the socket + * conserts them to a raw packet and the net device then adds the + * protocol specific headers and trailers. This socket type + * is very similar to the linux and BSD "packet" sockets. + * + * Here is a summary of the semantics of this class: + * - Bind: Bind uses only the protocol and device fields of the + * PacketSocketAddress. If none are provided, Bind uses + * zero for both, which means that the socket is bound + * to all protocols on all devices on the node. + * + * - Connect: uses only the protocol, device and "physical address" + * field of the PacketSocketAddress. It is used to set the default + * destination address for outgoing packets. + * + * - Send: send the input packet to the underlying NetDevices + * with the default destination address. The socket must + * be bound and connected. + * + * - SendTo: uses the protocol, device, and "physical address" + * fields of the PacketSocketAddress. The device value is + * used to specialize the packet transmission to a single + * device, the protocol value specifies the protocol of this + * packet only and the "physical address" field is used to override the + * default destination address. The socket must be bound. + * + * - Recv: The address represents the address of the packer originator. + * The fields "physical address", device, and protocol are filled. + * + * - Accept: not allowed + */ +class PacketSocket : public Socket +{ +public: + PacketSocket (Ptr node); + virtual ~PacketSocket (); + + virtual enum SocketErrno GetErrno (void) const; + virtual Ptr GetNode (void) const; + virtual int Bind (void); + virtual int Bind (const Address & address); + virtual int ShutdownSend (void); + virtual int ShutdownRecv (void); + +private: + virtual int DoClose(Callback > closeCompleted); + virtual int DoConnect(const Address & address, + Callback > connectionSucceeded, + Callback > connectionFailed, + Callback > halfClose); + virtual int DoAccept(Callback, const Address&> connectionRequest, + Callback, const Address&> newConnectionCreated, + Callback > closeRequested); + virtual int DoSend (const uint8_t* buffer, + uint32_t size, + Callback, uint32_t> dataSent); + virtual int DoSendTo(const Address &address, + const uint8_t *buffer, + uint32_t size, + Callback, uint32_t> dataSent); + virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Address&> receive); + virtual void DoRecvDummy(Callback, uint32_t,const Address&>); + +private: + void Init (void); + void ForwardUp (Ptr device, const Packet &packet, + uint16_t protocol, const Address &from); + int DoBind (const PacketSocketAddress &address); + virtual void DoDispose (void); + + enum State { + STATE_OPEN, + STATE_BOUND, // open and bound + STATE_CONNECTED, // open, bound and connected + STATE_CLOSED + }; + Ptr m_node; + Callback,uint32_t,const Address &> m_dummyRxCallback; + Callback,uint8_t const*,uint32_t, const Address &> m_rxCallback; + enum SocketErrno m_errno; + bool m_shutdownSend; + bool m_shutdownRecv; + enum State m_state; + uint16_t m_protocol; + uint32_t m_device; + Address m_destAddr; /// Default destination address +}; + +}//namespace ns3 + +#endif /* PACKET_SOCKET_H */ + + diff --git a/src/node/wscript b/src/node/wscript index 9cc3d3daf..17714f897 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -8,7 +8,9 @@ def build(bld): node.source = [ 'address.cc', 'eui48-address.cc', + 'eui64-address.cc', 'inet-socket-address.cc', + 'packet-socket-address.cc', 'node.cc', 'ipv4-address.cc', 'net-device.cc', @@ -23,6 +25,8 @@ def build(bld): 'node-list.cc', 'socket.cc', 'socket-factory.cc', + 'packet-socket-factory.cc', + 'packet-socket.cc', 'udp.cc', 'ipv4.cc', 'application.cc', @@ -32,7 +36,9 @@ def build(bld): headers.source = [ 'address.h', 'eui48-address.h', + 'eui64-address.h', 'inet-socket-address.h', + 'packet-socket-address.h', 'node.h', 'ipv4-address.h', 'net-device.h', @@ -47,6 +53,7 @@ def build(bld): 'node-list.h', 'socket.h', 'socket-factory.h', + 'packet-socket-factory.h', 'udp.h', 'ipv4.h', 'application.h', From e91a1198a05121280bcbd0918080b299e093d970 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 09:14:31 +0200 Subject: [PATCH 132/278] fix build: missing const --- src/node/address.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/address.h b/src/node/address.h index 7d234fd72..25bb282fe 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -93,7 +93,7 @@ public: * through the default constructor and it was never * re-initialized. */ - bool IsInvalid (void); + bool IsInvalid (void) const; /** * \returns the length of the underlying address. */ From 802ac99d0d564e265bd3beedae545faab2f8faf4 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 09:15:48 +0200 Subject: [PATCH 133/278] remove extra includes --- examples/csma-cd-one-subnet.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/csma-cd-one-subnet.cc b/examples/csma-cd-one-subnet.cc index ceaf88810..e19ed7e63 100644 --- a/examples/csma-cd-one-subnet.cc +++ b/examples/csma-cd-one-subnet.cc @@ -58,11 +58,6 @@ #include "ns3/ipv4-route.h" #include "ns3/onoff-application.h" -#include "ns3/ascii-trace.h" - -#include "ns3/trace-context.h" -#include "ns3/trace-root.h" - using namespace ns3; From 2319629592510edb76af972a8bf0060b154c9414 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 09:38:09 +0200 Subject: [PATCH 134/278] fix bug 59: debug output now goes to stderr. --- src/core/assert.h | 4 ++-- src/core/debug.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/assert.h b/src/core/assert.h index 928a3b76a..e97fa8aa6 100644 --- a/src/core/assert.h +++ b/src/core/assert.h @@ -65,7 +65,7 @@ void AssertBreakpoint (void); { \ if (!(condition)) \ { \ - std::cout << "assert failed. file=" << __FILE__ << \ + std::cerr << "assert failed. file=" << __FILE__ << \ ", line=" << __LINE__ << ", cond=\""#condition << \ "\"" << std::endl; \ ns3::AssertBreakpoint (); \ @@ -88,7 +88,7 @@ void AssertBreakpoint (void); { \ if (!(condition)) \ { \ - std::cout << message << std::endl; \ + std::cerr << message << std::endl; \ ns3::AssertBreakpoint (); \ } \ } \ diff --git a/src/core/debug.h b/src/core/debug.h index 0171387f2..3fc6fef4b 100644 --- a/src/core/debug.h +++ b/src/core/debug.h @@ -110,7 +110,7 @@ private: { \ if (g_debug.IsEnabled ()) \ { \ - std::cout << msg << std::endl; \ + std::cerr << msg << std::endl; \ } \ } \ while (false) @@ -125,7 +125,7 @@ private: #define NS_DEBUG_UNCOND(msg) \ do \ { \ - std::cout << msg << std::endl; \ + std::cerr << msg << std::endl; \ } \ while (false) From 492afc0f9d63718159b472ebe76361db32162ed7 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 10:29:03 +0200 Subject: [PATCH 135/278] PacketSocketAddress serialization code was buggy. --- src/node/address.cc | 17 +++++++++++++---- src/node/address.h | 23 +++++++++++++++++++---- src/node/packet-socket-address.cc | 11 +++-------- src/node/packet-socket-address.h | 1 - 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/node/address.cc b/src/node/address.cc index 74993a0b4..33104083d 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -52,29 +52,32 @@ Address::GetLength (void) const NS_ASSERT (m_len <= MAX_SIZE); return m_len; } -void +uint32_t Address::CopyTo (uint8_t buffer[MAX_SIZE]) const { NS_ASSERT (m_len <= MAX_SIZE); memcpy (buffer, m_data, m_len); + return m_len; } -void +uint32_t Address::CopyAllTo (uint8_t *buffer, uint8_t len) const { NS_ASSERT (len >= m_len + 2); buffer[0] = m_type; buffer[1] = m_len; memcpy (buffer + 2, m_data, m_len); + return m_len + 2; } -void +uint32_t Address::CopyFrom (const uint8_t *buffer, uint8_t len) { NS_ASSERT (len <= MAX_SIZE); memcpy (m_data, buffer, len); m_len = len; + return m_len; } -void +uint32_t Address::CopyAllFrom (const uint8_t *buffer, uint8_t len) { NS_ASSERT (len >= 2); @@ -82,6 +85,7 @@ Address::CopyAllFrom (const uint8_t *buffer, uint8_t len) m_len = buffer[1]; NS_ASSERT (len >= m_len + 2); memcpy (m_data, buffer + 2, m_len); + return m_len + 2; } bool Address::CheckCompatible (uint8_t type, uint8_t len) const @@ -89,6 +93,11 @@ Address::CheckCompatible (uint8_t type, uint8_t len) const NS_ASSERT (len <= MAX_SIZE); return m_len == len && (m_type == type || m_type == 0); } +bool +Address::IsMatchingType (uint8_t type) const +{ + return m_type == type; +} uint8_t Address::Register (void) diff --git a/src/node/address.h b/src/node/address.h index 25bb282fe..0d3b0da83 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -100,29 +100,33 @@ public: uint8_t GetLength (void) const; /** * \param buffer buffer to copy the address bytes to. + * \returns the number of bytes copied. */ - void CopyTo (uint8_t buffer[MAX_SIZE]) const; + uint32_t CopyTo (uint8_t buffer[MAX_SIZE]) const; /** * \param buffer buffer to copy the whole address data structure to * \param len the size of the buffer + * \returns the number of bytes copied. */ - void CopyAllTo (uint8_t *buffer, uint8_t len) const; + uint32_t CopyAllTo (uint8_t *buffer, uint8_t len) const; /** * \param buffer pointer to a buffer of bytes which contain * a serialized representation of the address in network * byte order. * \param len length of buffer + * \returns the number of bytes copied. * * Copy the input buffer to the internal buffer of this address * instance. */ - void CopyFrom (const uint8_t *buffer, uint8_t len); + uint32_t CopyFrom (const uint8_t *buffer, uint8_t len); /** * \param buffer pointer to a buffer of bytes which contain * a copy of all the members of this Address class. * \param len the length of the buffer + * \returns the number of bytes copied. */ - void CopyAllFrom (const uint8_t *buffer, uint8_t len); + uint32_t CopyAllFrom (const uint8_t *buffer, uint8_t len); /** * \param type a type id as returned by Address::Register * \param len the length associated to this type id. @@ -131,6 +135,17 @@ public: * is compatible with the requested type, false otherwise. */ bool CheckCompatible (uint8_t type, uint8_t len) const; + /** + * \param type a type id as returned by Address::Register + * \returns true if the type of the address stored internally + * is compatible with the requested type, false otherwise. + * + * This method checks that the types are _exactly_ equal. + * This method is really used only by the PacketSocketAddress + * and there is little point in using it otherwise so, + * you have been warned: DO NOT USE THIS METHOD. + */ + bool IsMatchingType (uint8_t type) const; /** * Allocate a new type id for a new type of address. * \returns a new type id. diff --git a/src/node/packet-socket-address.cc b/src/node/packet-socket-address.cc index ac5bded70..2c5fcb7b8 100644 --- a/src/node/packet-socket-address.cc +++ b/src/node/packet-socket-address.cc @@ -79,8 +79,8 @@ PacketSocketAddress::ConvertTo (void) const buffer[3] = (m_device >> 16) & 0xff; buffer[4] = (m_device >> 8) & 0xff; buffer[5] = (m_device >> 0) & 0xff; - m_address.CopyAllTo (buffer + 6, Address::MAX_SIZE - 6); - return Address (GetType (), buffer, GetSize ()); + uint32_t copied = m_address.CopyAllTo (buffer + 6, Address::MAX_SIZE - 6); + return Address (GetType (), buffer, 6 + copied); } PacketSocketAddress PacketSocketAddress::ConvertFrom (const Address &address) @@ -108,7 +108,7 @@ PacketSocketAddress::ConvertFrom (const Address &address) bool PacketSocketAddress::IsMatchingType (const Address &address) { - return address.CheckCompatible (GetType (), GetSize ()); + return address.IsMatchingType (GetType ()); } uint8_t PacketSocketAddress::GetType (void) @@ -116,10 +116,5 @@ PacketSocketAddress::GetType (void) static uint8_t type = Address::Register (); return type; } -uint8_t -PacketSocketAddress::GetSize (void) -{ - return 2 + sizeof (NetDevice *) + 1 + 1 + 8; -} } // namespace ns3 diff --git a/src/node/packet-socket-address.h b/src/node/packet-socket-address.h index 1e903d181..ca138ad43 100644 --- a/src/node/packet-socket-address.h +++ b/src/node/packet-socket-address.h @@ -68,7 +68,6 @@ class PacketSocketAddress static bool IsMatchingType (const Address &address); private: static uint8_t GetType (void); - static uint8_t GetSize (void); uint16_t m_protocol; uint32_t m_device; Address m_address; From b4b0d52ffb74310b0caec867bd4f655507c24546 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 10:29:22 +0200 Subject: [PATCH 136/278] add an extra constructor --- src/devices/csma-cd/csma-cd-net-device.cc | 9 +++++++++ src/devices/csma-cd/csma-cd-net-device.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index 3d2670fa4..538625ee5 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -35,6 +35,15 @@ NS_DEBUG_COMPONENT_DEFINE ("CsmaCdNetDevice"); namespace ns3 { +CsmaCdNetDevice::CsmaCdNetDevice (Ptr node) + : NetDevice (node, Eui48Address::Allocate ().ConvertTo ()), + m_bps (DataRate (0xffffffff)) +{ + NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); + m_encapMode = IP_ARP; + Init(true, true); +} + CsmaCdNetDevice::CsmaCdNetDevice (Ptr node, Eui48Address addr, CsmaCdEncapsulationMode encapMode) : NetDevice(node, addr.ConvertTo ()), diff --git a/src/devices/csma-cd/csma-cd-net-device.h b/src/devices/csma-cd/csma-cd-net-device.h index 6b1341b89..05a327127 100644 --- a/src/devices/csma-cd/csma-cd-net-device.h +++ b/src/devices/csma-cd/csma-cd-net-device.h @@ -83,6 +83,7 @@ enum CsmaCdEncapsulationMode { LLC, /**< LLC packet encapsulation */ }; + CsmaCdNetDevice (Ptr node); /** * Construct a CsmaCdNetDevice * From a4c3028881afbd37b1a4e1648dba7e744a667024 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 10:29:40 +0200 Subject: [PATCH 137/278] example code. --- examples/csma-cd-packet-socket.cc | 136 ++++++++++++++++++++++++++++++ examples/wscript | 1 + 2 files changed, 137 insertions(+) create mode 100644 examples/csma-cd-packet-socket.cc diff --git a/examples/csma-cd-packet-socket.cc b/examples/csma-cd-packet-socket.cc new file mode 100644 index 000000000..9f3cc1877 --- /dev/null +++ b/examples/csma-cd-packet-socket.cc @@ -0,0 +1,136 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// Port of ns-2/tcl/ex/simple.tcl to ns-3 +// +// Network topology +// +// n0 n1 n2 n3 +// | | | | +// ===================== +// +// - CBR/UDP flows from n0 to n1, and from n3 to n0 +// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. +// (i.e., DataRate of 448,000 bps) +// - DropTail queues +// - Tracing of queues and packet receptions to file "csma-cd-one-subnet.tr" + +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/debug.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/csma-cd-channel.h" +#include "ns3/csma-cd-net-device.h" +#include "ns3/eui48-address.h" +#include "ns3/packet-socket-address.h" +#include "ns3/socket.h" +#include "ns3/onoff-application.h" +#include "ns3/queue.h" + +using namespace ns3; + +static Ptr +CreateCsmaCdDevice (Ptr node, Ptr channel) +{ + Ptr device = Create (node); + device->Attach (channel); + Ptr queue = Queue::CreateDefault (); + device->AddQueue (queue); + return device; +} + + +int main (int argc, char *argv[]) +{ + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // create the shared medium used by all csma/cd devices. + Ptr channel = Create (DataRate(5000000), MilliSeconds(2)); + + // use a helper function to connect our nodes to the shared channel. + Ptr n0If = CreateCsmaCdDevice (n0, channel); + Ptr n1If = CreateCsmaCdDevice (n1, channel); + Ptr n2If = CreateCsmaCdDevice (n2, channel); + Ptr n3If = CreateCsmaCdDevice (n3, channel); + + + // create the address which identifies n1 from n0 + PacketSocketAddress n0ToN1; + n0ToN1.SetDevice (n0If->GetIfIndex ()); // set outgoing interface for outgoing packets + n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets + n0ToN1.SetProtocol (2); // set arbitrary protocol for outgoing packets + + // create the address which identifies n0 from n3 + PacketSocketAddress n3ToN0; + n3ToN0.SetDevice (n3If->GetIfIndex ()); + n3ToN0.SetPhysicalAddress (n0If->GetAddress ()); + n3ToN0.SetProtocol (3); + + // Create the OnOff application to send raw datagrams of size + // 210 bytes at a rate of 448 Kb/s + // from n0 to n1 + Ptr ooff = Create ( + n0, + n0ToN1.ConvertTo (), + "Packet", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.0)); + ooff->Stop (Seconds(10.0)); + + // Create a similar flow from n3 to n0, starting at time 1.1 seconds + ooff = Create ( + n3, + n3ToN0.ConvertTo (), + "Packet", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.1)); + ooff->Stop (Seconds(10.0)); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the csma-cd-packet-socket.tr file + AsciiTrace asciitrace ("csma-cd-packet-socket.tr"); + asciitrace.TraceAllNetDeviceRx (); + asciitrace.TraceAllQueues (); + + Simulator::Run (); + + Simulator::Destroy (); +} diff --git a/examples/wscript b/examples/wscript index e1b960ddc..f455a2c1b 100644 --- a/examples/wscript +++ b/examples/wscript @@ -11,4 +11,5 @@ def build(bld): obj = create_ns_prog('simple-point-to-point', 'simple-point-to-point.cc', deps=['point-to-point', 'internet-node']) obj = create_ns_prog('csma-cd-one-subnet', 'csma-cd-one-subnet.cc', deps=['csma-cd', 'internet-node']) + obj = create_ns_prog('csma-cd-packet-socket', 'csma-cd-packet-socket.cc', deps=['csma-cd', 'internet-node']) From dd3ca3aa63ba90e93d31fb3fa95bbb8e4be75f6e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 12:33:44 +0200 Subject: [PATCH 138/278] replace Node::DoCreateTraceResolver with Node::DoFillTraceResolver --- src/common/array-trace-resolver.h | 12 +++++----- src/internet-node/ascii-trace.cc | 4 ++-- src/internet-node/internet-node.cc | 14 +++++------- src/internet-node/internet-node.h | 2 +- src/internet-node/ipv4-l3-protocol.cc | 4 ++-- src/node/node-list.cc | 12 +++------- src/node/node.cc | 32 ++++++++++++++++++++------- src/node/node.h | 18 ++++++++++----- 8 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/common/array-trace-resolver.h b/src/common/array-trace-resolver.h index 572df6e57..2dc3409d6 100644 --- a/src/common/array-trace-resolver.h +++ b/src/common/array-trace-resolver.h @@ -81,11 +81,11 @@ public: */ ArrayTraceResolver (TraceContext const &context, Callback getSize, - Callback get); + Callback get); private: virtual TraceResolverList DoLookup (std::string id) const; Callback m_getSize; - Callback m_get; + Callback m_get; }; }//namespace ns3 @@ -108,7 +108,7 @@ ArrayTraceResolver::Index::operator uint32_t () template ArrayTraceResolver::ArrayTraceResolver (TraceContext const &context, Callback getSize, - Callback get) + Callback get) : TraceResolver (context), m_getSize (getSize), m_get (get) @@ -122,10 +122,10 @@ ArrayTraceResolver::DoLookup (std::string id) const { for (uint32_t i = 0; i < m_getSize (); i++) { - TraceContext context = GetContext (); + TraceContext context = GetContext (); typename ArrayTraceResolver::Index index = typename ArrayTraceResolver::Index (i); - context.Add (index); - list.push_back (m_get (i)->CreateTraceResolver (context)); + context.Add (index); + list.push_back (m_get (i)->CreateTraceResolver (context)); } } return list; diff --git a/src/internet-node/ascii-trace.cc b/src/internet-node/ascii-trace.cc index 1314f2150..33bcffc25 100644 --- a/src/internet-node/ascii-trace.cc +++ b/src/internet-node/ascii-trace.cc @@ -47,14 +47,14 @@ void AsciiTrace::TraceAllQueues (void) { Packet::EnableMetadata (); - TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*", + TraceRoot::Connect ("/nodes/*/devices/*/queue/*", MakeCallback (&AsciiTrace::LogDevQueue, this)); } void AsciiTrace::TraceAllNetDeviceRx (void) { Packet::EnableMetadata (); - TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx", + TraceRoot::Connect ("/nodes/*/devices/*/rx", MakeCallback (&AsciiTrace::LogDevRx, this)); } diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index fa0bb1471..ffb44b79b 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -76,16 +76,14 @@ InternetNode::Construct (void) } -TraceResolver * -InternetNode::DoCreateTraceResolver (TraceContext const &context) +void +InternetNode::DoFillTraceResolver (CompositeTraceResolver &resolver) { - CompositeTraceResolver *resolver = new CompositeTraceResolver (context); + Node::DoFillTraceResolver (resolver); Ptr ipv4 = QueryInterface (Ipv4L3Protocol::iid); - resolver->Add ("ipv4", - MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)), - InternetNode::IPV4); - - return resolver; + resolver.Add ("ipv4", + MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)), + InternetNode::IPV4); } void diff --git a/src/internet-node/internet-node.h b/src/internet-node/internet-node.h index 1d63edae5..6047a1717 100644 --- a/src/internet-node/internet-node.h +++ b/src/internet-node/internet-node.h @@ -46,7 +46,7 @@ public: protected: virtual void DoDispose(void); private: - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); + virtual void DoFillTraceResolver (CompositeTraceResolver &resolver); bool ReceiveFromDevice (Ptr device, const Packet &p, uint16_t protocolNumber) const; void Construct (void); }; diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index 31c3935f5..a012d814c 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -99,8 +99,8 @@ Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context) TraceResolver * Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const { - ArrayTraceResolver *resolver = - new ArrayTraceResolver + ArrayTraceResolver *resolver = + new ArrayTraceResolver (context, MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this), MakeCallback (&Ipv4L3Protocol::GetInterface, this)); diff --git a/src/node/node-list.cc b/src/node/node-list.cc index 4fed7eb5e..118e19585 100644 --- a/src/node/node-list.cc +++ b/src/node/node-list.cc @@ -53,7 +53,6 @@ public: NodeList::Iterator Begin (void); NodeList::Iterator End (void); TraceResolver *CreateTraceResolver (TraceContext const &context); - Node *PeekNode (uint32_t n); Ptr GetNode (uint32_t n); uint32_t GetNNodes (void); @@ -99,11 +98,6 @@ NodeListPriv::GetNNodes (void) { return m_nodes.size (); } -Node * -NodeListPriv::PeekNode (uint32_t n) -{ - return PeekPointer (m_nodes[n]); -} Ptr NodeListPriv::GetNode (uint32_t n) @@ -115,11 +109,11 @@ NodeListPriv::GetNode (uint32_t n) TraceResolver * NodeListPriv::CreateTraceResolver (TraceContext const &context) { - ArrayTraceResolver *resolver = - new ArrayTraceResolver + ArrayTraceResolver > *resolver = + new ArrayTraceResolver > (context, MakeCallback (&NodeListPriv::GetNNodes, this), - MakeCallback (&NodeListPriv::PeekNode, this)); + MakeCallback (&NodeListPriv::GetNode, this)); return resolver; } diff --git a/src/node/node.cc b/src/node/node.cc index 7aaa0216a..caad3d9e1 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -24,7 +24,7 @@ #include "application.h" #include "packet-socket-factory.h" #include "ns3/simulator.h" -#include "ns3/empty-trace-resolver.h" +#include "ns3/composite-trace-resolver.h" namespace ns3{ @@ -59,7 +59,9 @@ Node::~Node () TraceResolver * Node::CreateTraceResolver (TraceContext const &context) { - return DoCreateTraceResolver (context); + CompositeTraceResolver *resolver = new CompositeTraceResolver (context); + DoFillTraceResolver (*resolver); + return resolver; } uint32_t @@ -120,8 +122,27 @@ Node::GetNApplications (void) const return m_applications.size (); } +TraceResolver * +Node::CreateDevicesTraceResolver (const TraceContext &context) +{ + ArrayTraceResolver > *resolver = + new ArrayTraceResolver > (context, + MakeCallback (&Node::GetNDevices, this), + MakeCallback (&Node::GetDevice, this)); + + return resolver; +} -void Node::DoDispose() +void +Node::DoFillTraceResolver (CompositeTraceResolver &resolver) +{ + resolver.Add ("devices", + MakeCallback (&Node::CreateDevicesTraceResolver, this), + Node::DEVICES); +} + +void +Node::DoDispose() { for (std::vector >::iterator i = m_devices.begin (); i != m_devices.end (); i++) @@ -142,11 +163,6 @@ void Node::DoDispose() Object::DoDispose (); } -TraceResolver * -Node::DoCreateTraceResolver (TraceContext const &context) -{ - return new EmptyTraceResolver (context); -} void Node::NotifyDeviceAdded (Ptr device) {} diff --git a/src/node/node.h b/src/node/node.h index eea8089a5..e7e34d2c2 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -34,6 +34,7 @@ class NetDevice; class Application; class Packet; class Address; +class CompositeTraceResolver; /** * \brief A network Node. @@ -175,14 +176,17 @@ protected: * end of their own DoDispose method. */ virtual void DoDispose (void); -private: /** - * \param context the trace context - * \returns a trace resolver to the user. The user must delete it. + * \param resolver the resolver to store trace sources in. * - * Subclasses must implement this method. + * If a subclass wants to add new traces to a Node, it needs + * to override this method and record the new trace sources + * in the input resolver. Subclasses also _must_ chain up to + * their parent's DoFillTraceResolver method prior + * to recording they own trace sources. */ - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); + virtual void DoFillTraceResolver (CompositeTraceResolver &resolver); +private: /** * \param device the device added to this Node. * @@ -196,7 +200,11 @@ private: bool ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol, const Address &from); void Construct (void); + TraceResolver *CreateDevicesTraceResolver (const TraceContext &context); + enum TraceSource { + DEVICES + }; struct ProtocolHandlerEntry { ProtocolHandler handler; uint16_t protocol; From 707b722c36cf96cec95be75d12051f35cdce8b3a Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 13:53:48 +0200 Subject: [PATCH 139/278] fix tracing --- examples/csma-cd-packet-socket.cc | 4 +-- src/internet-node/ascii-trace.cc | 52 ++++------------------------ src/internet-node/ascii-trace.h | 1 - src/internet-node/ipv4-l3-protocol.h | 2 +- src/node/node-list.h | 2 +- src/node/node.cc | 11 ++---- src/node/node.h | 2 ++ src/node/packet-socket-address.cc | 43 ++++++++++++++--------- src/node/packet-socket-address.h | 15 ++++---- src/node/packet-socket.cc | 37 ++++++++++++-------- src/node/packet-socket.h | 1 + 11 files changed, 70 insertions(+), 100 deletions(-) diff --git a/examples/csma-cd-packet-socket.cc b/examples/csma-cd-packet-socket.cc index 9f3cc1877..f19249789 100644 --- a/examples/csma-cd-packet-socket.cc +++ b/examples/csma-cd-packet-socket.cc @@ -90,13 +90,13 @@ int main (int argc, char *argv[]) // create the address which identifies n1 from n0 PacketSocketAddress n0ToN1; - n0ToN1.SetDevice (n0If->GetIfIndex ()); // set outgoing interface for outgoing packets + n0ToN1.SetSingleDevice (n0If->GetIfIndex ()); // set outgoing interface for outgoing packets n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets n0ToN1.SetProtocol (2); // set arbitrary protocol for outgoing packets // create the address which identifies n0 from n3 PacketSocketAddress n3ToN0; - n3ToN0.SetDevice (n3If->GetIfIndex ()); + n3ToN0.SetSingleDevice (n3If->GetIfIndex ()); n3ToN0.SetPhysicalAddress (n0If->GetAddress ()); n3ToN0.SetProtocol (3); diff --git a/src/internet-node/ascii-trace.cc b/src/internet-node/ascii-trace.cc index 33bcffc25..b4e1430cb 100644 --- a/src/internet-node/ascii-trace.cc +++ b/src/internet-node/ascii-trace.cc @@ -26,12 +26,6 @@ #include "ns3/node.h" #include "ns3/queue.h" #include "ns3/node-list.h" -#include "ns3/llc-snap-header.h" - -#include "ipv4-l3-protocol.h" -#include "arp-header.h" -#include "udp-header.h" -#include "ipv4-header.h" namespace ns3 { @@ -58,40 +52,6 @@ AsciiTrace::TraceAllNetDeviceRx (void) MakeCallback (&AsciiTrace::LogDevRx, this)); } -void -AsciiTrace::PrintType (Packet const &packet) -{ - Packet p = packet; - LlcSnapHeader llc; - p.RemoveHeader (llc); - switch (llc.GetType ()) - { - case 0x0800: { - Ipv4Header ipv4; - p.RemoveHeader (ipv4); - if (ipv4.GetProtocol () == 17) - { - UdpHeader udp; - p.RemoveHeader (udp); - m_os << "udp size=" << p.GetSize (); - } - } break; - case 0x0806: { - ArpHeader arp; - p.RemoveHeader (arp); - m_os << "arp "; - if (arp.IsRequest ()) - { - m_os << "request"; - } - else - { - m_os << "reply "; - } - } break; - } -} - void AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet) { @@ -113,9 +73,9 @@ AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet) NodeList::NodeIndex nodeIndex; context.Get (nodeIndex); m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " "; - Ipv4L3Protocol::InterfaceIndex interfaceIndex; - context.Get (interfaceIndex); - m_os << "interface=" << interfaceIndex << " "; + Node::NetDeviceIndex deviceIndex; + context.Get (deviceIndex); + m_os << "device=" << deviceIndex << " "; m_os << "pkt-uid=" << packet.GetUid () << " "; packet.Print (m_os); m_os << std::endl; @@ -127,9 +87,9 @@ AsciiTrace::LogDevRx (TraceContext const &context, Packet &p) NodeList::NodeIndex nodeIndex; context.Get (nodeIndex); m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " "; - Ipv4L3Protocol::InterfaceIndex interfaceIndex; - context.Get (interfaceIndex); - m_os << "interface=" << interfaceIndex << " "; + Node::NetDeviceIndex deviceIndex; + context.Get (deviceIndex); + m_os << "device=" << deviceIndex << " "; m_os << "pkt-uid=" << p.GetUid () << " "; p.Print (m_os); m_os << std::endl; diff --git a/src/internet-node/ascii-trace.h b/src/internet-node/ascii-trace.h index 5d7554665..56b4195cb 100644 --- a/src/internet-node/ascii-trace.h +++ b/src/internet-node/ascii-trace.h @@ -37,7 +37,6 @@ public: void TraceAllQueues (void); void TraceAllNetDeviceRx (void); private: - void PrintType (Packet const &p); void LogDevQueue (TraceContext const &context, const Packet &p); void LogDevRx (TraceContext const &context, Packet &p); std::ofstream m_os; diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index d9abe535a..6130872cd 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -57,7 +57,7 @@ public: DROP, INTERFACES, }; - typedef ArrayTraceResolver::Index InterfaceIndex; + typedef ArrayTraceResolver::Index InterfaceIndex; Ipv4L3Protocol(Ptr node); virtual ~Ipv4L3Protocol (); diff --git a/src/node/node-list.h b/src/node/node-list.h index 607a47d71..cb4be3cc2 100644 --- a/src/node/node-list.h +++ b/src/node/node-list.h @@ -40,7 +40,7 @@ class TraceContext; class NodeList { public: - typedef ArrayTraceResolver::Index NodeIndex; + typedef ArrayTraceResolver >::Index NodeIndex; typedef std::vector< Ptr >::iterator Iterator; /** diff --git a/src/node/node.cc b/src/node/node.cc index caad3d9e1..05b61c096 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -79,8 +79,8 @@ Node::GetSystemId (void) const uint32_t Node::AddDevice (Ptr device) { - m_devices.push_back (device); uint32_t index = m_devices.size (); + m_devices.push_back (device); device->SetIfIndex(index); device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this)); NotifyDeviceAdded (device); @@ -89,14 +89,7 @@ Node::AddDevice (Ptr device) Ptr Node::GetDevice (uint32_t index) const { - if (index == 0) - { - return 0; - } - else - { - return m_devices[index - 1]; - } + return m_devices[index]; } uint32_t Node::GetNDevices (void) const diff --git a/src/node/node.h b/src/node/node.h index e7e34d2c2..e2e99dee3 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -25,6 +25,7 @@ #include "ns3/object.h" #include "ns3/callback.h" +#include "ns3/array-trace-resolver.h" namespace ns3 { @@ -57,6 +58,7 @@ class Node : public Object { public: static const InterfaceId iid; + typedef ArrayTraceResolver >::Index NetDeviceIndex; /** * Must be invoked by subclasses only. diff --git a/src/node/packet-socket-address.cc b/src/node/packet-socket-address.cc index 2c5fcb7b8..de7ae5980 100644 --- a/src/node/packet-socket-address.cc +++ b/src/node/packet-socket-address.cc @@ -29,22 +29,17 @@ PacketSocketAddress::SetProtocol (uint16_t protocol) { m_protocol = protocol; } -void -PacketSocketAddress::SetDevice (uint32_t index) +void +PacketSocketAddress::SetAllDevices (void) { - m_device = index; + m_isSingleDevice = false; + m_device = 0; } void -PacketSocketAddress::SetDevice (Ptr device) +PacketSocketAddress::SetSingleDevice (uint32_t index) { - if (device == 0) - { - m_device = 0; - } - else - { - m_device = device->GetIfIndex (); - } + m_isSingleDevice = true; + m_device = index; } void PacketSocketAddress::SetPhysicalAddress (const Address address) @@ -57,8 +52,13 @@ PacketSocketAddress::GetProtocol (void) const { return m_protocol; } +bool +PacketSocketAddress::IsSingleDevice (void) const +{ + return m_isSingleDevice; +} uint32_t -PacketSocketAddress::GetDevice (void) const +PacketSocketAddress::GetSingleDevice (void) const { return m_device; } @@ -79,8 +79,9 @@ PacketSocketAddress::ConvertTo (void) const buffer[3] = (m_device >> 16) & 0xff; buffer[4] = (m_device >> 8) & 0xff; buffer[5] = (m_device >> 0) & 0xff; - uint32_t copied = m_address.CopyAllTo (buffer + 6, Address::MAX_SIZE - 6); - return Address (GetType (), buffer, 6 + copied); + buffer[6] = m_isSingleDevice?1:0; + uint32_t copied = m_address.CopyAllTo (buffer + 7, Address::MAX_SIZE - 7); + return Address (GetType (), buffer, 7 + copied); } PacketSocketAddress PacketSocketAddress::ConvertFrom (const Address &address) @@ -97,11 +98,19 @@ PacketSocketAddress::ConvertFrom (const Address &address) device |= buffer[4]; device <<= 8; device |= buffer[5]; + bool isSingleDevice = (buffer[6] == 1)?true:false; Address physical; - physical.CopyAllFrom (buffer + 6, Address::MAX_SIZE - 6); + physical.CopyAllFrom (buffer + 7, Address::MAX_SIZE - 7); PacketSocketAddress ad; ad.SetProtocol (protocol); - ad.SetDevice (device); + if (isSingleDevice) + { + ad.SetSingleDevice (device); + } + else + { + ad.SetAllDevices (); + } ad.SetPhysicalAddress (physical); return ad; } diff --git a/src/node/packet-socket-address.h b/src/node/packet-socket-address.h index ca138ad43..ad313f8c4 100644 --- a/src/node/packet-socket-address.h +++ b/src/node/packet-socket-address.h @@ -35,18 +35,14 @@ class PacketSocketAddress public: PacketSocketAddress (); void SetProtocol (uint16_t protocol); - /** - * \param index of NetDevice. - * - * index zero is reserved to identify _all_ - * Netdevices. - */ - void SetDevice (uint32_t index); - void SetDevice (Ptr device); + + void SetAllDevices (void); + void SetSingleDevice (uint32_t device); void SetPhysicalAddress (const Address address); uint16_t GetProtocol (void) const; - uint32_t GetDevice (void) const; + uint32_t GetSingleDevice (void) const; + bool IsSingleDevice (void) const; Address GetPhysicalAddress (void) const; /** @@ -69,6 +65,7 @@ class PacketSocketAddress private: static uint8_t GetType (void); uint16_t m_protocol; + bool m_isSingleDevice; uint32_t m_device; Address m_address; }; diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index 9bce9bafa..e2c510e27 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -64,7 +64,7 @@ PacketSocket::Bind (void) { PacketSocketAddress address; address.SetProtocol (0); - address.SetDevice (0); + address.SetAllDevices (); return DoBind (address); } int @@ -93,12 +93,21 @@ PacketSocket::DoBind (const PacketSocketAddress &address) m_errno = ERROR_BADF; return -1; } - Ptr dev = m_node->GetDevice (address.GetDevice ()); + Ptr dev ; + if (address.IsSingleDevice ()) + { + dev = 0; + } + else + { + m_node->GetDevice (address.GetSingleDevice ()); + } m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this), address.GetProtocol (), dev); m_state = STATE_BOUND; m_protocol = address.GetProtocol (); - m_device = address.GetDevice (); + m_isSingleDevice = address.IsSingleDevice (); + m_device = address.GetSingleDevice (); return 0; } @@ -254,9 +263,17 @@ PacketSocket::DoSendTo(const Address &address, bool error = false; Address dest = ad.GetPhysicalAddress (); - if (ad.GetDevice () == 0) + if (ad.IsSingleDevice ()) { - for (uint32_t i = 1; i <= m_node->GetNDevices (); i++) + Ptr device = m_node->GetDevice (ad.GetSingleDevice ()); + if (!device->Send (p, dest, ad.GetProtocol ())) + { + error = true; + } + } + else + { + for (uint32_t i = 0; i < m_node->GetNDevices (); i++) { Ptr device = m_node->GetDevice (i); if (!device->Send (p, dest, ad.GetProtocol ())) @@ -265,14 +282,6 @@ PacketSocket::DoSendTo(const Address &address, } } } - else - { - Ptr device = m_node->GetDevice (ad.GetDevice ()); - if (!device->Send (p, dest, ad.GetProtocol ())) - { - error = true; - } - } if (!error && !dataSent.IsNull ()) { dataSent (this, p.GetSize ()); @@ -314,7 +323,7 @@ PacketSocket::ForwardUp (Ptr device, const Packet &packet, PacketSocketAddress address; address.SetPhysicalAddress (from); - address.SetDevice (device->GetIfIndex ()); + address.SetSingleDevice (device->GetIfIndex ()); address.SetProtocol (protocol); NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid() diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index 790420970..f18279949 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -121,6 +121,7 @@ private: bool m_shutdownRecv; enum State m_state; uint16_t m_protocol; + bool m_isSingleDevice; uint32_t m_device; Address m_destAddr; /// Default destination address }; From b632880fdecd41c62100596b58be0545196dde78 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 13:54:09 +0200 Subject: [PATCH 140/278] update address size --- src/node/address.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/address.h b/src/node/address.h index 0d3b0da83..aedc940d4 100644 --- a/src/node/address.h +++ b/src/node/address.h @@ -63,7 +63,7 @@ public: * The maximum size of a byte buffer which * can be stored in an Address instance. */ - MAX_SIZE = 14 + MAX_SIZE = 30 }; /** From 73322272fe452ab1fed411a785641365639c5169 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 17:22:10 +0200 Subject: [PATCH 141/278] fix trace output --- src/node/address.cc | 4 ++-- src/node/eui48-address.cc | 4 ++-- src/node/eui64-address.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/node/address.cc b/src/node/address.cc index 33104083d..0cc37b1a2 100644 --- a/src/node/address.cc +++ b/src/node/address.cc @@ -147,7 +147,7 @@ std::ostream& operator<< (std::ostream& os, const Address & address) return os; } os.setf (std::ios::hex, std::ios::basefield); - std::cout.fill('0'); + os.fill('0'); for (uint8_t i=0; i < (address.m_len-1); i++) { os << std::setw(2) << (uint32_t)address.m_data[i] << ":"; @@ -155,7 +155,7 @@ std::ostream& operator<< (std::ostream& os, const Address & address) // Final byte not suffixed by ":" os << std::setw(2) << (uint32_t)address.m_data[address.m_len-1]; os.setf (std::ios::dec, std::ios::basefield); - std::cout.fill(' '); + os.fill(' '); return os; } diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 096a1cc38..fd78d4e0f 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -148,7 +148,7 @@ std::ostream& operator<< (std::ostream& os, const Eui48Address & address) address.CopyTo (ad); os.setf (std::ios::hex, std::ios::basefield); - std::cout.fill('0'); + os.fill('0'); for (uint8_t i=0; i < 5; i++) { os << std::setw(2) << (uint32_t)ad[i] << ":"; @@ -156,7 +156,7 @@ std::ostream& operator<< (std::ostream& os, const Eui48Address & address) // Final byte not suffixed by ":" os << std::setw(2) << (uint32_t)ad[5]; os.setf (std::ios::dec, std::ios::basefield); - std::cout.fill(' '); + os.fill(' '); return os; } diff --git a/src/node/eui64-address.cc b/src/node/eui64-address.cc index 342fd4d91..af539f950 100644 --- a/src/node/eui64-address.cc +++ b/src/node/eui64-address.cc @@ -150,7 +150,7 @@ std::ostream& operator<< (std::ostream& os, const Eui64Address & address) address.CopyTo (ad); os.setf (std::ios::hex, std::ios::basefield); - std::cout.fill('0'); + os.fill('0'); for (uint8_t i=0; i < 7; i++) { os << std::setw(2) << (uint32_t)ad[i] << ":"; @@ -158,7 +158,7 @@ std::ostream& operator<< (std::ostream& os, const Eui64Address & address) // Final byte not suffixed by ":" os << std::setw(2) << (uint32_t)ad[7]; os.setf (std::ios::dec, std::ios::basefield); - std::cout.fill(' '); + os.fill(' '); return os; } From 210e88b511d97d7d125ed942f0afa75c497a8a52 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 18:48:24 +0200 Subject: [PATCH 142/278] split callback registration from socket operations in socket.h API. --- samples/main-simple.cc | 3 +- src/internet-node/ipv4-loopback-interface.cc | 3 +- src/internet-node/udp-socket.cc | 85 ++------ src/internet-node/udp-socket.h | 27 +-- src/node/packet-socket.cc | 81 ++----- src/node/packet-socket.h | 24 +-- src/node/socket.cc | 177 ++++++++++----- src/node/socket.h | 215 +++++++++---------- 8 files changed, 280 insertions(+), 335 deletions(-) diff --git a/samples/main-simple.cc b/samples/main-simple.cc index e3567e0b1..e62763dd7 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -33,7 +33,8 @@ SocketPrinter (Ptr socket, uint32_t size, const Address &from) static void PrintTraffic (Ptr socket) { - socket->RecvDummy (MakeCallback (&SocketPrinter)); + socket->SetRecvCallback (MakeNullCallback,const uint8_t *,uint32_t,const Address &> (), + MakeCallback (&SocketPrinter)); } void diff --git a/src/internet-node/ipv4-loopback-interface.cc b/src/internet-node/ipv4-loopback-interface.cc index 47ddc9ee2..fb9ac1fc9 100644 --- a/src/internet-node/ipv4-loopback-interface.cc +++ b/src/internet-node/ipv4-loopback-interface.cc @@ -22,6 +22,7 @@ #include "ns3/empty-trace-resolver.h" #include "ns3/net-device.h" #include "ns3/node.h" +#include "ns3/eui48-address.h" #include "ipv4-loopback-interface.h" #include "ipv4-l3-protocol.h" @@ -44,7 +45,7 @@ void Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest) { Ptr ipv4 = m_node->QueryInterface (Ipv4L3Protocol::iid); - ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, GetDevice ()->GetAddress ()); + ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff").ConvertTo ()); } }//namespace ns3 diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 61d32499e..bfcce63bf 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -57,6 +57,12 @@ UdpSocket::~UdpSocket () m_udp = 0; } +enum Socket::SocketErrno +UdpSocket::GetErrno (void) const +{ + return m_errno; +} + Ptr UdpSocket::GetNode (void) const { @@ -118,11 +124,6 @@ UdpSocket::Bind (const Address &address) return FinishBind (); } -enum Socket::SocketErrno -UdpSocket::GetErrno (void) const -{ - return m_errno; -} int UdpSocket::ShutdownSend (void) { @@ -137,44 +138,25 @@ UdpSocket::ShutdownRecv (void) } int -UdpSocket::DoClose(Callback > closeCompleted) +UdpSocket::Close(void) { - // XXX: we should set the close state and check it in all API methods. - if (!closeCompleted.IsNull ()) - { - closeCompleted (this); - } + NotifyCloseCompleted (); return 0; } + int -UdpSocket::DoConnect(const Address & address, - Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose) +UdpSocket::Connect(const Address & address) { InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); m_defaultAddress = transport.GetIpv4 (); m_defaultPort = transport.GetPort (); - if (!connectionSucceeded.IsNull ()) - { - connectionSucceeded (this); - } + NotifyConnectionSucceeded (); m_connected = true; return 0; } -int -UdpSocket::DoAccept(Callback, const Address&> connectionRequest, - Callback, const Address&> newConnectionCreated, - Callback > closeRequested) -{ - // calling accept on a udp socket is a programming error. - m_errno = ERROR_OPNOTSUPP; - return -1; -} int -UdpSocket::DoSend (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent) +UdpSocket::Send (const uint8_t* buffer, + uint32_t size) { if (!m_connected) { @@ -190,20 +172,18 @@ UdpSocket::DoSend (const uint8_t* buffer, { p = Packet (buffer, size); } - return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent); + return DoSendTo (p, m_defaultAddress, m_defaultPort); } int -UdpSocket::DoSendPacketTo (const Packet &p, const Address &address, - Callback, uint32_t> dataSent) +UdpSocket::DoSendTo (const Packet &p, const Address &address) { InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); - return DoSendPacketTo (p, ipv4, port, dataSent); + return DoSendTo (p, ipv4, port); } int -UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address ipv4, uint16_t port, - Callback, uint32_t> dataSent) +UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port) { if (m_endPoint == 0) { @@ -221,17 +201,13 @@ UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address ipv4, uint16_t port, } m_udp->Send (p, m_endPoint->GetLocalAddress (), ipv4, m_endPoint->GetLocalPort (), port); - if (!dataSent.IsNull ()) - { - dataSent (this, p.GetSize ()); - } + NotifyDataSent (p.GetSize ()); return 0; } int -UdpSocket::DoSendTo(const Address &address, +UdpSocket::SendTo(const Address &address, const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent) + uint32_t size) { if (m_connected) { @@ -250,17 +226,7 @@ UdpSocket::DoSendTo(const Address &address, InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); - return DoSendPacketTo (p, ipv4, port, dataSent); -} -void -UdpSocket::DoRecv(Callback, const uint8_t*, uint32_t,const Address&> callback) -{ - m_rxCallback = callback; -} -void -UdpSocket::DoRecvDummy(Callback, uint32_t,const Address&> callback) -{ - m_dummyRxCallback = callback; + return DoSendTo (p, ipv4, port); } void @@ -273,14 +239,7 @@ UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) Address address = InetSocketAddress (ipv4, port).ConvertTo (); Packet p = packet; - if (!m_dummyRxCallback.IsNull ()) - { - m_dummyRxCallback (this, p.GetSize (), address); - } - if (!m_rxCallback.IsNull ()) - { - m_rxCallback (this, p.PeekData (), p.GetSize (), address); - } + NotifyDataReceived (p, address); } }//namespace ns3 diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket.h index 8778aff84..2ef148247 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket.h @@ -47,27 +47,14 @@ public: virtual Ptr GetNode (void) const; virtual int Bind (void); virtual int Bind (const Address &address); + virtual int Close (void); virtual int ShutdownSend (void); virtual int ShutdownRecv (void); + virtual int Connect(const Address &address); + virtual int Send (const uint8_t* buffer, uint32_t size); + virtual int SendTo(const Address &address,const uint8_t *buffer, uint32_t size); private: - virtual int DoClose(Callback > closeCompleted); - virtual int DoConnect(const Address & address, - Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose); - virtual int DoAccept(Callback, const Address&> connectionRequest, - Callback, const Address&> newConnectionCreated, - Callback > closeRequested); - virtual int DoSend (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent); - virtual int DoSendTo(const Address &address, - const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent); - virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Address&>); - virtual void DoRecvDummy(Callback, uint32_t,const Address&>); private: friend class Udp; @@ -75,10 +62,8 @@ private: int FinishBind (void); void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port); void Destroy (void); - int DoSendPacketTo (const Packet &p, const Address &daddr, - Callback, uint32_t> dataSent); - int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport, - Callback, uint32_t> dataSent); + int DoSendTo (const Packet &p, const Address &daddr); + int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport); Ipv4EndPoint *m_endPoint; Ptr m_node; diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index e2c510e27..8fe64714e 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -52,13 +52,18 @@ PacketSocket::DoDispose (void) m_device = 0; } +enum Socket::SocketErrno +PacketSocket::GetErrno (void) const +{ + return m_errno; +} + Ptr PacketSocket::GetNode (void) const { return m_node; } - int PacketSocket::Bind (void) { @@ -111,11 +116,6 @@ PacketSocket::DoBind (const PacketSocketAddress &address) return 0; } -enum Socket::SocketErrno -PacketSocket::GetErrno (void) const -{ - return m_errno; -} int PacketSocket::ShutdownSend (void) { @@ -139,26 +139,20 @@ PacketSocket::ShutdownRecv (void) return 0; } int -PacketSocket::DoClose(ns3::Callback > closeCompleted) +PacketSocket::Close(void) { if (m_state == STATE_CLOSED) { m_errno = ERROR_BADF; return -1; } - if (!closeCompleted.IsNull ()) - { - closeCompleted (this); - } m_state = STATE_CLOSED; + NotifyCloseCompleted (); return 0; } int -PacketSocket::DoConnect(const Address &ad, - ns3::Callback > connectionSucceeded, - ns3::Callback > connectionFailed, - ns3::Callback > halfClose) +PacketSocket::Connect(const Address &ad) { PacketSocketAddress address; if (m_state == STATE_CLOSED) @@ -184,33 +178,16 @@ PacketSocket::DoConnect(const Address &ad, } m_destAddr = ad; m_state = STATE_CONNECTED; - if (!connectionSucceeded.IsNull ()) - { - connectionSucceeded (this); - } + NotifyConnectionSucceeded (); return 0; error: - if (!connectionFailed.IsNull ()) - { - connectionFailed (this); - } + NotifyConnectionFailed (); return -1; } int -PacketSocket::DoAccept(ns3::Callback, const Address &> connectionRequest, - ns3::Callback, const Address &> newConnectionCreated, - ns3::Callback > closeRequested) -{ - // calling accept on a packet socket is a programming error. - m_errno = ERROR_OPNOTSUPP; - return -1; -} - -int -PacketSocket::DoSend (const uint8_t* buffer, - uint32_t size, - ns3::Callback, uint32_t> dataSent) +PacketSocket::Send (const uint8_t* buffer, + uint32_t size) { if (m_state == STATE_OPEN || m_state == STATE_BOUND) @@ -218,14 +195,13 @@ PacketSocket::DoSend (const uint8_t* buffer, m_errno = ERROR_NOTCONN; return -1; } - return DoSendTo (m_destAddr, buffer, size, dataSent); + return SendTo (m_destAddr, buffer, size); } int -PacketSocket::DoSendTo(const Address &address, +PacketSocket::SendTo(const Address &address, const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent) + uint32_t size) { PacketSocketAddress ad; if (m_state == STATE_CLOSED) @@ -282,9 +258,9 @@ PacketSocket::DoSendTo(const Address &address, } } } - if (!error && !dataSent.IsNull ()) + if (!error) { - dataSent (this, p.GetSize ()); + NotifyDataSent (p.GetSize ()); } if (error) @@ -298,18 +274,6 @@ PacketSocket::DoSendTo(const Address &address, } } -void -PacketSocket::DoRecv(ns3::Callback, const uint8_t*, uint32_t,const Address &> callback) -{ - m_rxCallback = callback; -} - -void -PacketSocket::DoRecvDummy(ns3::Callback, uint32_t, const Address &> callback) -{ - m_dummyRxCallback = callback; -} - void PacketSocket::ForwardUp (Ptr device, const Packet &packet, uint16_t protocol, const Address &from) @@ -328,14 +292,7 @@ PacketSocket::ForwardUp (Ptr device, const Packet &packet, NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid() << " PacketSocket " << this); - if (!m_dummyRxCallback.IsNull ()) - { - m_dummyRxCallback (this, p.GetSize (), address.ConvertTo ()); - } - if (!m_rxCallback.IsNull ()) - { - m_rxCallback (this, p.PeekData (), p.GetSize (), address.ConvertTo ()); - } + NotifyDataReceived (p, address.ConvertTo ()); } }//namespace ns3 diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index f18279949..c18d69087 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -78,27 +78,15 @@ public: virtual Ptr GetNode (void) const; virtual int Bind (void); virtual int Bind (const Address & address); + virtual int Close (void); virtual int ShutdownSend (void); virtual int ShutdownRecv (void); + virtual int Connect(const Address &address); + virtual int Send (const uint8_t* buffer, uint32_t size); + virtual int SendTo(const Address &address,const uint8_t *buffer, uint32_t size); + private: - virtual int DoClose(Callback > closeCompleted); - virtual int DoConnect(const Address & address, - Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose); - virtual int DoAccept(Callback, const Address&> connectionRequest, - Callback, const Address&> newConnectionCreated, - Callback > closeRequested); - virtual int DoSend (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent); - virtual int DoSendTo(const Address &address, - const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent); - virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Address&> receive); - virtual void DoRecvDummy(Callback, uint32_t,const Address&>); private: void Init (void); @@ -114,8 +102,6 @@ private: STATE_CLOSED }; Ptr m_node; - Callback,uint32_t,const Address &> m_dummyRxCallback; - Callback,uint8_t const*,uint32_t, const Address &> m_rxCallback; enum SocketErrno m_errno; bool m_shutdownSend; bool m_shutdownRecv; diff --git a/src/node/socket.cc b/src/node/socket.cc index e3e573ab6..45e12b271 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -1,79 +1,150 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation + * 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: George F. Riley + * Mathieu Lacage + */ #include "socket.h" +#include "ns3/packet.h" namespace ns3 { Socket::~Socket () {} -int -Socket::Close(Callback > closeCompleted) +void +Socket::SetCloseCallback (Callback > closeCompleted) { - return DoClose (closeCompleted); -} - -int -Socket::Connect(const Address & address, - Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose) -{ - return DoConnect (address, connectionSucceeded, connectionFailed, halfClose); -} -int -Socket::Accept(Callback, const Address&> connectionRequest, - Callback, const Address&> newConnectionCreated, - Callback > closeRequested) -{ - return DoAccept (connectionRequest, newConnectionCreated, closeRequested); -} -int -Socket::Send (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent) -{ - return DoSend (buffer, size, dataSent); -} -int -Socket::SendTo(const Address &address, - const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent) -{ - return DoSendTo (address, buffer, size, dataSent); + m_closeCompleted = closeCompleted; } void -Socket::Recv(Callback, const uint8_t*, uint32_t,const Address&> callback) +Socket::SetConnectCallback (Callback > connectionSucceeded, + Callback > connectionFailed, + Callback > halfClose) { - DoRecv (callback); + m_connectionSucceeded = connectionSucceeded; + m_connectionFailed = connectionFailed; + m_halfClose = halfClose; } void -Socket::RecvDummy(Callback, uint32_t,const Address&> callback) +Socket::SetAcceptCallback (Callback, const Address &> connectionRequest, + Callback, const Address&> newConnectionCreated, + Callback > closeRequested) { - DoRecvDummy (callback); + m_connectionRequest = connectionRequest; + m_newConnectionCreated = newConnectionCreated; + m_closeRequested = closeRequested; +} +void +Socket::SetSendCallback (Callback, uint32_t> dataSent) +{ + m_dataSent = dataSent; +} +void +Socket::SetRecvCallback (Callback, const uint8_t*, uint32_t,const Address&> receivedData, + Callback, uint32_t,const Address&> receivedDummyData) +{ + m_receivedData = receivedData; + m_receivedDummyData = receivedDummyData; } - +void +Socket::NotifyCloseCompleted (void) +{ + if (!m_closeCompleted.IsNull ()) + { + m_closeCompleted (this); + } +} +void +Socket::NotifyConnectionSucceeded (void) +{ + if (!m_connectionSucceeded.IsNull ()) + { + m_connectionSucceeded (this); + } +} +void +Socket::NotifyConnectionFailed (void) +{ + if (!m_connectionFailed.IsNull ()) + { + m_connectionFailed (this); + } +} +void +Socket::NotifyHalfClose (void) +{ + if (!m_halfClose.IsNull ()) + { + m_halfClose (this); + } +} bool -Socket::RefuseAllConnections (Ptr socket, const Address& address) +Socket::NotifyConnectionRequest (const Address &from) { - return false; + if (!m_connectionRequest.IsNull ()) + { + return m_connectionRequest (this, from); + } + else + { + // refuse all incomming connections by default. + return false; + } } void -Socket::DummyCallbackVoidSocket (Ptr socket) -{} -void -Socket::DummyCallbackVoidSocketUi32 (Ptr socket, uint32_t) -{} +Socket::NotifyNewConnectionCreated (Ptr socket, const Address &from) +{ + if (!m_newConnectionCreated.IsNull ()) + { + m_newConnectionCreated (socket, from); + } +} void -Socket::DummyCallbackVoidSocketUi32Address (Ptr socket, uint32_t, const Address &) -{} +Socket::NotifyCloseRequested (void) +{ + if (!m_closeRequested.IsNull ()) + { + m_closeRequested (this); + } +} void -Socket::DummyCallbackVoidSocketBufferUi32Address (Ptr socket, const uint8_t *, uint32_t, - const Address &) -{} +Socket::NotifyDataSent (uint32_t size) +{ + if (!m_dataSent.IsNull ()) + { + m_dataSent (this, size); + } +} void -Socket::DummyCallbackVoidSocketAddress (Ptr socket, const Address &) -{} +Socket::NotifyDataReceived (const Packet &p, const Address &from) +{ + if (!m_receivedData.IsNull ()) + { + m_receivedData (this, p.PeekData (), p.GetSize (), from); + } + if (!m_receivedDummyData.IsNull ()) + { + m_receivedDummyData (this, p.GetSize (), from); + } +} + }//namespace ns3 diff --git a/src/node/socket.h b/src/node/socket.h index 991fb01b1..eb5339a6e 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -1,22 +1,24 @@ -/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation + * 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: George F. Riley + * Mathieu Lacage + */ #ifndef __SOCKET_H__ #define __SOCKET_H__ @@ -30,6 +32,7 @@ namespace ns3 { class Node; +class Packet; /** * \brief Define a Socket API based on the BSD Socket API. @@ -70,6 +73,60 @@ public: */ virtual Ptr GetNode (void) const = 0; + /** + * \param closeCompleted Callback invoked when the close operation is + * completed. + */ + void SetCloseCallback (Callback > closeCompleted); + + /** + * \param connectionSucceeded this callback is invoked when the connection request + * initiated by the user is successfully completed. The callback is passed + * back a pointer to the same socket object. + * \param connectionFailed this callback is invoked when the connection request + * initiated by the user is unsuccessfully completed. The callback is passed + * back a pointer to the same socket object. + * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the + * other side closes the connection ? Or when I call Close ? + */ + void SetConnectCallback (Callback > connectionSucceeded, + Callback > connectionFailed, + Callback > halfClose); + /** + * \brief Accept connection requests from remote hosts + * \param connectionRequest Callback for connection request from peer. + * This user callback is passed a pointer to this socket, the + * ip address and the port number of the connection originator. + * This callback must return true to accept the incoming connection, + * false otherwise. If the connection is accepted, the + * "newConnectionCreated" callback will be invoked later to give access + * to the user to the socket created to match this new connection. If the + * user does not explicitely specify this callback, all incoming + * connections will be refused. + * \param newConnectionCreated Callback for new connection: when a new + * is accepted, it is created and the corresponding socket is passed + * back to the user through this callback. This user callback is passed + * a pointer to the new socket, and the ip address and port number + * of the connection originator. + * \param closeRequested Callback for connection close request from peer. + * XXX: when is this callback invoked ? + */ + void SetAcceptCallback (Callback, const Address &> connectionRequest, + Callback, const Address&> newConnectionCreated, + Callback > closeRequested); + void SetSendCallback (Callback, uint32_t> dataSent); + /** + * \brief Receive data + * \param receivedData Invoked whenever new data is received. + * + * If you wish to transport only dummy packets, this method is not a very + * efficient way to receive these dummy packets: it will trigger a memory + * allocation to hold the dummy memory into a buffer which can be passed + * to the user. Instead, consider using the RecvDummy method. + */ + void SetRecvCallback (Callback, const uint8_t*, uint32_t,const Address&> receivedData, + Callback, uint32_t,const Address&> receivedDummyData); + /** * \param address the address to try to allocate * \returns 0 on success, -1 on failure. @@ -85,16 +142,13 @@ public: */ virtual int Bind () = 0; - /** * \brief Close a socket. - * \param closeCompleted Callback invoked when the close operation is - * completed. * * After the Close call, the socket is no longer valid, and cannot * safely be used for subsequent operations. */ - int Close(Callback > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket)); + virtual int Close(void) = 0; /** * \returns zero on success, -1 on failure. @@ -115,45 +169,9 @@ public: /** * \brief Initiate a connection to a remote host * \param address Address of remote. - * \param connectionSucceeded this callback is invoked when the connection request - * initiated by the user is successfully completed. The callback is passed - * back a pointer to the same socket object. - * \param connectionFailed this callback is invoked when the connection request - * initiated by the user is unsuccessfully completed. The callback is passed - * back a pointer to the same socket object. - * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the - * other side closes the connection ? Or when I call Close ? */ - int Connect(const Address &address, - Callback > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket), - Callback > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket), - Callback > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket)); + virtual int Connect(const Address &address) = 0; - /** - * \brief Accept connection requests from remote hosts - * \param connectionRequest Callback for connection request from peer. - * This user callback is passed a pointer to this socket, the - * ip address and the port number of the connection originator. - * This callback must return true to accept the incoming connection, - * false otherwise. If the connection is accepted, the - * "newConnectionCreated" callback will be invoked later to give access - * to the user to the socket created to match this new connection. If the - * user does not explicitely specify this callback, all incoming - * connections will be refused. - * \param newConnectionCreated Callback for new connection: when a new - * is accepted, it is created and the corresponding socket is passed - * back to the user through this callback. This user callback is passed - * a pointer to the new socket, and the ip address and port number - * of the connection originator. - * \param closeRequested Callback for connection close request from peer. - * XXX: when is this callback invoked ? - */ - int Accept(Callback, const Address &> connectionRequest = - MakeCallback(&Socket::RefuseAllConnections), - Callback, const Address&> newConnectionCreated = - MakeCallback (&Socket::DummyCallbackVoidSocketAddress), - Callback > closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket)); - /** * \brief Send data (or dummy data) to the remote host * \param buffer Data to send (nil if dummy data). @@ -162,9 +180,7 @@ public: * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - int Send (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32)); + virtual int Send (const uint8_t* buffer, uint32_t size) = 0; /** * \brief Send data to a specified peer. @@ -175,60 +191,29 @@ public: * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - int SendTo(const Address &address, - const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32)); - - /** - * \brief Receive data - * \param receivedData Invoked whenever new data is received. - * - * If you wish to transport only dummy packets, this method is not a very - * efficient way to receive these dummy packets: it will trigger a memory - * allocation to hold the dummy memory into a buffer which can be passed - * to the user. Instead, consider using the RecvDummy method. - */ - void Recv(Callback, const uint8_t*, uint32_t,const Address&> receivedData = - MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Address)); - - /** - * \brief Receive data - * \param receivedData Invoked whenever new data is received. - * - * This method is included because it is vastly more efficient than the - * Recv method when you use dummy payload. - */ - void RecvDummy(Callback, uint32_t,const Address&> receivedData = - MakeCallback (&Socket::DummyCallbackVoidSocketUi32Address)); + virtual int SendTo(const Address &address,const uint8_t *buffer, uint32_t size) = 0; -private: - virtual int DoClose(Callback > closeCompleted) = 0; - virtual int DoConnect(const Address & address, - Callback > connectionSucceeded, - Callback > connectionFailed, - Callback > halfClose) = 0; - virtual int DoAccept(Callback, const Address&> connectionRequest, - Callback, const Address&> newConnectionCreated, - Callback > closeRequested) = 0; - virtual int DoSend (const uint8_t* buffer, - uint32_t size, - Callback, uint32_t> dataSent) = 0; - virtual int DoSendTo(const Address &address, - const uint8_t *buffer, - uint32_t size, - Callback, uint32_t> dataSent) = 0; - virtual void DoRecv(Callback, const uint8_t*, uint32_t,const Address&> receive) = 0; - virtual void DoRecvDummy(Callback, uint32_t,const Address&>) = 0; +protected: + void NotifyCloseCompleted (void); + void NotifyConnectionSucceeded (void); + void NotifyConnectionFailed (void); + void NotifyHalfClose (void); + bool NotifyConnectionRequest (const Address &from); + void NotifyNewConnectionCreated (Ptr socket, const Address &from); + void NotifyCloseRequested (void); + void NotifyDataSent (uint32_t size); + void NotifyDataReceived (const Packet &p, const Address &from); - - static bool RefuseAllConnections (Ptr socket, const Address& address); - static void DummyCallbackVoidSocket (Ptr socket); - static void DummyCallbackVoidSocketUi32 (Ptr socket, uint32_t); - static void DummyCallbackVoidSocketUi32Address (Ptr socket, uint32_t, const Address &); - static void DummyCallbackVoidSocketBufferUi32Address (Ptr socket, const uint8_t *, uint32_t, - const Address &); - static void DummyCallbackVoidSocketAddress (Ptr socket, const Address &); + Callback > m_closeCompleted; + Callback > m_connectionSucceeded; + Callback > m_connectionFailed; + Callback > m_halfClose; + Callback > m_closeRequested; + Callback, const Address &> m_connectionRequest; + Callback, const Address&> m_newConnectionCreated; + Callback, uint32_t> m_dataSent; + Callback, const uint8_t*, uint32_t,const Address&> m_receivedData; + Callback, uint32_t,const Address&> m_receivedDummyData; }; } //namespace ns3 From 48d1219f5c444f24bab3709b2a2993788973c8c3 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 19:09:11 +0200 Subject: [PATCH 143/278] remove uint8_t * buffers from socket receive API --- samples/main-simple.cc | 8 ++++---- src/node/socket.cc | 10 ++-------- src/node/socket.h | 10 ++-------- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/samples/main-simple.cc b/samples/main-simple.cc index e62763dd7..11cd27d16 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -6,6 +6,7 @@ #include "ns3/socket.h" #include "ns3/inet-socket-address.h" #include "ns3/nstime.h" +#include "ns3/packet.h" using namespace ns3; @@ -25,16 +26,15 @@ GenerateTraffic (Ptr socket, uint32_t size) } static void -SocketPrinter (Ptr socket, uint32_t size, const Address &from) +SocketPrinter (Ptr socket, const Packet &packet, const Address &from) { - std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl; + std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet.GetSize () << std::endl; } static void PrintTraffic (Ptr socket) { - socket->SetRecvCallback (MakeNullCallback,const uint8_t *,uint32_t,const Address &> (), - MakeCallback (&SocketPrinter)); + socket->SetRecvCallback (MakeCallback (&SocketPrinter)); } void diff --git a/src/node/socket.cc b/src/node/socket.cc index 45e12b271..58f83947f 100644 --- a/src/node/socket.cc +++ b/src/node/socket.cc @@ -56,11 +56,9 @@ Socket::SetSendCallback (Callback, uint32_t> dataSent) m_dataSent = dataSent; } void -Socket::SetRecvCallback (Callback, const uint8_t*, uint32_t,const Address&> receivedData, - Callback, uint32_t,const Address&> receivedDummyData) +Socket::SetRecvCallback (Callback, const Packet &,const Address&> receivedData) { m_receivedData = receivedData; - m_receivedDummyData = receivedDummyData; } void @@ -137,11 +135,7 @@ Socket::NotifyDataReceived (const Packet &p, const Address &from) { if (!m_receivedData.IsNull ()) { - m_receivedData (this, p.PeekData (), p.GetSize (), from); - } - if (!m_receivedDummyData.IsNull ()) - { - m_receivedDummyData (this, p.GetSize (), from); + m_receivedData (this, p, from); } } diff --git a/src/node/socket.h b/src/node/socket.h index eb5339a6e..14e105da8 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -119,13 +119,8 @@ public: * \brief Receive data * \param receivedData Invoked whenever new data is received. * - * If you wish to transport only dummy packets, this method is not a very - * efficient way to receive these dummy packets: it will trigger a memory - * allocation to hold the dummy memory into a buffer which can be passed - * to the user. Instead, consider using the RecvDummy method. */ - void SetRecvCallback (Callback, const uint8_t*, uint32_t,const Address&> receivedData, - Callback, uint32_t,const Address&> receivedDummyData); + void SetRecvCallback (Callback, const Packet &,const Address&> receivedData); /** * \param address the address to try to allocate @@ -212,8 +207,7 @@ protected: Callback, const Address &> m_connectionRequest; Callback, const Address&> m_newConnectionCreated; Callback, uint32_t> m_dataSent; - Callback, const uint8_t*, uint32_t,const Address&> m_receivedData; - Callback, uint32_t,const Address&> m_receivedDummyData; + Callback, const Packet &,const Address&> m_receivedData; }; } //namespace ns3 From 1b62aa5a79d58cc2d1e528de20de7fdf77765d2e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 19:19:28 +0200 Subject: [PATCH 144/278] consitify the API a bit --- src/devices/csma-cd/csma-cd-net-device.cc | 3 ++- src/devices/csma-cd/csma-cd-net-device.h | 2 +- src/devices/point-to-point/point-to-point-net-device.cc | 3 ++- src/devices/point-to-point/point-to-point-net-device.h | 2 +- src/node/net-device.cc | 2 +- src/node/net-device.h | 4 ++-- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index 538625ee5..f522a7e16 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -250,8 +250,9 @@ CsmaCdNetDevice::DoNeedsArp (void) const } bool -CsmaCdNetDevice::SendTo (Packet& p, const Address& dest, uint16_t protocolNumber) +CsmaCdNetDevice::SendTo (const Packet& packet, const Address& dest, uint16_t protocolNumber) { + Packet p = packet; NS_DEBUG ("CsmaCdNetDevice::SendTo (" << &p << ")"); NS_DEBUG ("CsmaCdNetDevice::SendTo (): UID is " << p.GetUid () << ")"); diff --git a/src/devices/csma-cd/csma-cd-net-device.h b/src/devices/csma-cd/csma-cd-net-device.h index 05a327127..7bc5b79a5 100644 --- a/src/devices/csma-cd/csma-cd-net-device.h +++ b/src/devices/csma-cd/csma-cd-net-device.h @@ -249,7 +249,7 @@ private: * \param protocolNumber -- this parameter is not used here * \return true if success, false on failure */ - virtual bool SendTo (Packet& p, const Address& dest, uint16_t protocolNumber); + virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber); /** * Start Sending a Packet Down the Wire. diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index b450421f5..121f9e87e 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -102,9 +102,10 @@ void PointToPointNetDevice::SetInterframeGap(const Time& t) m_tInterframeGap = t; } -bool PointToPointNetDevice::SendTo (Packet& p, const Address& dest, +bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest, uint16_t protocolNumber) { + Packet p = packet; NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index 77a55a8dc..06b472650 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -212,7 +212,7 @@ private: * @param protocolNumber Protocol Number used to find protocol touse * @returns true if success, false on failure */ - virtual bool SendTo (Packet& p, const Address& dest, + virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber); /** * Start Sending a Packet Down the Wire. diff --git a/src/node/net-device.cc b/src/node/net-device.cc index 4fa2e8d51..1ffe6d4b1 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -171,7 +171,7 @@ NetDevice::DisablePointToPoint (void) // Receive packet from above bool -NetDevice::Send(Packet& p, const Address& dest, uint16_t protocolNumber) +NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber) { if (m_isUp) { diff --git a/src/node/net-device.h b/src/node/net-device.h index dd590f39c..315f16033 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -158,7 +158,7 @@ public: * * \return whether the Send operation succeeded */ - bool Send(Packet& p, const Address& dest, uint16_t protocolNumber); + bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber); /** * \returns the node base class which contains this network * interface. @@ -274,7 +274,7 @@ public: * method. When the link is Up, this method is invoked to ask * subclasses to forward packets. Subclasses MUST override this method. */ - virtual bool SendTo (Packet& p, const Address &dest, uint16_t protocolNumber) = 0; + virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0; /** * \returns true if this NetDevice needs the higher-layers * to perform ARP over it, false otherwise. From b954d65b8fda467d57f31b35a74e59e97532c00e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 19:19:42 +0200 Subject: [PATCH 145/278] remove uint8_t * from the send path of the socket API --- samples/main-simple.cc | 2 +- src/applications/onoff-application.cc | 3 ++- src/internet-node/udp-socket.cc | 25 ++----------------------- src/internet-node/udp-socket.h | 4 ++-- src/node/packet-socket.cc | 19 +++---------------- src/node/packet-socket.h | 4 ++-- src/node/socket.h | 10 ++++------ 7 files changed, 16 insertions(+), 51 deletions(-) diff --git a/samples/main-simple.cc b/samples/main-simple.cc index 11cd27d16..c9ae24ce3 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -14,7 +14,7 @@ static void GenerateTraffic (Ptr socket, uint32_t size) { std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl; - socket->Send (0, size); + socket->Send (Packet (size)); if (size > 0) { Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); diff --git a/src/applications/onoff-application.cc b/src/applications/onoff-application.cc index 5fa2c8266..32bcd7564 100644 --- a/src/applications/onoff-application.cc +++ b/src/applications/onoff-application.cc @@ -31,6 +31,7 @@ #include "ns3/simulator.h" #include "ns3/socket-factory.h" #include "ns3/default-value.h" +#include "ns3/packet.h" #include "onoff-application.h" using namespace std; @@ -205,7 +206,7 @@ void OnOffApplication::ScheduleStopEvent() void OnOffApplication::SendPacket() { NS_ASSERT (m_sendEvent.IsExpired ()); - m_socket->Send(0, m_pktSize); + m_socket->Send(Packet (m_pktSize)); m_totBytes += m_pktSize; m_lastStartTime = Simulator::Now(); m_residualBits = 0; diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index bfcce63bf..7c9d6b015 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -155,23 +155,13 @@ UdpSocket::Connect(const Address & address) return 0; } int -UdpSocket::Send (const uint8_t* buffer, - uint32_t size) +UdpSocket::Send (const Packet &p) { if (!m_connected) { m_errno = ERROR_NOTCONN; return -1; } - Packet p; - if (buffer == 0) - { - p = Packet (size); - } - else - { - p = Packet (buffer, size); - } return DoSendTo (p, m_defaultAddress, m_defaultPort); } int @@ -205,24 +195,13 @@ UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port) return 0; } int -UdpSocket::SendTo(const Address &address, - const uint8_t *buffer, - uint32_t size) +UdpSocket::SendTo(const Address &address, const Packet &p) { if (m_connected) { m_errno = ERROR_ISCONN; return -1; } - Packet p; - if (buffer == 0) - { - p = Packet (size); - } - else - { - p = Packet (buffer, size); - } InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); uint16_t port = transport.GetPort (); diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket.h index 2ef148247..b3674f7ef 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket.h @@ -51,8 +51,8 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (const uint8_t* buffer, uint32_t size); - virtual int SendTo(const Address &address,const uint8_t *buffer, uint32_t size); + virtual int Send (const Packet &p); + virtual int SendTo(const Address &address,const Packet &p); private: diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index 8fe64714e..6035f74f6 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -186,8 +186,7 @@ PacketSocket::Connect(const Address &ad) } int -PacketSocket::Send (const uint8_t* buffer, - uint32_t size) +PacketSocket::Send (const Packet &p) { if (m_state == STATE_OPEN || m_state == STATE_BOUND) @@ -195,13 +194,11 @@ PacketSocket::Send (const uint8_t* buffer, m_errno = ERROR_NOTCONN; return -1; } - return SendTo (m_destAddr, buffer, size); + return SendTo (m_destAddr, p); } int -PacketSocket::SendTo(const Address &address, - const uint8_t *buffer, - uint32_t size) +PacketSocket::SendTo(const Address &address, const Packet &p) { PacketSocketAddress ad; if (m_state == STATE_CLOSED) @@ -226,16 +223,6 @@ PacketSocket::SendTo(const Address &address, return -1; } ad = PacketSocketAddress::ConvertFrom (address); - - Packet p; - if (buffer == 0) - { - p = Packet (size); - } - else - { - p = Packet (buffer, size); - } bool error = false; Address dest = ad.GetPhysicalAddress (); diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index c18d69087..8dc1b9e62 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -82,8 +82,8 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (const uint8_t* buffer, uint32_t size); - virtual int SendTo(const Address &address,const uint8_t *buffer, uint32_t size); + virtual int Send (const Packet &p); + virtual int SendTo(const Address &address,const Packet &p); private: diff --git a/src/node/socket.h b/src/node/socket.h index 14e105da8..e3365fcd8 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -169,24 +169,22 @@ public: /** * \brief Send data (or dummy data) to the remote host - * \param buffer Data to send (nil if dummy data). - * \param size Number of bytes to send. + * \param p packet to send * \param dataSent Data sent callback. * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int Send (const uint8_t* buffer, uint32_t size) = 0; + virtual int Send (const Packet &p) = 0; /** * \brief Send data to a specified peer. * \param address IP Address of remote host - * \param buffer Data to send (nil if dummy data). - * \param size Number of bytes to send. + * \param p packet to send * \param dataSent Data sent callback. * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int SendTo(const Address &address,const uint8_t *buffer, uint32_t size) = 0; + virtual int SendTo(const Address &address,const Packet &p) = 0; protected: void NotifyCloseCompleted (void); From 63cc2150a0fb5f9d6fa2ef53cd3be69f3c03aa05 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 1 Aug 2007 18:34:23 +0100 Subject: [PATCH 146/278] WAF: when changing environment (e.g. LD_LIBRARY_PATH for --run and --shell), make the new paths take precedence over the old ones. --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 35c17074a..aec595298 100644 --- a/wscript +++ b/wscript @@ -215,7 +215,7 @@ def _run_argv(argv): os_env = dict(os.environ) if pathvar is not None: if pathvar in os_env: - os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH'])) + os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']) + [os_env[pathvar]]) else: os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH'])) From 2eef3ac5fbc1b40b301abf10917bd3a0644d7711 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 1 Aug 2007 20:17:28 +0200 Subject: [PATCH 147/278] small bug in InetSocketAddress deserialization --- src/node/inet-socket-address.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/inet-socket-address.cc b/src/node/inet-socket-address.cc index 232e9215f..b51ca0398 100644 --- a/src/node/inet-socket-address.cc +++ b/src/node/inet-socket-address.cc @@ -67,7 +67,7 @@ InetSocketAddress::ConvertFrom (const Address &address) uint8_t buf[6]; address.CopyTo (buf); Ipv4Address ipv4 = Ipv4Address::Deserialize (buf); - uint16_t port = buf[0] | (buf[1] << 8); + uint16_t port = buf[4] | (buf[5] << 8); return InetSocketAddress (ipv4, port); } uint8_t From 7c001bf4687290655d2b5eb159b9981717017ddf Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 1 Aug 2007 21:35:34 +0100 Subject: [PATCH 148/278] Detect when running waf --shell with stale environment variables and give an error when it happens. --- wscript | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/wscript b/wscript index aec595298..e91740cbe 100644 --- a/wscript +++ b/wscript @@ -142,7 +142,9 @@ def build(bld): if Params.g_options.shell: run_shell() - return + raise SystemExit(0) + + check_shell() # process subfolders from here bld.add_subdirs('src') @@ -192,34 +194,32 @@ def _find_program(program_name, env): raise ValueError("program '%s' not found; available programs are: %r" % (program_name, found_programs)) -def _run_argv(argv): +def _run_argv(argv, os_env=None): env = Params.g_build.env_of_name('default') if sys.platform == 'linux2': pathvar = 'LD_LIBRARY_PATH' - pathsep = ':' elif sys.platform == 'darwin': pathvar = 'DYLD_LIBRARY_PATH' - pathsep = ':' elif sys.platform == 'win32': pathvar = 'PATH' - pathsep = ';' elif sys.platform == 'cygwin': pathvar = 'PATH' - pathsep = ':' else: Params.warning(("Don't know how to configure " "dynamic library path for the platform '%s'") % (sys.platform,)) pathvar = None - pathsep = None - os_env = dict(os.environ) + proc_env = dict(os.environ) + if os_env is not None: + proc_env.update(os_env) + if pathvar is not None: - if pathvar in os_env: - os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']) + [os_env[pathvar]]) + if pathvar in proc_env: + proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]]) else: - os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH'])) + proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH'])) - retval = subprocess.Popen(argv, env=os_env).wait() + retval = subprocess.Popen(argv, env=proc_env).wait() if retval: Params.fatal("Command %s exited with code %i" % (argv, retval)) @@ -273,13 +273,33 @@ def run_program(program_string, command_template=None): return retval +def check_shell(): + if 'NS3_MODULE_PATH' not in os.environ: + return + env = Params.g_build.env_of_name('default') + correct_modpath = os.pathsep.join(env['NS3_MODULE_PATH']) + found_modpath = os.environ['NS3_MODULE_PATH'] + if found_modpath != correct_modpath: + msg = ("Detected shell (waf --shell) with incorrect configuration\n" + "=========================================================\n" + "Possible reasons for this problem:\n" + " 1. You switched to another ns-3 tree from inside this shell\n" + " 2. You switched ns-3 debug level (waf configure --debug)\n" + " 3. You modified the list of built ns-3 modules\n" + "You should correct this situation before running any program. Possible solutions:\n" + " 1. Exit this shell, and start a new one\n" + " 2. Run a new nested shell") + Params.fatal(msg) + def run_shell(): if sys.platform == 'win32': shell = os.environ.get("COMSPEC", "cmd.exe") else: shell = os.environ.get("SHELL", "/bin/sh") - _run_argv([shell]) + + env = Params.g_build.env_of_name('default') + _run_argv([shell], {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])}) def doxygen(): From 078d8b607c3524292c26cadf7150beee8e2cc8f5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 2 Aug 2007 08:55:56 +0200 Subject: [PATCH 149/278] do not access the iterator after erasing it --- src/simulator/scheduler-map.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index f413ed830..e73abf4cf 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -118,9 +118,10 @@ SchedulerMap::PeekNext (void) const EventId SchedulerMap::RemoveNext (void) { - EventMapCI i = m_list.begin (); - m_list.erase (m_list.begin ()); - return EventId (Ptr (i->second, false), i->first.m_ts, i->first.m_uid); + EventMapI i = m_list.begin (); + std::pair next = *i; + m_list.erase (i); + return EventId (Ptr (next.second, false), next.first.m_ts, next.first.m_uid); } bool From 67e42e860023e5dfbd0e0c6a4bba6a77bd998f48 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 2 Aug 2007 13:59:08 +0100 Subject: [PATCH 150/278] Bug #7: Better breakpoints. --- src/core/assert.h | 32 ++--------- src/core/{assert.cc => breakpoint.cc} | 23 ++++++-- src/core/breakpoint.h | 76 +++++++++++++++++++++++++++ src/core/fatal-error.h | 6 +-- src/core/uid-manager.cc | 1 + src/core/wscript | 9 +++- 6 files changed, 112 insertions(+), 35 deletions(-) rename src/core/{assert.cc => breakpoint.cc} (77%) create mode 100644 src/core/breakpoint.h diff --git a/src/core/assert.h b/src/core/assert.h index e97fa8aa6..eb0b6e028 100644 --- a/src/core/assert.h +++ b/src/core/assert.h @@ -21,36 +21,12 @@ #ifndef ASSERT_H #define ASSERT_H -/** - * \defgroup assert Assert - * \brief assert functions and macros - * - * The assert macros are used to verify - * at runtime that a certain condition is true. If it is - * not true, the program halts. These checks are built - * into the program only in debugging builds. They are - * removed in optimized builds. - */ - -namespace ns3 { - -/** - * \ingroup debugging - * - * When an NS_ASSERT cannot verify its condition, - * this function is called. This is where you should - * be able to put a breakpoint with a debugger if - * you want to catch assertions before the program - * halts. - */ -void AssertBreakpoint (void); - -}//namespace ns3 - #ifdef NS3_ASSERT_ENABLE #include +#include "breakpoint.h" + /** * \ingroup assert * \param condition condition to verifiy. @@ -68,7 +44,7 @@ void AssertBreakpoint (void); std::cerr << "assert failed. file=" << __FILE__ << \ ", line=" << __LINE__ << ", cond=\""#condition << \ "\"" << std::endl; \ - ns3::AssertBreakpoint (); \ + NS_BREAKPOINT (); \ } \ } \ while (false) @@ -89,7 +65,7 @@ void AssertBreakpoint (void); if (!(condition)) \ { \ std::cerr << message << std::endl; \ - ns3::AssertBreakpoint (); \ + NS_BREAKPOINT (); \ } \ } \ while (false) diff --git a/src/core/assert.cc b/src/core/breakpoint.cc similarity index 77% rename from src/core/assert.cc rename to src/core/breakpoint.cc index c780a37ea..c748792bc 100644 --- a/src/core/assert.cc +++ b/src/core/breakpoint.cc @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* - * Copyright (c) 2006 INRIA + * Copyright (c) 2006,2007 INRIA, INESC Porto * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -17,14 +17,29 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Mathieu Lacage + * Author: Gustavo Carneiro */ -#include "assert.h" +#include "breakpoint.h" +#include "ns3/core-config.h" +#ifdef HAVE_SIGNAL_H +# include +#endif namespace ns3 { +#ifdef HAVE_SIGNAL_H + void -AssertBreakpoint (void) +Breakpoint (void) +{ + raise (SIGTRAP); +} + +#else + +void +Breakpoint (void) { int *a = 0; /** @@ -38,4 +53,6 @@ AssertBreakpoint (void) } } +#endif // HAVE_SIGNAL_H + }//namespace ns3 diff --git a/src/core/breakpoint.h b/src/core/breakpoint.h new file mode 100644 index 000000000..c2f541ad8 --- /dev/null +++ b/src/core/breakpoint.h @@ -0,0 +1,76 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006,2007 INESC Porto, INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Gustavo Carneiro + * Author: Mathieu Lacage + */ +#ifndef BREAKPOINT_H +#define BREAKPOINT_H + +namespace ns3 { + +/* Hacker macro to place breakpoints for selected machines. + * Actual use is strongly discouraged of course ;) + * Copied from GLib 2.12.9. + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/** + * \ingroup debugging + * + * Inserts a breakpoint instruction (or equivalent system call) into + * the code for selected machines. When an NS_ASSERT cannot verify its condition, + * this macro is used. Falls back to calling + * AssertBreakpoint() for architectures where breakpoint assembly + * instructions are not supported. + */ +#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2 +# define NS_BREAKPOINT() \ + do{ __asm__ __volatile__ ("int $03"); }while(false) +#elif defined (_MSC_VER) && defined (_M_IX86) +# define NS_BREAKPOINT() \ + do{ __asm int 3h }while(false) +#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2 +# define NS_BREAKPOINT() \ + do{ __asm__ __volatile__ ("bpt"); }while(false) +#else /* !__i386__ && !__alpha__ */ +# define NS_BREAKPOINT() ns3::BreakpointFallback () +#endif + +/** + * \brief fallback breakpoint function + * + * This function is used by the NS_BREAKPOINT() macro as a fallback + * for when breakpoint assembly instructions are not available. It + * attempts to halt program execution either by a raising SIGTRAP, on + * unix systems, or by dereferencing a null pointer. + * + * Normally you should not call this function directly. + */ +void BreakpointFallback (void); + + +}//namespace ns3 + + +#endif /* BREAKPOINT_H */ diff --git a/src/core/fatal-error.h b/src/core/fatal-error.h index bcb22269b..9acab8091 100644 --- a/src/core/fatal-error.h +++ b/src/core/fatal-error.h @@ -21,7 +21,7 @@ #ifndef FATAL_ERROR_H #define FATAL_ERROR_H -#include "assert.h" +#include "breakpoint.h" #include /** @@ -32,7 +32,7 @@ * * When this macro is hit at runtime, the user-specified * error message is output and the program is halted by calling - * the ns3::AssertBreakpoint function. This macro is enabled + * the NS_DEBUG_BREAKPOINT macro. This macro is enabled * unconditionally in all builds, including debug and optimized * builds. */ @@ -40,7 +40,7 @@ do \ { \ std::cout << msg << std::endl; \ - ns3::AssertBreakpoint (); \ + NS_BREAKPOINT (); \ } \ while (false) diff --git a/src/core/uid-manager.cc b/src/core/uid-manager.cc index f9af50622..f6aa3f6de 100644 --- a/src/core/uid-manager.cc +++ b/src/core/uid-manager.cc @@ -20,6 +20,7 @@ */ #include "uid-manager.h" #include "ns3/fatal-error.h" +#include "ns3/assert.h" namespace ns3 { diff --git a/src/core/wscript b/src/core/wscript index 219f5541f..139f1c56b 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -15,6 +15,12 @@ def configure(conf): e.define = 'HAVE_GETENV' e.run() + e = conf.create_header_configurator() + e.mandatory = False + e.name = 'signal.h' + e.define = 'HAVE_SIGNAL_H' + e.run() + conf.write_config_header('ns3/core-config.h') @@ -26,7 +32,7 @@ def build(bld): core.source = [ 'callback-test.cc', 'debug.cc', - 'assert.cc', + 'breakpoint.cc', 'ptr.cc', 'object.cc', 'test.cc', @@ -58,6 +64,7 @@ def build(bld): 'object.h', 'debug.h', 'assert.h', + 'breakpoint.h', 'fatal-error.h', 'test.h', 'random-variable.h', From d272bd4e059f3f4c1b321175ee61a176f55f968a Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 2 Aug 2007 14:47:51 +0100 Subject: [PATCH 151/278] Replace the stdout "warning" with a NS_FATAL_ERROR --- src/core/debug.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/debug.cc b/src/core/debug.cc index abd91b504..181bb9622 100644 --- a/src/core/debug.cc +++ b/src/core/debug.cc @@ -24,6 +24,7 @@ #include "debug.h" #include "assert.h" #include "ns3/core-config.h" +#include "fatal-error.h" #ifdef HAVE_STDLIB_H #include @@ -88,7 +89,7 @@ DebugComponentEnableEnvVar (void) } if (!found) { - std::cout << "No debug component named=\"" << tmp << "\"" << std::endl; + NS_FATAL_ERROR ("No debug component named=\"" << tmp << "\""); } if (next == std::string::npos) { From bd1932f12cf27e539be51e472f9a9b9d69c37784 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 2 Aug 2007 14:48:36 +0100 Subject: [PATCH 152/278] In some places, print debug messages / errors to stderr, not stdout. --- src/core/fatal-error.h | 2 +- src/core/random-variable.cc | 6 +++--- src/core/rng-stream.cc | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/fatal-error.h b/src/core/fatal-error.h index 9acab8091..2c83de580 100644 --- a/src/core/fatal-error.h +++ b/src/core/fatal-error.h @@ -39,7 +39,7 @@ #define NS_FATAL_ERROR(msg) \ do \ { \ - std::cout << msg << std::endl; \ + std::cerr << msg << std::endl; \ NS_BREAKPOINT (); \ } \ while (false) diff --git a/src/core/random-variable.cc b/src/core/random-variable.cc index f93404fda..fa44440d0 100644 --- a/src/core/random-variable.cc +++ b/src/core/random-variable.cc @@ -108,8 +108,8 @@ void RandomVariable::UseGlobalSeed(uint32_t s0, uint32_t s1, uint32_t s2, { if (RandomVariable::globalSeedSet) { - cout << "Random number generator already initialized!" << endl; - cout << "Call to RandomVariable::UseGlobalSeed() ignored" << endl; + cerr << "Random number generator already initialized!" << endl; + cerr << "Call to RandomVariable::UseGlobalSeed() ignored" << endl; return; } RandomVariable::globalSeed[0] = s0; @@ -537,7 +537,7 @@ void EmpiricalVariable::Validate() ValueCDF& current = emp[i]; if (current.value < prior.value || current.cdf < prior.cdf) { // Error - cout << "Empirical Dist error," + cerr << "Empirical Dist error," << " current value " << current.value << " prior value " << prior.value << " current cdf " << current.cdf diff --git a/src/core/rng-stream.cc b/src/core/rng-stream.cc index cca0e9c4d..e24ab052c 100644 --- a/src/core/rng-stream.cc +++ b/src/core/rng-stream.cc @@ -269,11 +269,11 @@ bool RngStream::CheckSeed (const uint32_t seed[6]) } for (i = 3; i < 6; ++i) { if (seed[i] >= m2) { - cout << "Seed[" << i << "] = " << seed[i] << endl; - cerr << "*****************************************\n\n" - << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set." - << "\n\n*****************************************\n\n"; - return (false); + cerr << "Seed[" << i << "] = " << seed[i] << endl; + cerr << "*****************************************\n\n" + << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set." + << "\n\n*****************************************\n\n"; + return (false); } } if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) { From a905bf35a7acfeda73515e0bdd9872eca1cba1a5 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Thu, 2 Aug 2007 14:56:04 +0100 Subject: [PATCH 153/278] Send PacketMetadataTest unit test output to Failure (), not std::cout. --- src/common/packet-metadata.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 1308b7d12..c62b7d8f5 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -1377,13 +1377,13 @@ PacketMetadataTest::Check (const char *file, int line, std::list expected) { if (m_headerError) { - std::cout << "PacketMetadata header error. file=" << file + Failure () << "PacketMetadata header error. file=" << file << ", line=" << line << std::endl; return false; } if (m_trailerError) { - std::cout << "PacketMetadata trailer error. file=" << file + Failure () << "PacketMetadata trailer error. file=" << file << ", line=" << line << std::endl; return false; } @@ -1403,20 +1403,20 @@ PacketMetadataTest::Check (const char *file, int line, std::list expected) } return true; error: - std::cout << "PacketMetadata error. file="<< file + Failure () << "PacketMetadata error. file="<< file << ", line=" << line << ", got:\""; for (std::list::iterator i = m_prints.begin (); i != m_prints.end (); i++) { - std::cout << *i << ", "; + Failure () << *i << ", "; } - std::cout << "\", expected: \""; + Failure () << "\", expected: \""; for (std::list::iterator j = expected.begin (); j != expected.end (); j++) { - std::cout << *j << ", "; + Failure () << *j << ", "; } - std::cout << "\"" << std::endl; + Failure () << "\"" << std::endl; return false; } @@ -1436,7 +1436,7 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t va_end (ap); m_printer.PrintForward (); - p.Print (std::cerr, m_printer); + p.Print (Failure (), m_printer); bool ok = Check (file, line, expected); CleanupPrints (); if (!ok) @@ -1445,7 +1445,7 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t } m_printer.PrintBackward (); - p.Print (std::cerr, m_printer); + p.Print (Failure (), m_printer); expected.reverse (); ok = Check (file, line, expected); CleanupPrints (); From 9c2de843b5cb4d549c19d3f84008f22eca3a981c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 09:09:19 +0200 Subject: [PATCH 154/278] move constants to private section --- src/node/ethernet-header.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/node/ethernet-header.h b/src/node/ethernet-header.h index f16db2976..daa63d20d 100644 --- a/src/node/ethernet-header.h +++ b/src/node/ethernet-header.h @@ -47,10 +47,6 @@ namespace ns3 { */ class EthernetHeader : public Header { public: - static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field - static const int LENGTH_SIZE = 2; /// size of the length_type header field - static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields - /** * \brief Construct a null ethernet header * \param hasPreamble if true, insert and remove an ethernet preamble from the @@ -105,6 +101,10 @@ public: uint32_t GetHeaderSize() const; private: + static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field + static const int LENGTH_SIZE = 2; /// size of the length_type header field + static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields + virtual std::string DoGetName (void) const; virtual void PrintTo (std::ostream &os) const; virtual uint32_t GetSerializedSize (void) const; From 62310f6b21fcd6d112c2fa5856c2f85c4e3345b0 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 09:15:11 +0200 Subject: [PATCH 155/278] fix coding style --- src/node/ethernet-header.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index 73172d3e5..19c90e0e7 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -123,7 +123,9 @@ EthernetHeader::GetSerializedSize (void) const if (m_enPreambleSfd) { return PREAMBLE_SIZE + LENGTH_SIZE + 2*MAC_ADDR_SIZE; - } else { + } + else + { return LENGTH_SIZE + 2*MAC_ADDR_SIZE; } } From 740ad8c1b273fd2559a77de71ea396a0f5e8b00c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 09:15:25 +0200 Subject: [PATCH 156/278] remove redundant printing output --- src/node/ethernet-header.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index 19c90e0e7..cc0649eab 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -108,7 +108,6 @@ void EthernetHeader::PrintTo (std::ostream &os) const { // ethernet, right ? - os << "(ethernet)"; if (m_enPreambleSfd) { os << " preamble/sfd=" << m_preambleSfd << ","; From e672f9711f56591bbb1af833a2d8c99b539b577f Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 09:23:41 +0200 Subject: [PATCH 157/278] add GetUid methods to all headers and trailers --- src/internet-node/arp-header.cc | 6 ++++++ src/internet-node/arp-header.h | 7 +++++-- src/internet-node/ipv4-header.cc | 6 ++++++ src/internet-node/ipv4-header.h | 4 +++- src/internet-node/udp-header.cc | 6 ++++++ src/internet-node/udp-header.h | 5 ++++- src/node/ethernet-header.cc | 6 ++++++ src/node/ethernet-header.h | 5 ++++- src/node/ethernet-trailer.cc | 6 ++++++ src/node/ethernet-trailer.h | 5 ++++- src/node/llc-snap-header.cc | 6 ++++++ src/node/llc-snap-header.h | 7 +++++-- 12 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index 7191b0299..3ac09fe0d 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -25,6 +25,12 @@ namespace ns3 { +const char * +ArpHeader::GetUid (void) +{ + return "ArpHeader.ns3"; +} + ArpHeader::~ArpHeader () {} diff --git a/src/internet-node/arp-header.h b/src/internet-node/arp-header.h index 9f85579f5..9c0386b73 100644 --- a/src/internet-node/arp-header.h +++ b/src/internet-node/arp-header.h @@ -30,8 +30,11 @@ namespace ns3 { /** * \brief The packet header for an ARP packet */ -class ArpHeader : public Header { - public: +class ArpHeader : public Header +{ +public: + static const char *GetUid (void); + virtual ~ArpHeader (); void SetRequest (MacAddress sourceHardwareAddress, diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index 44bc46fd2..60ed939c2 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -30,6 +30,12 @@ namespace ns3 { bool Ipv4Header::m_calcChecksum = false; +const char * +Ipv4Header::GetUid (void) +{ + return "Ipv4Header.ns3"; +} + Ipv4Header::Ipv4Header () : m_payloadSize (0), m_identification (0), diff --git a/src/internet-node/ipv4-header.h b/src/internet-node/ipv4-header.h index b45ed9f02..3d9a9b449 100644 --- a/src/internet-node/ipv4-header.h +++ b/src/internet-node/ipv4-header.h @@ -29,8 +29,10 @@ namespace ns3 { /** * \brief Packet header for IPv4 */ -class Ipv4Header : public Header { +class Ipv4Header : public Header +{ public: + static const char *GetUid (void); /** * \brief Construct a null IPv4 header */ diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index a7a95ca49..cc0591a2f 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -26,6 +26,12 @@ namespace ns3 { bool UdpHeader::m_calcChecksum = false; +const char * +UdpHeader::GetUid (void) +{ + return "UdpHeader.ns3"; +} + /* The magic values below are used only for debugging. * They can be used to easily detect memory corruption * problems so you can see the patterns in memory. diff --git a/src/internet-node/udp-header.h b/src/internet-node/udp-header.h index 332614ba0..bc2d0d0e2 100644 --- a/src/internet-node/udp-header.h +++ b/src/internet-node/udp-header.h @@ -30,8 +30,11 @@ namespace ns3 { /** * \brief Packet header for UDP packets */ -class UdpHeader : public Header { +class UdpHeader : public Header +{ public: + static const char *GetUid (void); + /** * \brief Constructor * diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index cc0649eab..bb7df999b 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -29,6 +29,12 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetHeader"); namespace ns3 { +const char * +EthernetHeader::GetUid (void) +{ + return "EthernetHeader.ns3"; +} + EthernetHeader::EthernetHeader (bool hasPreamble) : m_enPreambleSfd (hasPreamble), m_lengthType (0) diff --git a/src/node/ethernet-header.h b/src/node/ethernet-header.h index daa63d20d..c403b5ddc 100644 --- a/src/node/ethernet-header.h +++ b/src/node/ethernet-header.h @@ -45,8 +45,11 @@ namespace ns3 { * the packet. Eventually the class will be improved to also support * VLAN tags in packet headers. */ -class EthernetHeader : public Header { +class EthernetHeader : public Header +{ public: + static const char *GetUid (void); + /** * \brief Construct a null ethernet header * \param hasPreamble if true, insert and remove an ethernet preamble from the diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index 6aa622b66..4eceea452 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -30,6 +30,12 @@ namespace ns3 { bool EthernetTrailer::m_calcFcs = false; +const char * +EthernetTrailer::GetUid (void) +{ + return "EthernetTrailer.ns3"; +} + EthernetTrailer::EthernetTrailer () { Init(); diff --git a/src/node/ethernet-trailer.h b/src/node/ethernet-trailer.h index 7ec3e162d..4d75c911b 100644 --- a/src/node/ethernet-trailer.h +++ b/src/node/ethernet-trailer.h @@ -33,8 +33,11 @@ namespace ns3 { * ethernet packet. The actual FCS functionality is not yet coded and * so this acts more as a placeholder. */ -class EthernetTrailer : public Trailer { +class EthernetTrailer : public Trailer +{ public: + static const char *GetUid (void); + /** * \brief Construct a null ethernet trailer */ diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index ee37ffecf..1054dddaf 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -25,6 +25,12 @@ namespace ns3 { +const char * +LlcSnapHeader::GetUid (void) +{ + return "LlcSnapHeader.ns3"; +} + LlcSnapHeader::LlcSnapHeader () {} diff --git a/src/node/llc-snap-header.h b/src/node/llc-snap-header.h index ad98cda7c..84404fa94 100644 --- a/src/node/llc-snap-header.h +++ b/src/node/llc-snap-header.h @@ -27,8 +27,11 @@ namespace ns3 { -class LlcSnapHeader : public Header { - public: +class LlcSnapHeader : public Header +{ +public: + static const char *GetUid (void); + LlcSnapHeader (); virtual ~LlcSnapHeader (); From 7298cd1110ee9f217043e8ae62504e0e7fc7cccc Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 10:39:55 +0200 Subject: [PATCH 158/278] make sure we return the right integer uid if the header of trailer was already registered. --- samples/main-packet.cc | 12 +++++++++++- src/common/packet-metadata.cc | 23 ++++++++++++++++++++++- src/common/packet-metadata.h | 8 ++++---- src/common/packet-printer.cc | 18 +++++++++--------- src/common/packet-printer.h | 13 ++++++++++++- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/samples/main-packet.cc b/samples/main-packet.cc index 777f95815..8eda7a475 100644 --- a/samples/main-packet.cc +++ b/samples/main-packet.cc @@ -7,8 +7,11 @@ using namespace ns3; /* A sample Header implementation */ -class MyHeader : public Header { +class MyHeader : public Header +{ public: + static const char *GetUid (void); + MyHeader (); virtual ~MyHeader (); @@ -24,6 +27,13 @@ private: uint16_t m_data; }; +const char * +MyHeader::GetUid (void) +{ + // make sure the string is really unique. + return "MyHeader.test.nsnam.org"; +} + MyHeader::MyHeader () {} MyHeader::~MyHeader () diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index c62b7d8f5..75117bd3c 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -977,7 +977,7 @@ PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item, Buffer data, uint32_t offset, const PacketPrinter &printer, std::ostream &os) const { - uint32_t uid = item->typeUid & 0xfffffffe; + uint32_t uid = (item->typeUid & 0xfffffffe) >> 1; if (uid == 0) { // payload. @@ -1112,6 +1112,7 @@ template class HistoryHeader : public Header { public: + static const char *GetUid (void); HistoryHeader (); bool IsOk (void) const; private: @@ -1123,6 +1124,15 @@ private: bool m_ok; }; +template +const char * +HistoryHeader::GetUid (void) +{ + std::ostringstream oss; + oss << N << "HistoryHeader.ns3"; + return oss.str ().c_str (); +} + template HistoryHeader::HistoryHeader () : m_ok (false) @@ -1181,6 +1191,7 @@ template class HistoryTrailer : public Trailer { public: + static const char *GetUid (void); HistoryTrailer (); bool IsOk (void) const; private: @@ -1192,6 +1203,16 @@ private: bool m_ok; }; +template +const char * +HistoryTrailer::GetUid (void) +{ + std::ostringstream oss; + oss << N << "HistoryTrailer.ns3"; + return oss.str ().c_str (); +} + + template HistoryTrailer::HistoryTrailer () : m_ok (false) diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index be102a4d3..919f35e42 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -254,26 +254,26 @@ template void PacketMetadata::AddHeader (T const &header, uint32_t size) { - DoAddHeader (PacketPrinter::GetHeaderUid (), size); + DoAddHeader (PacketPrinter::GetHeaderUid () << 1, size); } template void PacketMetadata::RemoveHeader (T const &header, uint32_t size) { - DoRemoveHeader (PacketPrinter::GetHeaderUid (), size); + DoRemoveHeader (PacketPrinter::GetHeaderUid () << 1, size); } template void PacketMetadata::AddTrailer (T const &trailer, uint32_t size) { - DoAddTrailer (PacketPrinter::GetTrailerUid (), size); + DoAddTrailer (PacketPrinter::GetTrailerUid () << 1, size); } template void PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size) { - DoRemoveTrailer (PacketPrinter::GetTrailerUid (), size); + DoRemoveTrailer (PacketPrinter::GetTrailerUid () << 1, size); } diff --git a/src/common/packet-printer.cc b/src/common/packet-printer.cc index 9ccda7668..b5a807d52 100644 --- a/src/common/packet-printer.cc +++ b/src/common/packet-printer.cc @@ -91,17 +91,17 @@ PacketPrinter::PrintChunk (uint32_t chunkUid, uint32_t size) const { RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ()); + NS_ASSERT (chunkUid >= 1 && chunkUid <= registeredChunks->size ()); for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++) { if (i->m_chunkUid == chunkUid) { - DoPrintCallback cb = (*registeredChunks)[chunkUid/2-1].printCallback; + DoPrintCallback cb = (*registeredChunks)[chunkUid-1].printCallback; cb (i->m_printer, start, os, packetUid, size); return; } } - DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback; + DoGetNameCallback cb = (*registeredChunks)[chunkUid-1].getNameCallback; std::string name = cb (); struct PacketPrinter::FragmentInformation info; info.start = 0; @@ -120,8 +120,8 @@ PacketPrinter::PrintChunkFragment (uint32_t chunkUid, uint32_t fragmentEnd) const { RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ()); - DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback; + NS_ASSERT (chunkUid >= 1 && chunkUid <= registeredChunks->size ()); + DoGetNameCallback cb = (*registeredChunks)[chunkUid-1].getNameCallback; std::string name = cb (); struct PacketPrinter::FragmentInformation info; info.start = fragmentStart; @@ -217,16 +217,16 @@ bool PacketPrinter::IsTrailer (uint32_t uid) { RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ()); - bool isHeader = (*registeredChunks)[uid/2-1].isHeader; + NS_ASSERT (uid >= 1 && uid <= registeredChunks->size ()); + bool isHeader = (*registeredChunks)[uid-1].isHeader; return !isHeader; } bool PacketPrinter::IsHeader (uint32_t uid) { RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ()); - bool isHeader = (*registeredChunks)[uid/2-1].isHeader; + NS_ASSERT (uid >= 1 && uid <= registeredChunks->size ()); + bool isHeader = (*registeredChunks)[uid-1].isHeader; return isHeader; } diff --git a/src/common/packet-printer.h b/src/common/packet-printer.h index cd340545d..c79be0a3b 100644 --- a/src/common/packet-printer.h +++ b/src/common/packet-printer.h @@ -140,6 +140,7 @@ private: { DoPrintCallback printCallback; DoGetNameCallback getNameCallback; + std::string uidString; bool isHeader; }; typedef std::vector PrinterList; @@ -291,12 +292,22 @@ uint32_t PacketPrinter::AllocateUid (bool isHeader) { RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks (); + uint32_t j = 0; + for (RegisteredChunks::iterator i = chunks->begin (); i != chunks->end (); i++) + { + if (i->uidString == T::GetUid ()) + { + return j; + } + j++; + } RegisteredChunk chunk; chunk.printCallback = &PacketPrinter::DoPrint; chunk.getNameCallback = &PacketPrinter::DoGetName; chunk.isHeader = isHeader; + chunk.uidString = T::GetUid (); chunks->push_back (chunk); - uint32_t uid = chunks->size () * 2; + uint32_t uid = chunks->size (); PacketPrinter::PeekDefault ()->DoAddPrinter (uid, MakeCallback (&PacketPrinter::DoDefaultPrint).GetImpl (), MakeCallback (&PacketPrinter::DoDefaultPrintFragment)); From 9c1e4a0e70f7f8f319267ad66af51b6545ace336 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 13:00:38 +0200 Subject: [PATCH 159/278] rework the Tags API to ensure proper uid generation for tags --- samples/main-packet.cc | 13 ++- src/common/tags.cc | 192 ++++++++++++++------------------- src/common/tags.h | 235 +++++++++++++++++++---------------------- 3 files changed, 200 insertions(+), 240 deletions(-) diff --git a/samples/main-packet.cc b/samples/main-packet.cc index 8eda7a475..d0796a90b 100644 --- a/samples/main-packet.cc +++ b/samples/main-packet.cc @@ -80,13 +80,18 @@ MyHeader::GetData (void) const /* A sample Tag implementation */ -struct MyTag { +class MyTag +{ +public: + static const char *GetUid (void) {return "MyTag.test.nsnam.org";} + void Print (std::ostream &os) const {} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint16_t m_streamId; }; -static TagRegistration g_MyTagRegistration ("ns3::MyTag", 0); - - static void Receive (Packet p) { diff --git a/src/common/tags.cc b/src/common/tags.cc index 2d72f6bec..ce9a1121d 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -23,80 +23,43 @@ namespace ns3 { -TagRegistry * -TagRegistry::GetInstance (void) +Tag::TagInfoVector * +Tag::GetInfo (void) { - static TagRegistry registry; - return ®istry; + static Tag::TagInfoVector vector; + return &vector; } -TagRegistry::TagRegistry () - : m_sorted (false) -{} - - void -TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor) +Tag::Destruct (uint32_t uid, uint8_t data[Tags::SIZE]) { - NS_ASSERT (!m_sorted); - struct TagInfoItem item; - item.uuid = uuid; - item.printer = prettyPrinter; - item.destructor = destructor; - m_registry.push_back (item); + TagInfo info = (*GetInfo ())[uid - 1]; + info.destruct (data); } -bool -TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b) +void +Tag::Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os) { - return a.uuid < b.uuid; + TagInfo info = (*GetInfo ())[uid - 1]; + info.print (data, os); +} +uint32_t +Tag::GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + return info.getSerializedSize (data); +} +void +Tag::Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + info.serialize (data, start); } uint32_t -TagRegistry::LookupUid (std::string uuid) +Tag::Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) { - if (!m_sorted) - { - std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem); - m_sorted = true; - } - NS_ASSERT (m_sorted); - uint32_t uid = 1; - for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++) - { - if (i->uuid == uuid) - { - return uid; - } - uid++; - } - // someone asked for a uid for an unregistered uuid. - NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration."); - // quiet compiler - return 0; + TagInfo info = (*GetInfo ())[uid - 1]; + return info.deserialize (data, start); } -void -TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os) -{ - NS_ASSERT (uid > 0); - uint32_t index = uid - 1; - NS_ASSERT (m_registry.size () > index); - PrettyPrinter prettyPrinter = m_registry[index].printer; - if (prettyPrinter != 0) - { - prettyPrinter (buf, os); - } -} -void -TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]) -{ - NS_ASSERT (uid > 0); - uint32_t index = uid - 1; - NS_ASSERT (m_registry.size () > index); - Destructor destructor = m_registry[index].destructor; - NS_ASSERT (destructor != 0); - destructor (buf); -} - - #ifdef USE_FREE_LIST @@ -197,7 +160,7 @@ Tags::PrettyPrint (std::ostream &os) { for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os); + Tag::Print (cur->m_id, cur->m_data, os); } } @@ -224,25 +187,65 @@ public: virtual bool RunTests (void); }; -struct myTagA { +class myTagA +{ +public: + static const char *GetUid (void) {return "myTagA.test.nsnam.org";} + void Print (std::ostream &os) const {g_a = true;} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint8_t a; }; -struct myTagB { +class myTagB +{ +public: + static const char *GetUid (void) {return "myTagB.test.nsnam.org";} + void Print (std::ostream &os) const {g_b = true;} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint32_t b; }; -struct myTagC { +class myTagC +{ +public: + static const char *GetUid (void) {return "myTagC.test.nsnam.org";} + void Print (std::ostream &os) const {g_c = true;} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} uint8_t c [Tags::SIZE]; }; -struct myInvalidTag { +class myInvalidTag +{ +public: + static const char *GetUid (void) {return "myInvalidTag.test.nsnam.org";} + void Print (std::ostream &os) const {} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint8_t invalid [Tags::SIZE+1]; }; -struct myTagZ { +class myTagZ +{ +public: + static const char *GetUid (void) {return "myTagZ.test.nsnam.org";} + void Print (std::ostream &os) const {g_z = true;} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint8_t z; }; class MySmartTag { public: + static const char *GetUid (void) {return "mySmartTag.test.nsnam.org";} MySmartTag () { //std::cout << "construct" << std::endl; @@ -260,43 +263,12 @@ public: //std::cout << "assign" << std::endl; return *this; } - static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os) - {} + void Print (std::ostream &os) const {} + uint32_t GetSerializedSize (void) const {return 0;} + void Serialize (Buffer::Iterator i) const {} + uint32_t Deserialize (Buffer::Iterator i) {return 0;} }; -static void -myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os) -{ - //os << "struct myTagA, a="<<(uint32_t)a->a< gMyTagARegistration ("A", &myTagAPrettyPrinterCb); -static TagRegistration gMyTagBRegistration ("B", &myTagBPrettyPrinterCb); -static TagRegistration gMyTagCRegistration ("C", &myTagCPrettyPrinterCb); -static TagRegistration g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", - &myTagZPrettyPrinterCb); -static TagRegistration g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb); - TagsTest::TagsTest () : Test ("Tags") @@ -311,7 +283,7 @@ TagsTest::RunTests (void) // build initial tag. Tags tags; - struct myTagA a; + myTagA a; a.a = 10; tags.Add (a); a.a = 0; @@ -326,7 +298,7 @@ TagsTest::RunTests (void) { ok = false; } - struct myTagB b; + myTagB b; b.b = 0xff; tags.Add (b); b.b = 0; @@ -358,14 +330,14 @@ TagsTest::RunTests (void) { ok = false; } - struct myTagA oA; + myTagA oA; oA.a = 0; other.Peek (oA); if (oA.a != 10) { ok = false; } - struct myTagB oB; + myTagB oB; oB.b = 1; other.Peek (oB); if (oB.b != 0xff) @@ -401,7 +373,7 @@ TagsTest::RunTests (void) other = tags; Tags another = other; - struct myTagC c; + myTagC c; memset (c.c, 0x66, 16); another.Add (c); c.c[0] = 0; @@ -421,7 +393,7 @@ TagsTest::RunTests (void) //struct myInvalidTag invalid; //tags.add (&invalid); - struct myTagZ tagZ; + myTagZ tagZ; Tags testLastTag; tagZ.z = 0; testLastTag.Add (tagZ); diff --git a/src/common/tags.h b/src/common/tags.h index 3c9583c9a..5d4690de8 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -24,6 +24,7 @@ #include #include #include +#include "buffer.h" namespace ns3 { @@ -79,31 +80,7 @@ private: struct TagData *m_next; }; -/** - * \brief pretty print packet tags - * - * This class is used to register a pretty-printer - * callback function to print in a nice user-friendly - * way the content of the target type. To register - * such a type, all you need to do is instantiate - * an instance of this type as a static variable. - */ -template -class TagRegistration { -public: - /** - * \param uuid a uuid generated with uuidgen - * \param fn a function which can pretty-print an instance - * of type T in the output stream. - */ - TagRegistration (std::string uuid, void(*fn) (T const*, std::ostream &)); -private: - static void PrettyPrinterCb (uint8_t *buf, std::ostream &os); - static void DestructorCb (uint8_t *buf); - static void(*m_prettyPrinter) (T const*, std::ostream &); -}; - -}; // namespace ns3 +} // namespace ns3 @@ -115,111 +92,119 @@ private: namespace ns3 { -class TagRegistry { -public: - typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &); - typedef void (*Destructor) (uint8_t [Tags::SIZE]); - void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor); - /** - * returns a numeric integer which uniquely identifies the input string. - * that integer cannot be zero which is a reserved value. - */ - uint32_t LookupUid (std::string uuid); - void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os); - void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]); - - static TagRegistry *GetInstance (void); -private: - TagRegistry (); - struct TagInfoItem - { - std::string uuid; - PrettyPrinter printer; - Destructor destructor; - }; - typedef std::vector TagsData; - typedef std::vector::const_iterator TagsDataCI; - static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b); - bool m_sorted; - TagsData m_registry; -}; -/** - * The TypeUid class is used to create a mapping Type --> uid - * Note that we use a static getUuid function which contains a - * static std::string variable rather than a simpler static - * member std::string variable to ensure the proper order - * of initialization when these methods are invoked - * from the constructor of another static variable. - */ -template -class TypeUid { -public: - static void Record (std::string uuid); - static const uint32_t GetUid (void); -private: - static std::string *GetUuid (void); - T m_realType; -}; - -template -void TypeUid::Record (std::string uuid) +class Tag { - *(GetUuid ()) = uuid; +public: + template + static uint32_t GetUid (void); + static void Destruct (uint32_t uid, uint8_t data[Tags::SIZE]); + static void Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os); + static uint32_t GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]); + static void Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start); + static uint32_t Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start); +private: + typedef void (*DestructCb) (uint8_t [Tags::SIZE]); + typedef void (*PrintCb) (uint8_t [Tags::SIZE], std::ostream &); + typedef uint32_t (*GetSerializedSizeCb) (uint8_t [Tags::SIZE]); + typedef void (*SerializeCb) (uint8_t [Tags::SIZE], Buffer::Iterator); + typedef uint32_t (*DeserializeCb) (uint8_t [Tags::SIZE], Buffer::Iterator); + struct TagInfo + { + std::string uidString; + DestructCb destruct; + PrintCb print; + GetSerializedSizeCb getSerializedSize; + SerializeCb serialize; + DeserializeCb deserialize; + }; + typedef std::vector TagInfoVector; + + template + static void DoDestruct (uint8_t data[Tags::SIZE]); + template + static void DoPrint (uint8_t data[Tags::SIZE], std::ostream &os); + template + static uint32_t DoGetSerializedSize (uint8_t data[Tags::SIZE]); + template + static void DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start); + template + static uint32_t DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start); + template + static uint32_t AllocateUid (void); + + static TagInfoVector *GetInfo (void); +}; + +template +void +Tag::DoDestruct (uint8_t data[Tags::SIZE]) +{ + T *tag = reinterpret_cast (data); + tag->~T (); +} +template +void +Tag::DoPrint (uint8_t data[Tags::SIZE], std::ostream &os) +{ + T *tag = reinterpret_cast (data); + tag->Print (os); +} +template +uint32_t +Tag::DoGetSerializedSize (uint8_t data[Tags::SIZE]) +{ + T *tag = reinterpret_cast (data); + return tag->GetSerializedSize (); +} +template +void +Tag::DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) +{ + T *tag = reinterpret_cast (data); + tag->Serialize (start); +} +template +uint32_t +Tag::DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) +{ + T *tag = reinterpret_cast (data); + return tag->Deserialize (start); } template -const uint32_t TypeUid::GetUid (void) +uint32_t +Tag::GetUid (void) { - static const uint32_t uid = TagRegistry::GetInstance ()-> - LookupUid (*(GetUuid ())); + static uint32_t uid = AllocateUid (); return uid; } template -std::string *TypeUid::GetUuid (void) +uint32_t +Tag::AllocateUid (void) { - static std::string uuid; - return &uuid; + TagInfoVector *vec = GetInfo (); + uint32_t j = 0; + for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == T::GetUid ()) + { + return j; + } + j++; + } + TagInfo info; + info.uidString = T::GetUid (); + info.destruct = &Tag::DoDestruct; + info.print = &Tag::DoPrint; + info.getSerializedSize = &Tag::DoGetSerializedSize; + info.serialize = &Tag::DoSerialize; + info.deserialize = &Tag::DoDeserialize; + vec->push_back (info); + uint32_t uid = vec->size (); + return uid; } - - -/** - * Implementation of the TagRegistration registration class. - * It records a callback with the TagRegistry - * This callback performs type conversion before forwarding - * the call to the user-provided function. - */ -template -TagRegistration::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &)) -{ - NS_ASSERT (sizeof (T) <= Tags::SIZE); - m_prettyPrinter = prettyPrinter; - TagRegistry::GetInstance ()-> - Record (uuid, &TagRegistration::PrettyPrinterCb, &TagRegistration::DestructorCb); - TypeUid::Record (uuid); -} -template -void -TagRegistration::PrettyPrinterCb (uint8_t *buf, std::ostream &os) -{ - NS_ASSERT (sizeof (T) <= Tags::SIZE); - T *tag = reinterpret_cast (buf); - (*m_prettyPrinter) (tag, os); -} -template -void -TagRegistration::DestructorCb (uint8_t *buf) -{ - T *tag = reinterpret_cast (buf); - tag->~T (); -} -template -void (*TagRegistration::m_prettyPrinter) (T const*, std::ostream &) = 0; - - - - template void Tags::Add (T const&tag) @@ -228,12 +213,12 @@ Tags::Add (T const&tag) // ensure this id was not yet added for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - NS_ASSERT (cur->m_id != TypeUid::GetUid ()); + NS_ASSERT (cur->m_id != Tag::GetUid ()); } struct TagData *newStart = AllocData (); newStart->m_count = 1; newStart->m_next = 0; - newStart->m_id = TypeUid::GetUid (); + newStart->m_id = Tag::GetUid (); void *buf = &newStart->m_data; new (buf) T (tag); newStart->m_next = m_next; @@ -245,7 +230,7 @@ bool Tags::Remove (T &tag) { NS_ASSERT (sizeof (T) <= Tags::SIZE); - return Remove (TypeUid::GetUid ()); + return Remove (Tag::GetUid ()); } template @@ -255,7 +240,7 @@ Tags::Peek (T &tag) const NS_ASSERT (sizeof (T) <= Tags::SIZE); for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - if (cur->m_id == TypeUid::GetUid ()) + if (cur->m_id == Tag::GetUid ()) { /* found tag */ T *data = reinterpret_cast (&cur->m_data); @@ -315,16 +300,14 @@ Tags::RemoveAll (void) } if (prev != 0) { - TagRegistry::GetInstance ()-> - Destruct (prev->m_id, prev->m_data); + Tag::Destruct (prev->m_id, prev->m_data); FreeData (prev); } prev = cur; } if (prev != 0) { - TagRegistry::GetInstance ()-> - Destruct (prev->m_id, prev->m_data); + Tag::Destruct (prev->m_id, prev->m_data); FreeData (prev); } m_next = 0; From 9c309707a77d80e46babf679ac097357b67bbb5b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 13:07:10 +0200 Subject: [PATCH 160/278] add internal documentation --- src/common/tags.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/common/tags.h b/src/common/tags.h index 5d4690de8..d204ab875 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -92,6 +92,26 @@ private: namespace ns3 { +/** + * \brief represent a single tag + * \internal + * + * This class is used to give polymorphic access to the methods + * exported by a tag. It also is used to associate a single + * reliable uid to each unique type. The tricky part here is + * that we have to deal correctly with a single type + * being registered multiple times in AllocateUid so, + * AllocateUid must first check in the list of existing + * types if there is already a type registered with the + * same string returned by T::GetUid. + * + * It is important to note that, for example, this code + * will never be triggered on ELF systems (linux, and + * a lot of unixes) because the ELF runtime ensures that + * there exist a single instance of a template instanciation + * even if multiple instanciations of that template are + * present in memory at runtime. + */ class Tag { public: From 6c6a9a073f53ac06edd94ab30bfe4cd795f38e1f Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 13:58:53 +0200 Subject: [PATCH 161/278] implement Tags::Serialize and Tags::Deserialize --- src/common/tags.cc | 123 ++++++++++++++++++++++++++++++++++++++++++--- src/common/tags.h | 7 ++- 2 files changed, 122 insertions(+), 8 deletions(-) diff --git a/src/common/tags.cc b/src/common/tags.cc index ce9a1121d..a58591422 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -20,6 +20,7 @@ */ #include "tags.h" #include +#include "ns3/fatal-error.h" namespace ns3 { @@ -30,6 +31,29 @@ Tag::GetInfo (void) return &vector; } +std::string +Tag::GetUidString (uint32_t uid) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + return info.uidString; +} +uint32_t +Tag::GetUidFromUidString (std::string uidString) +{ + TagInfoVector *vec = GetInfo (); + uint32_t uid = 1; + for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == uidString) + { + return uid; + } + uid++; + } + NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work."); + return 0; +} + void Tag::Destruct (uint32_t uid, uint8_t data[Tags::SIZE]) { @@ -156,7 +180,7 @@ Tags::Remove (uint32_t id) } void -Tags::PrettyPrint (std::ostream &os) +Tags::Print (std::ostream &os) const { for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { @@ -164,6 +188,91 @@ Tags::PrettyPrint (std::ostream &os) } } +uint32_t +Tags::GetSerializedSize (void) const +{ + uint32_t totalSize = 4; // reserve space for the size of the tag data. + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) + { + uint32_t size = Tag::GetSerializedSize (cur->m_id, cur->m_data); + if (size != 0) + { + std::string uidString = Tag::GetUidString (cur->m_id); + totalSize += 4; // for the size of the string itself. + totalSize += uidString.size (); + totalSize += size; + } + } + return totalSize; +} + +void +Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const +{ + i.WriteU32 (totalSize); + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) + { + uint32_t size = Tag::GetSerializedSize (cur->m_id, cur->m_data); + if (size != 0) + { + std::string uidString = Tag::GetUidString (cur->m_id); + i.WriteU32 (uidString.size ()); + uint8_t *buf = (uint8_t *)uidString.c_str (); + i.Write (buf, uidString.size ()); + Tag::Serialize (cur->m_id, cur->m_data, i); + } + } +} +uint32_t +Tags::Deserialize (Buffer::Iterator i) +{ + uint32_t totalSize = i.ReadU32 (); + uint32_t bytesRead = 4; + while (bytesRead < totalSize) + { + uint32_t uidStringSize = i.ReadU32 (); + bytesRead += 4; + std::string uidString; + uidString.reserve (uidStringSize); + for (uint32_t j = 0; j < uidStringSize; j++) + { + uint32_t c = i.ReadU8 (); + uidString.push_back (c); + } + bytesRead += uidStringSize; + uint32_t uid = Tag::GetUidFromUidString (uidString); + struct TagData *newStart = AllocData (); + newStart->m_count = 1; + newStart->m_next = 0; + newStart->m_id = uid; + bytesRead += Tag::Deserialize (uid, newStart->m_data, i); + newStart->m_next = m_next; + m_next = newStart; + } + NS_ASSERT (bytesRead == totalSize); + /** + * The process of serialization/deserialization + * results in an inverted linked-list after + * deserialization so, we invert the linked-list + * in-place here. + * Note: the algorithm below is pretty classic + * but whenever I get to code it, it makes my + * brain hurt :) + */ + struct TagData *prev = 0; + struct TagData *cur = m_next; + while (cur != 0) + { + struct TagData *next = cur->m_next; + cur->m_next = prev; + prev = cur; + cur = next; + } + m_next = prev; + return totalSize; +} + + }; // namespace ns3 @@ -293,7 +402,7 @@ TagsTest::RunTests (void) ok = false; } g_a = false; - tags.PrettyPrint (std::cout); + tags.Print (std::cout); if (!g_a) { ok = false; @@ -309,7 +418,7 @@ TagsTest::RunTests (void) } g_b = false; g_a = false; - tags.PrettyPrint (std::cout); + tags.Print (std::cout); if (!g_a || !g_b) { ok = false; @@ -318,14 +427,14 @@ TagsTest::RunTests (void) Tags other = tags; g_b = false; g_a = false; - other.PrettyPrint (std::cout); + other.Print (std::cout); if (!g_a || !g_b) { ok = false; } g_b = false; g_a = false; - tags.PrettyPrint (std::cout); + tags.Print (std::cout); if (!g_a || !g_b) { ok = false; @@ -352,7 +461,7 @@ TagsTest::RunTests (void) } g_b = false; g_a = false; - other.PrettyPrint (std::cout); + other.Print (std::cout); if (g_a || !g_b) { ok = false; @@ -398,7 +507,7 @@ TagsTest::RunTests (void) tagZ.z = 0; testLastTag.Add (tagZ); g_z = false; - testLastTag.PrettyPrint (std::cout); + testLastTag.Print (std::cout); if (!g_z) { ok = false; diff --git a/src/common/tags.h b/src/common/tags.h index d204ab875..7442b6439 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -55,7 +55,10 @@ public: template bool Peek (T &tag) const; - void PrettyPrint (std::ostream &os); + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator i, uint32_t size) const; + uint32_t Deserialize (Buffer::Iterator i); inline void RemoveAll (void); @@ -117,6 +120,8 @@ class Tag public: template static uint32_t GetUid (void); + static std::string GetUidString (uint32_t uid); + static uint32_t GetUidFromUidString (std::string uidString); static void Destruct (uint32_t uid, uint8_t data[Tags::SIZE]); static void Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os); static uint32_t GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]); From f8a6287322cc2d40f7cc6e6b74ccc8f83ea7cacb Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 14:09:04 +0200 Subject: [PATCH 162/278] improve dox --- src/common/packet.h | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/common/packet.h b/src/common/packet.h index 09090164c..807dbaaca 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -37,12 +37,15 @@ class PacketPrinter; /** * \brief network packets * - * Each network packet contains a byte buffer and a list of tags. + * Each network packet contains a byte buffer, a list of tags, and + * metadata. + * * - The byte buffer stores the serialized content of the headers and trailers * added to a packet. The serialized representation of these headers is expected * to match that of real network packets bit for bit (although nothing * forces you to do this) which means that the content of a packet buffer * is expected to be that of a real packet. + * * - The list of tags stores an arbitrarily large set of arbitrary * user-provided data structures in the packet: only one instance of * each type of data structure is allowed in a list of tags. @@ -51,12 +54,25 @@ class PacketPrinter; * 16 bytes big. Trying to attach bigger data structures will trigger * crashes at runtime. * - * Implementing a new type of Header for a new protocol is pretty easy - * and is a matter of creating a subclass of the ns3::Header base class, - * and implementing the 4 pure virtual methods defined in ns3::Header. - * Sample code which shows how to create such a new Header, how to use - * it, and how to manipulate tags is shown below: - * \include samples/main-packet.cc + * - The metadata describes the type of the headers and trailers which + * were serialized in the byte buffer. The maintenance of metadata is + * optional and disabled by default. To enable it, you must call + * Packet::EnableMetadata and this will allow you to get non-empty + * output from Packet::Print and Packet::PrintDefault. + * + * Implementing a new type of Header or Trailer for a new protocol is + * pretty easy and is a matter of creating a subclass of the ns3::Header + * or of the ns3::Trailer base class, and implementing the 4 pure virtual + * methods defined in either of the two base classes. Users _must_ + * also implement a static public method named GetUid which is + * expected to return a unique string which uniquely identifies the + * user's new header or trailer. + * + * Sample code which shows how to create a new Header, and how to use it, + * is shown in the sample file samples/main-header.cc + * + * Implementing a new type of Tag requires roughly the same amount of + * work: * * The current implementation of the byte buffers and tag list is based * on COW (Copy On Write. An introduction to COW can be found in Scott @@ -70,15 +86,16 @@ class PacketPrinter; * * Dirty operations: * - ns3::Packet::RemoveTag - * - ns3::Packet::Add + * - ns3::Packet::AddHeader + * - ns3::Packet::AddTrailer * - both versions of ns3::Packet::AddAtEnd * * Non-dirty operations: * - ns3::Packet::AddTag * - ns3::Packet::RemoveAllTags * - ns3::Packet::PeekTag - * - ns3::Packet::Peek - * - ns3::Packet::Remove + * - ns3::Packet::RemoveHeader + * - ns3::Packet::RemoveTrailer * - ns3::Packet::CreateFragment * - ns3::Packet::RemoveAtStart * - ns3::Packet::RemoveAtEnd From c05e7134ed6f75f41994ed67ef9d8ea283b11e33 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 17:00:40 +0200 Subject: [PATCH 163/278] doxygen improvements to Packet, Tags, and Headers/Trailers --- samples/main-header.cc | 123 +++++++++++++++++++++++++++++++++++++++++ samples/main-packet.cc | 118 --------------------------------------- samples/wscript | 2 +- src/common/header.h | 23 ++++++++ src/common/packet.h | 16 +++--- src/common/trailer.h | 20 +++++++ 6 files changed, 174 insertions(+), 128 deletions(-) create mode 100644 samples/main-header.cc delete mode 100644 samples/main-packet.cc diff --git a/samples/main-header.cc b/samples/main-header.cc new file mode 100644 index 000000000..27126b8cf --- /dev/null +++ b/samples/main-header.cc @@ -0,0 +1,123 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#include "ns3/packet.h" +#include "ns3/header.h" +#include + +using namespace ns3; + +/* A sample Header implementation + */ +class MyHeader : public Header +{ +public: + static const char *GetUid (void); + + MyHeader (); + virtual ~MyHeader (); + + void SetData (uint16_t data); + uint16_t GetData (void) const; +private: + virtual std::string DoGetName (void) const; + virtual void PrintTo (std::ostream &os) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + virtual uint32_t GetSerializedSize (void) const; + + uint16_t m_data; +}; + +MyHeader::MyHeader () +{ + // we must provide a public default constructor, + // implicit or explicit, but never private. +} +MyHeader::~MyHeader () +{} + +const char * +MyHeader::GetUid (void) +{ + // This string is used by the internals of the packet + // code to keep track of the packet metadata. + // You need to make sure that this string is absolutely + // unique. The code will detect any duplicate string. + return "MyHeader.test.nsnam.org"; +} + +std::string +MyHeader::DoGetName (void) const +{ + // This string is used to identify the type of + // my header by the packet printing routines. + return "MYHEADER"; +} +void +MyHeader::PrintTo (std::ostream &os) const +{ + // This method is invoked by the packet printing + // routines to print the content of my header. + os << "data=" << m_data << std::endl; +} +uint32_t +MyHeader::GetSerializedSize (void) const +{ + // we reserve 2 bytes for our header. + return 2; +} +void +MyHeader::SerializeTo (Buffer::Iterator start) const +{ + // we can serialize two bytes at the start of the buffer. + // we write them in network byte order. + start.WriteHtonU16 (m_data); +} +uint32_t +MyHeader::DeserializeFrom (Buffer::Iterator start) +{ + // we can deserialize two bytes from the start of the buffer. + // we read them in network byte order and store them + // in host byte order. + m_data = start.ReadNtohU16 (); + + // we return the number of bytes effectively read. + return 2; +} + +void +MyHeader::SetData (uint16_t data) +{ + m_data = data; +} +uint16_t +MyHeader::GetData (void) const +{ + return m_data; +} + + + +int main (int argc, char *argv[]) +{ + // instantiate a header. + MyHeader sourceHeader; + sourceHeader.SetData (2); + + // instantiate a packet + Packet p; + // and store my header into the packet. + p.AddHeader (sourceHeader); + + // print the content of my packet on the standard output. + p.Print (std::cout); + + // you can now remove the header from the packet: + MyHeader destinationHeader; + p.RemoveHeader (destinationHeader); + + // and check that the destination and source + // headers contain the same values. + NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ()); + + return 0; +} diff --git a/samples/main-packet.cc b/samples/main-packet.cc deleted file mode 100644 index d0796a90b..000000000 --- a/samples/main-packet.cc +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -#include "ns3/packet.h" -#include "ns3/header.h" -#include - -using namespace ns3; - -/* A sample Header implementation - */ -class MyHeader : public Header -{ -public: - static const char *GetUid (void); - - MyHeader (); - virtual ~MyHeader (); - - void SetData (uint16_t data); - uint16_t GetData (void) const; -private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); - virtual uint32_t GetSerializedSize (void) const; - - uint16_t m_data; -}; - -const char * -MyHeader::GetUid (void) -{ - // make sure the string is really unique. - return "MyHeader.test.nsnam.org"; -} - -MyHeader::MyHeader () -{} -MyHeader::~MyHeader () -{} -std::string -MyHeader::DoGetName (void) const -{ - return "MyHeader"; -} -void -MyHeader::PrintTo (std::ostream &os) const -{ - os << "MyHeader data=" << m_data << std::endl; -} -uint32_t -MyHeader::GetSerializedSize (void) const -{ - return 2; -} -void -MyHeader::SerializeTo (Buffer::Iterator start) const -{ - // serialize in head of buffer - start.WriteHtonU16 (m_data); -} -uint32_t -MyHeader::DeserializeFrom (Buffer::Iterator start) -{ - // deserialize from head of buffer - m_data = start.ReadNtohU16 (); - return GetSerializedSize (); -} - -void -MyHeader::SetData (uint16_t data) -{ - m_data = data; -} -uint16_t -MyHeader::GetData (void) const -{ - return m_data; -} - -/* A sample Tag implementation - */ -class MyTag -{ -public: - static const char *GetUid (void) {return "MyTag.test.nsnam.org";} - void Print (std::ostream &os) const {} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} - - uint16_t m_streamId; -}; - -static void -Receive (Packet p) -{ - MyHeader my; - p.RemoveHeader (my); - std::cout << "received data=" << my.GetData () << std::endl; - struct MyTag myTag; - p.PeekTag (myTag); -} - - -int main (int argc, char *argv[]) -{ - Packet p; - MyHeader my; - my.SetData (2); - std::cout << "send data=2" << std::endl; - p.AddHeader (my); - struct MyTag myTag; - myTag.m_streamId = 5; - p.AddTag (myTag); - Receive (p); - return 0; -} diff --git a/samples/wscript b/samples/wscript index 30c825555..eb4e4f208 100644 --- a/samples/wscript +++ b/samples/wscript @@ -14,7 +14,7 @@ def build(bld): obj = create_ns_prog('main-ptr', 'main-ptr.cc') #obj = create_ns_prog('main-trace', 'main-trace.cc') obj = create_ns_prog('main-simulator', 'main-simulator.cc') - obj = create_ns_prog('main-packet', 'main-packet.cc') + obj = create_ns_prog('main-header', 'main-header.cc') obj = create_ns_prog('main-test', 'main-test.cc') obj = create_ns_prog('main-simple', 'main-simple.cc', deps=['node', 'internet-node', 'applications']) diff --git a/src/common/header.h b/src/common/header.h index 609729b26..b70b1d731 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -36,6 +36,29 @@ namespace ns3 { * - ns3::Header::DeserializeFrom * - ns3::Header::GetSerializedSize * - ns3::Header::PrintTo + * - ns3::Header::DoGetName + * + * Each header must also make sure that: + * - it defines a public default constructor + * - it defines a public static method named GetUid which returns a string. + * + * The latter should look like the following to ensure that + * every header returns a unique string. + * \code + * class MyHeader : public Header + * { + * public: + * static const char *GetUid (void); + * }; + * + * const char *MyHeader::GetUid (void) + * { + * return "MyHeader.unique.prefix"; + * } + * \endcode + * + * Sample code which shows how to create a new Header, and how to use it, + * is shown in the sample file samples/main-header.cc */ class Header : public Chunk { public: diff --git a/src/common/packet.h b/src/common/packet.h index 807dbaaca..3e305fa3d 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -58,21 +58,19 @@ class PacketPrinter; * were serialized in the byte buffer. The maintenance of metadata is * optional and disabled by default. To enable it, you must call * Packet::EnableMetadata and this will allow you to get non-empty - * output from Packet::Print and Packet::PrintDefault. + * output from Packet::Print and Packet::Print. * * Implementing a new type of Header or Trailer for a new protocol is * pretty easy and is a matter of creating a subclass of the ns3::Header - * or of the ns3::Trailer base class, and implementing the 4 pure virtual + * or of the ns3::Trailer base class, and implementing the 5 pure virtual * methods defined in either of the two base classes. Users _must_ - * also implement a static public method named GetUid which is - * expected to return a unique string which uniquely identifies the - * user's new header or trailer. - * - * Sample code which shows how to create a new Header, and how to use it, - * is shown in the sample file samples/main-header.cc + * also make sure that they class defines a public default constructor and + * a public method named GetUid, as documented in the ns3::Header and ns::Trailer + * API documentations. * * Implementing a new type of Tag requires roughly the same amount of - * work: + * work: users must implement a total of 6 methods which are described in + * the ns3::Tags API documentation. * * The current implementation of the byte buffers and tag list is based * on COW (Copy On Write. An introduction to COW can be found in Scott diff --git a/src/common/trailer.h b/src/common/trailer.h index 92aef295f..457c13ccc 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -36,6 +36,26 @@ namespace ns3 { * - ns3::Trailer::DeserializeFrom * - ns3::Trailer::GetSerializedSize * - ns3::Trailer::PrintTo + * - ns3::Trailer::DoGetName + * + * Each trailer must also make sure that: + * - it defines a public default constructor + * - it defines a public static method named GetUid which returns a string. + * + * The latter should look like the following to ensure that + * every trailer returns a unique string. + * \code + * class MyTrailer : public Header + * { + * public: + * static const char *GetUid (void); + * }; + * + * const char *MyTrailer::GetUid (void) + * { + * return "MyTrailer.unique.prefix"; + * } + * \endcode * * Note that the SerializeTo and DeserializeFrom methods behave * in a way which might seem surprising to users: the input iterator From 3378f0de1982b7a40899f67fdc06a45a0c81e6af Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 3 Aug 2007 08:23:23 -0700 Subject: [PATCH 164/278] remove Channel::GetType --- src/devices/p2p/p2p-channel.cc | 6 ------ src/devices/p2p/p2p-channel.h | 2 -- src/node/channel.h | 15 --------------- src/routing/global/global-router-interface.cc | 4 ---- 4 files changed, 27 deletions(-) diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc index c91fe368c..cbc3eb805 100644 --- a/src/devices/p2p/p2p-channel.cc +++ b/src/devices/p2p/p2p-channel.cc @@ -171,12 +171,6 @@ PointToPointChannel::GetDevice (uint32_t i) const return m_link[i].m_src; } - Channel::ChannelType -PointToPointChannel::GetType (void) const -{ - return Channel::PointToPoint; -} - DataRate PointToPointChannel::GetDataRate (void) { diff --git a/src/devices/p2p/p2p-channel.h b/src/devices/p2p/p2p-channel.h index 6bd849741..b534df915 100644 --- a/src/devices/p2p/p2p-channel.h +++ b/src/devices/p2p/p2p-channel.h @@ -94,8 +94,6 @@ public: virtual uint32_t GetNDevices (void) const; virtual Ptr GetDevice (uint32_t i) const; - virtual ChannelType GetType (void) const; - virtual DataRate GetDataRate (void); virtual Time GetDelay (void); diff --git a/src/node/channel.h b/src/node/channel.h index 0fa8d9656..5e72e1ae5 100644 --- a/src/node/channel.h +++ b/src/node/channel.h @@ -36,12 +36,6 @@ class Channel : public Object { public: static const InterfaceId iid; - enum ChannelType - { - Unknown = 0, - PointToPoint, - Multipoint - }; Channel (); Channel (std::string name); @@ -63,18 +57,9 @@ public: */ virtual Ptr GetDevice (uint32_t i) const = 0; - /** - * \returns the abstract type of this channel. Right now this is only - * PointToPoint (p2p) or Multipoint (Ethernet). - * - * This method must be implemented by subclasses. - */ - virtual ChannelType GetType (void) const = 0; - protected: virtual ~Channel (); std::string m_name; - ChannelType m_channelType; private: }; diff --git a/src/routing/global/global-router-interface.cc b/src/routing/global/global-router-interface.cc index 7df422ec3..24a84be06 100644 --- a/src/routing/global/global-router-interface.cc +++ b/src/routing/global/global-router-interface.cc @@ -534,10 +534,6 @@ GlobalRouter::GetLSA (uint32_t n, GlobalRouterLSA &lsa) const Ptr GlobalRouter::GetAdjacent(Ptr nd, Ptr ch) const { -// -// Double-check that channel agrees with device that it's a point-to-point -// - NS_ASSERT(ch->GetType () == Channel::PointToPoint); uint32_t nDevices = ch->GetNDevices(); NS_ASSERT_MSG(nDevices == 2, From 4050d495eddc36c27801f8747c1c8e3ebe26803a Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 17:26:10 +0200 Subject: [PATCH 165/278] fix valgrind warnings --- src/common/packet-metadata.cc | 12 ++++++------ src/internet-node/arp-header.cc | 2 +- src/internet-node/arp-header.h | 3 ++- src/internet-node/udp-header.cc | 2 +- src/internet-node/udp-header.h | 3 ++- src/node/ethernet-header.cc | 2 +- src/node/ethernet-header.h | 3 ++- src/node/ethernet-trailer.cc | 2 +- src/node/ethernet-trailer.h | 3 ++- src/node/llc-snap-header.cc | 7 ++++--- src/node/llc-snap-header.h | 3 ++- 11 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 75117bd3c..6d6264d44 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -1112,7 +1112,7 @@ template class HistoryHeader : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); HistoryHeader (); bool IsOk (void) const; private: @@ -1125,12 +1125,12 @@ private: }; template -const char * +std::string HistoryHeader::GetUid (void) { std::ostringstream oss; oss << N << "HistoryHeader.ns3"; - return oss.str ().c_str (); + return oss.str (); } template @@ -1191,7 +1191,7 @@ template class HistoryTrailer : public Trailer { public: - static const char *GetUid (void); + static std::string GetUid (void); HistoryTrailer (); bool IsOk (void) const; private: @@ -1204,12 +1204,12 @@ private: }; template -const char * +std::string HistoryTrailer::GetUid (void) { std::ostringstream oss; oss << N << "HistoryTrailer.ns3"; - return oss.str ().c_str (); + return oss.str (); } diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index 3ac09fe0d..e31cebf83 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -25,7 +25,7 @@ namespace ns3 { -const char * +std::string ArpHeader::GetUid (void) { return "ArpHeader.ns3"; diff --git a/src/internet-node/arp-header.h b/src/internet-node/arp-header.h index 9c0386b73..c75d268ca 100644 --- a/src/internet-node/arp-header.h +++ b/src/internet-node/arp-header.h @@ -25,6 +25,7 @@ #include "ns3/header.h" #include "ns3/mac-address.h" #include "ns3/ipv4-address.h" +#include namespace ns3 { /** @@ -33,7 +34,7 @@ namespace ns3 { class ArpHeader : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); virtual ~ArpHeader (); diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index cc0591a2f..a7f40d8d1 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -26,7 +26,7 @@ namespace ns3 { bool UdpHeader::m_calcChecksum = false; -const char * +std::string UdpHeader::GetUid (void) { return "UdpHeader.ns3"; diff --git a/src/internet-node/udp-header.h b/src/internet-node/udp-header.h index bc2d0d0e2..1a28f9ef9 100644 --- a/src/internet-node/udp-header.h +++ b/src/internet-node/udp-header.h @@ -23,6 +23,7 @@ #define UDP_HEADER_H #include +#include #include "ns3/header.h" #include "ns3/ipv4-address.h" @@ -33,7 +34,7 @@ namespace ns3 { class UdpHeader : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); /** * \brief Constructor diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index bb7df999b..d88ca027b 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -29,7 +29,7 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetHeader"); namespace ns3 { -const char * +std::string EthernetHeader::GetUid (void) { return "EthernetHeader.ns3"; diff --git a/src/node/ethernet-header.h b/src/node/ethernet-header.h index c403b5ddc..bde39cded 100644 --- a/src/node/ethernet-header.h +++ b/src/node/ethernet-header.h @@ -24,6 +24,7 @@ #include "ns3/header.h" #include "ns3/mac-address.h" +#include namespace ns3 { @@ -48,7 +49,7 @@ namespace ns3 { class EthernetHeader : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); /** * \brief Construct a null ethernet header diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index 4eceea452..d5df680b1 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -30,7 +30,7 @@ namespace ns3 { bool EthernetTrailer::m_calcFcs = false; -const char * +std::string EthernetTrailer::GetUid (void) { return "EthernetTrailer.ns3"; diff --git a/src/node/ethernet-trailer.h b/src/node/ethernet-trailer.h index 4d75c911b..f0452db75 100644 --- a/src/node/ethernet-trailer.h +++ b/src/node/ethernet-trailer.h @@ -24,6 +24,7 @@ #include "ns3/trailer.h" #include "ns3/packet.h" +#include namespace ns3 { /** @@ -36,7 +37,7 @@ namespace ns3 { class EthernetTrailer : public Trailer { public: - static const char *GetUid (void); + static std::string GetUid (void); /** * \brief Construct a null ethernet trailer diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index 1054dddaf..2c594c206 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -19,13 +19,14 @@ * Author: Mathieu Lacage */ -#include "ns3/assert.h" - #include "llc-snap-header.h" +#include "ns3/assert.h" +#include + namespace ns3 { -const char * +std::string LlcSnapHeader::GetUid (void) { return "LlcSnapHeader.ns3"; diff --git a/src/node/llc-snap-header.h b/src/node/llc-snap-header.h index 84404fa94..62b8057a6 100644 --- a/src/node/llc-snap-header.h +++ b/src/node/llc-snap-header.h @@ -23,6 +23,7 @@ #define LLC_SNAP_HEADER_H #include +#include #include "ns3/header.h" namespace ns3 { @@ -30,7 +31,7 @@ namespace ns3 { class LlcSnapHeader : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); LlcSnapHeader (); virtual ~LlcSnapHeader (); From a5b8f5af683049f78dcbf3ae625d5acf5ed69017 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 17:52:21 +0200 Subject: [PATCH 166/278] split test code out of the main PacketMetadata code --- src/common/packet-metadata-test.cc | 668 +++++++++++++++++++++++++++++ src/common/packet-metadata.cc | 648 +--------------------------- src/common/wscript | 1 + 3 files changed, 670 insertions(+), 647 deletions(-) create mode 100644 src/common/packet-metadata-test.cc diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc new file mode 100644 index 000000000..9cd7d4c60 --- /dev/null +++ b/src/common/packet-metadata-test.cc @@ -0,0 +1,668 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006,2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifdef RUN_SELF_TESTS + +#include +#include +#include +#include "ns3/test.h" +#include "header.h" +#include "trailer.h" +#include "packet.h" +#include "packet-metadata.h" +#include "packet-printer.h" + +namespace ns3 { + +template +class HistoryHeader : public Header +{ +public: + static std::string GetUid (void); + HistoryHeader (); + bool IsOk (void) const; +private: + virtual std::string DoGetName (void) const; + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + bool m_ok; +}; + +template +std::string +HistoryHeader::GetUid (void) +{ + std::ostringstream oss; + oss << N << "HistoryHeader.ns3"; + return oss.str (); +} + +template +HistoryHeader::HistoryHeader () + : m_ok (false) +{} + +template +bool +HistoryHeader::IsOk (void) const +{ + return m_ok; +} + +template +std::string +HistoryHeader::DoGetName (void) const +{ + std::ostringstream oss; + oss << N; + return oss.str (); +} + +template +void +HistoryHeader::PrintTo (std::ostream &os) const +{ + NS_ASSERT (false); +} +template +uint32_t +HistoryHeader::GetSerializedSize (void) const +{ + return N; +} +template +void +HistoryHeader::SerializeTo (Buffer::Iterator start) const +{ + start.WriteU8 (N, N); +} +template +uint32_t +HistoryHeader::DeserializeFrom (Buffer::Iterator start) +{ + m_ok = true; + for (int i = 0; i < N; i++) + { + if (start.ReadU8 () != N) + { + m_ok = false; + } + } + return N; +} + +template +class HistoryTrailer : public Trailer +{ +public: + static std::string GetUid (void); + HistoryTrailer (); + bool IsOk (void) const; +private: + virtual std::string DoGetName (void) const; + virtual void PrintTo (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void SerializeTo (Buffer::Iterator start) const; + virtual uint32_t DeserializeFrom (Buffer::Iterator start); + bool m_ok; +}; + +template +std::string +HistoryTrailer::GetUid (void) +{ + std::ostringstream oss; + oss << N << "HistoryTrailer.ns3"; + return oss.str (); +} + + +template +HistoryTrailer::HistoryTrailer () + : m_ok (false) +{} + +template +bool +HistoryTrailer::IsOk (void) const +{ + return m_ok; +} + +template +std::string +HistoryTrailer::DoGetName (void) const +{ + std::ostringstream oss; + oss << N; + return oss.str (); +} +template +void +HistoryTrailer::PrintTo (std::ostream &os) const +{ + NS_ASSERT (false); +} +template +uint32_t +HistoryTrailer::GetSerializedSize (void) const +{ + return N; +} +template +void +HistoryTrailer::SerializeTo (Buffer::Iterator start) const +{ + start.Prev (N); + start.WriteU8 (N, N); +} +template +uint32_t +HistoryTrailer::DeserializeFrom (Buffer::Iterator start) +{ + m_ok = true; + start.Prev (N); + for (int i = 0; i < N; i++) + { + if (start.ReadU8 () != N) + { + m_ok = false; + } + } + return N; +} + + + +class PacketMetadataTest : public Test { +public: + PacketMetadataTest (); + virtual ~PacketMetadataTest (); + bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...); + virtual bool RunTests (void); +private: + template + void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader *header); + template + void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer *trailer); + void PrintFragment (std::ostream &os,uint32_t packetUid, + uint32_t size,std::string & name, + struct PacketPrinter::FragmentInformation info); + void PrintDefault (std::ostream& os,uint32_t packetUid, + uint32_t size,std::string& name, + struct PacketPrinter::FragmentInformation info); + void PrintPayload (std::ostream &os,uint32_t packetUid, + uint32_t size, + struct PacketPrinter::FragmentInformation info); + template + void RegisterHeader (void); + template + void RegisterTrailer (void); + void CleanupPrints (void); + bool Check (const char *file, int line, std::list expected); + + + bool m_headerError; + bool m_trailerError; + std::list m_prints; + PacketPrinter m_printer; +}; + +PacketMetadataTest::PacketMetadataTest () + : Test ("PacketMetadata") +{ + m_printer.AddPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this)); + m_printer.AddDefaultPrinter (MakeCallback (&PacketMetadataTest::PrintDefault, this)); +} + +PacketMetadataTest::~PacketMetadataTest () +{} + +template +void +PacketMetadataTest::RegisterHeader (void) +{ + static bool registered = false; + if (!registered) + { + m_printer.AddHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader, this), + MakeCallback (&PacketMetadataTest::PrintFragment, this)); + registered = true; + } +} + +template +void +PacketMetadataTest::RegisterTrailer (void) +{ + static bool registered = false; + if (!registered) + { + m_printer.AddTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer, this), + MakeCallback (&PacketMetadataTest::PrintFragment, this)); + registered = true; + } +} + + +template +void +PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, + const HistoryHeader *header) +{ + if (!header->IsOk ()) + { + m_headerError = true; + } + m_prints.push_back (N); +} + +template +void +PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, + const HistoryTrailer *trailer) +{ + if (!trailer->IsOk ()) + { + m_trailerError = true; + } + m_prints.push_back (N); +} +void +PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid, + uint32_t size,std::string & name, + struct PacketPrinter::FragmentInformation info) +{ + m_prints.push_back (size - (info.end + info.start)); +} +void +PacketMetadataTest::PrintDefault (std::ostream& os,uint32_t packetUid, + uint32_t size,std::string& name, + struct PacketPrinter::FragmentInformation info) +{ + NS_ASSERT (false); +} +void +PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid, + uint32_t size, + struct PacketPrinter::FragmentInformation info) +{ + m_prints.push_back (size - (info.end + info.start)); +} + + +void +PacketMetadataTest::CleanupPrints (void) +{ + m_prints.clear (); +} + +bool +PacketMetadataTest::Check (const char *file, int line, std::list expected) +{ + if (m_headerError) + { + Failure () << "PacketMetadata header error. file=" << file + << ", line=" << line << std::endl; + return false; + } + if (m_trailerError) + { + Failure () << "PacketMetadata trailer error. file=" << file + << ", line=" << line << std::endl; + return false; + } + if (expected.size () != m_prints.size ()) + { + goto error; + } + for (std::list::iterator i = m_prints.begin (), + j = expected.begin (); + i != m_prints.end (); i++, j++) + { + NS_ASSERT (j != expected.end ()); + if (*j != *i) + { + goto error; + } + } + return true; + error: + Failure () << "PacketMetadata error. file="<< file + << ", line=" << line << ", got:\""; + for (std::list::iterator i = m_prints.begin (); + i != m_prints.end (); i++) + { + Failure () << *i << ", "; + } + Failure () << "\", expected: \""; + for (std::list::iterator j = expected.begin (); + j != expected.end (); j++) + { + Failure () << *j << ", "; + } + Failure () << "\"" << std::endl; + return false; +} + +bool +PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...) +{ + m_headerError = false; + m_trailerError = false; + std::list expected; + va_list ap; + va_start (ap, n); + for (uint32_t j = 0; j < n; j++) + { + int v = va_arg (ap, int); + expected.push_back (v); + } + va_end (ap); + + m_printer.PrintForward (); + p.Print (Failure (), m_printer); + bool ok = Check (file, line, expected); + CleanupPrints (); + if (!ok) + { + return false; + } + + m_printer.PrintBackward (); + p.Print (Failure (), m_printer); + expected.reverse (); + ok = Check (file, line, expected); + CleanupPrints (); + return ok; +} + +#define ADD_HEADER(p, n) \ + { \ + HistoryHeader header; \ + RegisterHeader (); \ + p.AddHeader (header); \ + } +#define ADD_TRAILER(p, n) \ + { \ + HistoryTrailer trailer; \ + RegisterTrailer (); \ + p.AddTrailer (trailer); \ + } +#define REM_HEADER(p, n) \ + { \ + HistoryHeader header; \ + RegisterHeader (); \ + p.RemoveHeader (header); \ + } +#define REM_TRAILER(p, n) \ + { \ + HistoryTrailer trailer; \ + RegisterTrailer (); \ + p.RemoveTrailer (trailer); \ + } +#define CHECK_HISTORY(p, ...) \ + { \ + if (!CheckHistory (p, __FILE__, \ + __LINE__, __VA_ARGS__)) \ + { \ + ok = false; \ + } \ + } + +bool +PacketMetadataTest::RunTests (void) +{ + bool ok = true; + + PacketMetadata::Enable (); + + Packet p = Packet (0); + Packet p1 = Packet (0); + + p = Packet (10); + ADD_TRAILER (p, 100); + CHECK_HISTORY (p, 2, 10, 100); + + p = Packet (10); + ADD_HEADER (p, 1); + ADD_HEADER (p, 2); + ADD_HEADER (p, 3); + CHECK_HISTORY (p, 4, + 3, 2, 1, 10); + ADD_HEADER (p, 5); + CHECK_HISTORY (p, 5, + 5, 3, 2, 1, 10); + ADD_HEADER (p, 6); + CHECK_HISTORY (p, 6, + 6, 5, 3, 2, 1, 10); + + p = Packet (10); + ADD_HEADER (p, 1); + ADD_HEADER (p, 2); + ADD_HEADER (p, 3); + REM_HEADER (p, 3); + CHECK_HISTORY (p, 3, + 2, 1, 10); + + p = Packet (10); + ADD_HEADER (p, 1); + ADD_HEADER (p, 2); + ADD_HEADER (p, 3); + REM_HEADER (p, 3); + REM_HEADER (p, 2); + CHECK_HISTORY (p, 2, + 1, 10); + + p = Packet (10); + ADD_HEADER (p, 1); + ADD_HEADER (p, 2); + ADD_HEADER (p, 3); + REM_HEADER (p, 3); + REM_HEADER (p, 2); + REM_HEADER (p, 1); + CHECK_HISTORY (p, 1, 10); + + p = Packet (10); + ADD_HEADER (p, 1); + ADD_HEADER (p, 2); + ADD_HEADER (p, 3); + p1 = p; + REM_HEADER (p1, 3); + REM_HEADER (p1, 2); + REM_HEADER (p1, 1); + CHECK_HISTORY (p1, 1, 10); + CHECK_HISTORY (p, 4, + 3, 2, 1, 10); + ADD_HEADER (p1, 1); + ADD_HEADER (p1, 2); + CHECK_HISTORY (p1, 3, + 2, 1, 10); + CHECK_HISTORY (p, 4, + 3, 2, 1, 10); + ADD_HEADER (p, 3); + CHECK_HISTORY (p, 5, + 3, 3, 2, 1, 10); + ADD_TRAILER (p, 4); + CHECK_HISTORY (p, 6, + 3, 3, 2, 1, 10, 4); + ADD_TRAILER (p, 5); + CHECK_HISTORY (p, 7, + 3, 3, 2, 1, 10, 4, 5); + REM_HEADER (p, 3); + CHECK_HISTORY (p, 6, + 3, 2, 1, 10, 4, 5); + REM_TRAILER (p, 5); + CHECK_HISTORY (p, 5, + 3, 2, 1, 10, 4); + p1 = p; + REM_TRAILER (p, 4); + CHECK_HISTORY (p, 4, + 3, 2, 1, 10); + CHECK_HISTORY (p1, 5, + 3, 2, 1, 10, 4); + p1.RemoveAtStart (3); + CHECK_HISTORY (p1, 4, + 2, 1, 10, 4); + p1.RemoveAtStart (1); + CHECK_HISTORY (p1, 4, + 1, 1, 10, 4); + p1.RemoveAtStart (1); + CHECK_HISTORY (p1, 3, + 1, 10, 4); + p1.RemoveAtEnd (4); + CHECK_HISTORY (p1, 2, + 1, 10); + p1.RemoveAtStart (1); + CHECK_HISTORY (p1, 1, 10); + + p = Packet (10); + ADD_HEADER (p, 8); + ADD_TRAILER (p, 8); + ADD_TRAILER (p, 8); + p.RemoveAtStart (8+10+8); + CHECK_HISTORY (p, 1, 8); + + p = Packet (10); + ADD_HEADER (p, 10); + ADD_HEADER (p, 8); + ADD_TRAILER (p, 6); + ADD_TRAILER (p, 7); + ADD_TRAILER (p, 9); + p.RemoveAtStart (5); + p.RemoveAtEnd (12); + CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4); + + p = Packet (10); + ADD_HEADER (p, 10); + ADD_TRAILER (p, 6); + p.RemoveAtEnd (18); + ADD_TRAILER (p, 5); + ADD_HEADER (p, 3); + CHECK_HISTORY (p, 3, 3, 8, 5); + p.RemoveAtStart (12); + CHECK_HISTORY (p, 1, 4); + p.RemoveAtEnd (2); + CHECK_HISTORY (p, 1, 2); + ADD_HEADER (p, 10); + CHECK_HISTORY (p, 2, 10, 2); + p.RemoveAtEnd (5); + CHECK_HISTORY (p, 1, 7); + + Packet p2 = Packet (0); + Packet p3 = Packet (0); + + p = Packet (40); + ADD_HEADER (p, 5); + ADD_HEADER (p, 8); + CHECK_HISTORY (p, 3, 8, 5, 40); + p1 = p.CreateFragment (0, 5); + p2 = p.CreateFragment (5, 5); + p3 = p.CreateFragment (10, 43); + CHECK_HISTORY (p1, 1, 5); + CHECK_HISTORY (p2, 2, 3, 2); + CHECK_HISTORY (p3, 2, 3, 40); + p1.AddAtEnd (p2); + CHECK_HISTORY (p1, 2, 8, 2); + CHECK_HISTORY (p2, 2, 3, 2); + p1.AddAtEnd (p3); + CHECK_HISTORY (p1, 3, 8, 5, 40); + CHECK_HISTORY (p2, 2, 3, 2); + CHECK_HISTORY (p3, 2, 3, 40); + p1 = p.CreateFragment (0, 5); + CHECK_HISTORY (p1, 1, 5); + + p3 = Packet (50); + ADD_HEADER (p3, 8); + CHECK_HISTORY (p3, 2, 8, 50); + CHECK_HISTORY (p1, 1, 5); + p1.AddAtEnd (p3); + CHECK_HISTORY (p1, 3, 5, 8, 50); + ADD_HEADER (p1, 5); + CHECK_HISTORY (p1, 4, 5, 5, 8, 50); + ADD_TRAILER (p1, 2); + CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2); + REM_HEADER (p1, 5); + CHECK_HISTORY (p1, 4, 5, 8, 50, 2); + p1.RemoveAtEnd (60); + CHECK_HISTORY (p1, 1, 5); + p1.AddAtEnd (p2); + CHECK_HISTORY (p1, 2, 8, 2); + CHECK_HISTORY (p2, 2, 3, 2); + + p3 = Packet (40); + ADD_HEADER (p3, 5); + ADD_HEADER (p3, 5); + CHECK_HISTORY (p3, 3, 5, 5, 40); + p1 = p3.CreateFragment (0, 5); + p2 = p3.CreateFragment (5, 5); + CHECK_HISTORY (p1, 1, 5); + CHECK_HISTORY (p2, 1, 5); + p1.AddAtEnd (p2); + CHECK_HISTORY (p1, 2, 5, 5); + + p = Packet (0); + CHECK_HISTORY (p, 0); + + p3 = Packet (0); + ADD_HEADER (p3, 5); + ADD_HEADER (p3, 5); + CHECK_HISTORY (p3, 2, 5, 5); + p1 = p3.CreateFragment (0, 4); + p2 = p3.CreateFragment (9, 1); + CHECK_HISTORY (p1, 1, 4); + CHECK_HISTORY (p2, 1, 1); + p1.AddAtEnd (p2); + CHECK_HISTORY (p1, 2, 4, 1); + + + p = Packet (2000); + CHECK_HISTORY (p, 1, 2000); + + p = Packet (); + ADD_TRAILER (p, 10); + ADD_HEADER (p, 5); + p1 = p.CreateFragment (0, 8); + p2 = p.CreateFragment (8, 7); + p1.AddAtEnd (p2); + CHECK_HISTORY (p, 2, 5, 10); + + p = Packet (); + ADD_TRAILER (p, 10); + REM_TRAILER (p, 10); + ADD_TRAILER (p, 10); + CHECK_HISTORY (p, 1, 10); + + p = Packet (); + ADD_HEADER (p, 10); + REM_HEADER (p, 10); + ADD_HEADER (p, 10); + CHECK_HISTORY (p, 1, 10); + + return ok; +} + +static PacketMetadataTest g_packetHistoryTest; + +}//namespace ns3 + +#endif /* RUN_SELF_TESTS */ diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 6d6264d44..1bb29ca00 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -1,7 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2006,2007 INRIA - * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1094,650 +1093,5 @@ PacketMetadata::Print (std::ostream &os, Buffer data, const PacketPrinter &print } } +} // namespace ns3 - -}; // namespace ns3 - -#include -#include -#include -#include "ns3/test.h" -#include "header.h" -#include "trailer.h" -#include "packet.h" - -namespace ns3 { - -template -class HistoryHeader : public Header -{ -public: - static std::string GetUid (void); - HistoryHeader (); - bool IsOk (void) const; -private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); - bool m_ok; -}; - -template -std::string -HistoryHeader::GetUid (void) -{ - std::ostringstream oss; - oss << N << "HistoryHeader.ns3"; - return oss.str (); -} - -template -HistoryHeader::HistoryHeader () - : m_ok (false) -{} - -template -bool -HistoryHeader::IsOk (void) const -{ - return m_ok; -} - -template -std::string -HistoryHeader::DoGetName (void) const -{ - std::ostringstream oss; - oss << N; - return oss.str (); -} - -template -void -HistoryHeader::PrintTo (std::ostream &os) const -{ - NS_ASSERT (false); -} -template -uint32_t -HistoryHeader::GetSerializedSize (void) const -{ - return N; -} -template -void -HistoryHeader::SerializeTo (Buffer::Iterator start) const -{ - start.WriteU8 (N, N); -} -template -uint32_t -HistoryHeader::DeserializeFrom (Buffer::Iterator start) -{ - m_ok = true; - for (int i = 0; i < N; i++) - { - if (start.ReadU8 () != N) - { - m_ok = false; - } - } - return N; -} - -template -class HistoryTrailer : public Trailer -{ -public: - static std::string GetUid (void); - HistoryTrailer (); - bool IsOk (void) const; -private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); - bool m_ok; -}; - -template -std::string -HistoryTrailer::GetUid (void) -{ - std::ostringstream oss; - oss << N << "HistoryTrailer.ns3"; - return oss.str (); -} - - -template -HistoryTrailer::HistoryTrailer () - : m_ok (false) -{} - -template -bool -HistoryTrailer::IsOk (void) const -{ - return m_ok; -} - -template -std::string -HistoryTrailer::DoGetName (void) const -{ - std::ostringstream oss; - oss << N; - return oss.str (); -} -template -void -HistoryTrailer::PrintTo (std::ostream &os) const -{ - NS_ASSERT (false); -} -template -uint32_t -HistoryTrailer::GetSerializedSize (void) const -{ - return N; -} -template -void -HistoryTrailer::SerializeTo (Buffer::Iterator start) const -{ - start.Prev (N); - start.WriteU8 (N, N); -} -template -uint32_t -HistoryTrailer::DeserializeFrom (Buffer::Iterator start) -{ - m_ok = true; - start.Prev (N); - for (int i = 0; i < N; i++) - { - if (start.ReadU8 () != N) - { - m_ok = false; - } - } - return N; -} - - - -class PacketMetadataTest : public Test { -public: - PacketMetadataTest (); - virtual ~PacketMetadataTest (); - bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...); - virtual bool RunTests (void); -private: - template - void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader *header); - template - void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer *trailer); - void PrintFragment (std::ostream &os,uint32_t packetUid, - uint32_t size,std::string & name, - struct PacketPrinter::FragmentInformation info); - void PrintDefault (std::ostream& os,uint32_t packetUid, - uint32_t size,std::string& name, - struct PacketPrinter::FragmentInformation info); - void PrintPayload (std::ostream &os,uint32_t packetUid, - uint32_t size, - struct PacketPrinter::FragmentInformation info); - template - void RegisterHeader (void); - template - void RegisterTrailer (void); - void CleanupPrints (void); - bool Check (const char *file, int line, std::list expected); - - - bool m_headerError; - bool m_trailerError; - std::list m_prints; - PacketPrinter m_printer; -}; - -PacketMetadataTest::PacketMetadataTest () - : Test ("PacketMetadata") -{ - m_printer.AddPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this)); - m_printer.AddDefaultPrinter (MakeCallback (&PacketMetadataTest::PrintDefault, this)); -} - -PacketMetadataTest::~PacketMetadataTest () -{} - -template -void -PacketMetadataTest::RegisterHeader (void) -{ - static bool registered = false; - if (!registered) - { - m_printer.AddHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader, this), - MakeCallback (&PacketMetadataTest::PrintFragment, this)); - registered = true; - } -} - -template -void -PacketMetadataTest::RegisterTrailer (void) -{ - static bool registered = false; - if (!registered) - { - m_printer.AddTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer, this), - MakeCallback (&PacketMetadataTest::PrintFragment, this)); - registered = true; - } -} - - -template -void -PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, - const HistoryHeader *header) -{ - if (!header->IsOk ()) - { - m_headerError = true; - } - m_prints.push_back (N); -} - -template -void -PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, - const HistoryTrailer *trailer) -{ - if (!trailer->IsOk ()) - { - m_trailerError = true; - } - m_prints.push_back (N); -} -void -PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid, - uint32_t size,std::string & name, - struct PacketPrinter::FragmentInformation info) -{ - m_prints.push_back (size - (info.end + info.start)); -} -void -PacketMetadataTest::PrintDefault (std::ostream& os,uint32_t packetUid, - uint32_t size,std::string& name, - struct PacketPrinter::FragmentInformation info) -{ - NS_ASSERT (false); -} -void -PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid, - uint32_t size, - struct PacketPrinter::FragmentInformation info) -{ - m_prints.push_back (size - (info.end + info.start)); -} - - -void -PacketMetadataTest::CleanupPrints (void) -{ - m_prints.clear (); -} - -bool -PacketMetadataTest::Check (const char *file, int line, std::list expected) -{ - if (m_headerError) - { - Failure () << "PacketMetadata header error. file=" << file - << ", line=" << line << std::endl; - return false; - } - if (m_trailerError) - { - Failure () << "PacketMetadata trailer error. file=" << file - << ", line=" << line << std::endl; - return false; - } - if (expected.size () != m_prints.size ()) - { - goto error; - } - for (std::list::iterator i = m_prints.begin (), - j = expected.begin (); - i != m_prints.end (); i++, j++) - { - NS_ASSERT (j != expected.end ()); - if (*j != *i) - { - goto error; - } - } - return true; - error: - Failure () << "PacketMetadata error. file="<< file - << ", line=" << line << ", got:\""; - for (std::list::iterator i = m_prints.begin (); - i != m_prints.end (); i++) - { - Failure () << *i << ", "; - } - Failure () << "\", expected: \""; - for (std::list::iterator j = expected.begin (); - j != expected.end (); j++) - { - Failure () << *j << ", "; - } - Failure () << "\"" << std::endl; - return false; -} - -bool -PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...) -{ - m_headerError = false; - m_trailerError = false; - std::list expected; - va_list ap; - va_start (ap, n); - for (uint32_t j = 0; j < n; j++) - { - int v = va_arg (ap, int); - expected.push_back (v); - } - va_end (ap); - - m_printer.PrintForward (); - p.Print (Failure (), m_printer); - bool ok = Check (file, line, expected); - CleanupPrints (); - if (!ok) - { - return false; - } - - m_printer.PrintBackward (); - p.Print (Failure (), m_printer); - expected.reverse (); - ok = Check (file, line, expected); - CleanupPrints (); - return ok; -} - -#define ADD_HEADER(p, n) \ - { \ - HistoryHeader header; \ - RegisterHeader (); \ - p.AddHeader (header); \ - } -#define ADD_TRAILER(p, n) \ - { \ - HistoryTrailer trailer; \ - RegisterTrailer (); \ - p.AddTrailer (trailer); \ - } -#define REM_HEADER(p, n) \ - { \ - HistoryHeader header; \ - RegisterHeader (); \ - p.RemoveHeader (header); \ - } -#define REM_TRAILER(p, n) \ - { \ - HistoryTrailer trailer; \ - RegisterTrailer (); \ - p.RemoveTrailer (trailer); \ - } -#define CHECK_HISTORY(p, ...) \ - { \ - if (!CheckHistory (p, __FILE__, \ - __LINE__, __VA_ARGS__)) \ - { \ - ok = false; \ - } \ - } - -bool -PacketMetadataTest::RunTests (void) -{ - bool ok = true; - - PacketMetadata::Enable (); - - Packet p = Packet (0); - Packet p1 = Packet (0); - - p = Packet (10); - ADD_TRAILER (p, 100); - CHECK_HISTORY (p, 2, 10, 100); - - p = Packet (10); - ADD_HEADER (p, 1); - ADD_HEADER (p, 2); - ADD_HEADER (p, 3); - CHECK_HISTORY (p, 4, - 3, 2, 1, 10); - ADD_HEADER (p, 5); - CHECK_HISTORY (p, 5, - 5, 3, 2, 1, 10); - ADD_HEADER (p, 6); - CHECK_HISTORY (p, 6, - 6, 5, 3, 2, 1, 10); - - p = Packet (10); - ADD_HEADER (p, 1); - ADD_HEADER (p, 2); - ADD_HEADER (p, 3); - REM_HEADER (p, 3); - CHECK_HISTORY (p, 3, - 2, 1, 10); - - p = Packet (10); - ADD_HEADER (p, 1); - ADD_HEADER (p, 2); - ADD_HEADER (p, 3); - REM_HEADER (p, 3); - REM_HEADER (p, 2); - CHECK_HISTORY (p, 2, - 1, 10); - - p = Packet (10); - ADD_HEADER (p, 1); - ADD_HEADER (p, 2); - ADD_HEADER (p, 3); - REM_HEADER (p, 3); - REM_HEADER (p, 2); - REM_HEADER (p, 1); - CHECK_HISTORY (p, 1, 10); - - p = Packet (10); - ADD_HEADER (p, 1); - ADD_HEADER (p, 2); - ADD_HEADER (p, 3); - p1 = p; - REM_HEADER (p1, 3); - REM_HEADER (p1, 2); - REM_HEADER (p1, 1); - CHECK_HISTORY (p1, 1, 10); - CHECK_HISTORY (p, 4, - 3, 2, 1, 10); - ADD_HEADER (p1, 1); - ADD_HEADER (p1, 2); - CHECK_HISTORY (p1, 3, - 2, 1, 10); - CHECK_HISTORY (p, 4, - 3, 2, 1, 10); - ADD_HEADER (p, 3); - CHECK_HISTORY (p, 5, - 3, 3, 2, 1, 10); - ADD_TRAILER (p, 4); - CHECK_HISTORY (p, 6, - 3, 3, 2, 1, 10, 4); - ADD_TRAILER (p, 5); - CHECK_HISTORY (p, 7, - 3, 3, 2, 1, 10, 4, 5); - REM_HEADER (p, 3); - CHECK_HISTORY (p, 6, - 3, 2, 1, 10, 4, 5); - REM_TRAILER (p, 5); - CHECK_HISTORY (p, 5, - 3, 2, 1, 10, 4); - p1 = p; - REM_TRAILER (p, 4); - CHECK_HISTORY (p, 4, - 3, 2, 1, 10); - CHECK_HISTORY (p1, 5, - 3, 2, 1, 10, 4); - p1.RemoveAtStart (3); - CHECK_HISTORY (p1, 4, - 2, 1, 10, 4); - p1.RemoveAtStart (1); - CHECK_HISTORY (p1, 4, - 1, 1, 10, 4); - p1.RemoveAtStart (1); - CHECK_HISTORY (p1, 3, - 1, 10, 4); - p1.RemoveAtEnd (4); - CHECK_HISTORY (p1, 2, - 1, 10); - p1.RemoveAtStart (1); - CHECK_HISTORY (p1, 1, 10); - - p = Packet (10); - ADD_HEADER (p, 8); - ADD_TRAILER (p, 8); - ADD_TRAILER (p, 8); - p.RemoveAtStart (8+10+8); - CHECK_HISTORY (p, 1, 8); - - p = Packet (10); - ADD_HEADER (p, 10); - ADD_HEADER (p, 8); - ADD_TRAILER (p, 6); - ADD_TRAILER (p, 7); - ADD_TRAILER (p, 9); - p.RemoveAtStart (5); - p.RemoveAtEnd (12); - CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4); - - p = Packet (10); - ADD_HEADER (p, 10); - ADD_TRAILER (p, 6); - p.RemoveAtEnd (18); - ADD_TRAILER (p, 5); - ADD_HEADER (p, 3); - CHECK_HISTORY (p, 3, 3, 8, 5); - p.RemoveAtStart (12); - CHECK_HISTORY (p, 1, 4); - p.RemoveAtEnd (2); - CHECK_HISTORY (p, 1, 2); - ADD_HEADER (p, 10); - CHECK_HISTORY (p, 2, 10, 2); - p.RemoveAtEnd (5); - CHECK_HISTORY (p, 1, 7); - - Packet p2 = Packet (0); - Packet p3 = Packet (0); - - p = Packet (40); - ADD_HEADER (p, 5); - ADD_HEADER (p, 8); - CHECK_HISTORY (p, 3, 8, 5, 40); - p1 = p.CreateFragment (0, 5); - p2 = p.CreateFragment (5, 5); - p3 = p.CreateFragment (10, 43); - CHECK_HISTORY (p1, 1, 5); - CHECK_HISTORY (p2, 2, 3, 2); - CHECK_HISTORY (p3, 2, 3, 40); - p1.AddAtEnd (p2); - CHECK_HISTORY (p1, 2, 8, 2); - CHECK_HISTORY (p2, 2, 3, 2); - p1.AddAtEnd (p3); - CHECK_HISTORY (p1, 3, 8, 5, 40); - CHECK_HISTORY (p2, 2, 3, 2); - CHECK_HISTORY (p3, 2, 3, 40); - p1 = p.CreateFragment (0, 5); - CHECK_HISTORY (p1, 1, 5); - - p3 = Packet (50); - ADD_HEADER (p3, 8); - CHECK_HISTORY (p3, 2, 8, 50); - CHECK_HISTORY (p1, 1, 5); - p1.AddAtEnd (p3); - CHECK_HISTORY (p1, 3, 5, 8, 50); - ADD_HEADER (p1, 5); - CHECK_HISTORY (p1, 4, 5, 5, 8, 50); - ADD_TRAILER (p1, 2); - CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2); - REM_HEADER (p1, 5); - CHECK_HISTORY (p1, 4, 5, 8, 50, 2); - p1.RemoveAtEnd (60); - CHECK_HISTORY (p1, 1, 5); - p1.AddAtEnd (p2); - CHECK_HISTORY (p1, 2, 8, 2); - CHECK_HISTORY (p2, 2, 3, 2); - - p3 = Packet (40); - ADD_HEADER (p3, 5); - ADD_HEADER (p3, 5); - CHECK_HISTORY (p3, 3, 5, 5, 40); - p1 = p3.CreateFragment (0, 5); - p2 = p3.CreateFragment (5, 5); - CHECK_HISTORY (p1, 1, 5); - CHECK_HISTORY (p2, 1, 5); - p1.AddAtEnd (p2); - CHECK_HISTORY (p1, 2, 5, 5); - - p = Packet (0); - CHECK_HISTORY (p, 0); - - p3 = Packet (0); - ADD_HEADER (p3, 5); - ADD_HEADER (p3, 5); - CHECK_HISTORY (p3, 2, 5, 5); - p1 = p3.CreateFragment (0, 4); - p2 = p3.CreateFragment (9, 1); - CHECK_HISTORY (p1, 1, 4); - CHECK_HISTORY (p2, 1, 1); - p1.AddAtEnd (p2); - CHECK_HISTORY (p1, 2, 4, 1); - - - p = Packet (2000); - CHECK_HISTORY (p, 1, 2000); - - p = Packet (); - ADD_TRAILER (p, 10); - ADD_HEADER (p, 5); - p1 = p.CreateFragment (0, 8); - p2 = p.CreateFragment (8, 7); - p1.AddAtEnd (p2); - CHECK_HISTORY (p, 2, 5, 10); - - p = Packet (); - ADD_TRAILER (p, 10); - REM_TRAILER (p, 10); - ADD_TRAILER (p, 10); - CHECK_HISTORY (p, 1, 10); - - p = Packet (); - ADD_HEADER (p, 10); - REM_HEADER (p, 10); - ADD_HEADER (p, 10); - CHECK_HISTORY (p, 1, 10); - - return ok; -} - -static PacketMetadataTest g_packetHistoryTest; - -}//namespace ns3 diff --git a/src/common/wscript b/src/common/wscript index 5d58f37b2..c1165026a 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -12,6 +12,7 @@ def build(bld): 'trailer.cc', 'packet-printer.cc', 'packet-metadata.cc', + 'packet-metadata-test.cc', 'packet.cc', 'tags.cc', 'pcap-writer.cc', From f6ec749e96bd55501149425478d1ec1c7e345df1 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 17:52:39 +0200 Subject: [PATCH 167/278] update sample code to use a std::string rather than a const char * --- samples/main-header.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/main-header.cc b/samples/main-header.cc index 27126b8cf..ed665045d 100644 --- a/samples/main-header.cc +++ b/samples/main-header.cc @@ -10,7 +10,7 @@ using namespace ns3; class MyHeader : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); MyHeader (); virtual ~MyHeader (); @@ -35,7 +35,7 @@ MyHeader::MyHeader () MyHeader::~MyHeader () {} -const char * +std::string MyHeader::GetUid (void) { // This string is used by the internals of the packet From 555885a3b0d5a117cffae2e28fd0611f6295454d Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 3 Aug 2007 17:52:58 +0200 Subject: [PATCH 168/278] add Tag documentation --- src/common/packet.h | 119 ++++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 33 deletions(-) diff --git a/src/common/packet.h b/src/common/packet.h index 3e305fa3d..93e62f4cf 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -70,39 +70,10 @@ class PacketPrinter; * * Implementing a new type of Tag requires roughly the same amount of * work: users must implement a total of 6 methods which are described in - * the ns3::Tags API documentation. + * \ref tags * - * The current implementation of the byte buffers and tag list is based - * on COW (Copy On Write. An introduction to COW can be found in Scott - * Meyer's "More Effective C++", items 17 and 29). What this means is that - * copying packets without modifying them is very cheap (in terms of cpu - * and memory usage) and modifying them can be also very cheap. What is - * key for proper COW implementations is being - * able to detect when a given modification of the state of a packet triggers - * a full copy of the data prior to the modification: COW systems need - * to detect when an operation is "dirty". - * - * Dirty operations: - * - ns3::Packet::RemoveTag - * - ns3::Packet::AddHeader - * - ns3::Packet::AddTrailer - * - both versions of ns3::Packet::AddAtEnd - * - * Non-dirty operations: - * - ns3::Packet::AddTag - * - ns3::Packet::RemoveAllTags - * - ns3::Packet::PeekTag - * - ns3::Packet::RemoveHeader - * - ns3::Packet::RemoveTrailer - * - ns3::Packet::CreateFragment - * - ns3::Packet::RemoveAtStart - * - ns3::Packet::RemoveAtEnd - * - * Dirty operations will always be slower than non-dirty operations, - * sometimes by several orders of magnitude. However, even the - * dirty operations have been optimized for common use-cases which - * means that most of the time, these operations will not trigger - * data copies and will thus be still very fast. + * The performance aspects of the Packet API are discussed in + * \ref packetperf */ class Packet { public: @@ -317,7 +288,89 @@ private: static uint32_t m_globalUid; }; -}; // namespace ns3 +/** + * \defgroup tags Packet Tags + * + * A tag is a class which must define: + * - a public default constructor + * - a public static method named GetUid + * - a public method named Print + * - a public method named GetSerializedSize + * - a public method named Serialize + * - a public method named Deserialize + * + * So, a tag class should look like this: + * \code + * // note how a tag class does not derive from any other class. + * class MyTag + * { + * public: + * // we need a public default constructor + * MyTag (); + * // we need a public static GetUid + * // GetUid must return a string which uniquely + * // identifies this tag type + * static std::string GetUid (void); + * // Print should record in the output stream + * // the content of the tag instance. + * void Print (std::ostream &os) const; + * // GetSerializedSize should return the number of bytes needed + * // to store the state of a tag instance + * uint32_t GetSerializedSize (void) const; + * // Serialize should store its state in the input + * // buffer with the help of the iterator. It should + * // write exactly size bytes. + * void Serialize (Buffer::Iterator i, uint32_t size) const; + * // Deserialize should restore the state of a Tag instance + * // from a byte buffer with the help of the iterator + * uint32_t Deserialize (Buffer::Iterator i); + * }; + * + * std::string MyTag::GetUid (void) + * { + * // we really want to make sure that this + * // string is unique in the universe. + * return "MyTag.unique.prefix"; + * } + * \endcode + */ + +/** + * \defgroup packetperf Packet Performance + * The current implementation of the byte buffers and tag list is based + * on COW (Copy On Write. An introduction to COW can be found in Scott + * Meyer's "More Effective C++", items 17 and 29). What this means is that + * copying packets without modifying them is very cheap (in terms of cpu + * and memory usage) and modifying them can be also very cheap. What is + * key for proper COW implementations is being + * able to detect when a given modification of the state of a packet triggers + * a full copy of the data prior to the modification: COW systems need + * to detect when an operation is "dirty". + * + * Dirty operations: + * - ns3::Packet::RemoveTag + * - ns3::Packet::AddHeader + * - ns3::Packet::AddTrailer + * - both versions of ns3::Packet::AddAtEnd + * + * Non-dirty operations: + * - ns3::Packet::AddTag + * - ns3::Packet::RemoveAllTags + * - ns3::Packet::PeekTag + * - ns3::Packet::RemoveHeader + * - ns3::Packet::RemoveTrailer + * - ns3::Packet::CreateFragment + * - ns3::Packet::RemoveAtStart + * - ns3::Packet::RemoveAtEnd + * + * Dirty operations will always be slower than non-dirty operations, + * sometimes by several orders of magnitude. However, even the + * dirty operations have been optimized for common use-cases which + * means that most of the time, these operations will not trigger + * data copies and will thus be still very fast. + */ + +} // namespace ns3 /************************************************** From de77db64fcb7b8cb4fdcaab031d07ba30738b567 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 3 Aug 2007 09:29:57 -0700 Subject: [PATCH 169/278] interim --- examples/wscript | 8 +++++--- src/internet-node/wscript | 2 +- src/routing/global/wscript | 8 ++------ src/wscript | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/examples/wscript b/examples/wscript index 03ca1de60..0f15f23df 100644 --- a/examples/wscript +++ b/examples/wscript @@ -10,7 +10,9 @@ def build(bld): return obj obj = create_ns_prog('simple-global-routing', 'simple-global-routing.cc', - deps=['p2p', 'internet-node', 'routing']) - obj = create_ns_prog('simple-point-to-point', 'simple-point-to-point.cc', deps=['point-to-point', 'internet-node']) - obj = create_ns_prog('csma-cd-one-subnet', 'csma-cd-one-subnet.cc', deps=['csma-cd', 'internet-node']) + deps=['point-to-point', 'internet-node', 'global-routing']) + obj = create_ns_prog('simple-point-to-point', 'simple-point-to-point.cc', + deps=['point-to-point', 'internet-node']) + obj = create_ns_prog('csma-cd-one-subnet', 'csma-cd-one-subnet.cc', + deps=['csma-cd', 'internet-node']) diff --git a/src/internet-node/wscript b/src/internet-node/wscript index 10b730016..7a1b1c10e 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -5,7 +5,7 @@ def build(bld): obj = bld.create_obj('cpp', 'shlib') obj.name = 'ns3-internet-node' obj.target = obj.name - obj.uselib_local = ['ns3-node', 'ns3-applications', 'ns3-routing'] + obj.uselib_local = ['ns3-node', 'ns3-applications'] obj.source = [ 'internet-node.cc', 'l3-demux.cc', diff --git a/src/routing/global/wscript b/src/routing/global/wscript index 130b633f2..787ef9308 100644 --- a/src/routing/global/wscript +++ b/src/routing/global/wscript @@ -1,12 +1,8 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-routing') - - def build(bld): module = bld.create_obj('cpp', 'shlib') - module.name = 'ns3-routing' + module.name = 'ns3-global-routing' module.target = module.name module.uselib_local = ['ns3-node'] module.source = [ @@ -15,10 +11,10 @@ def build(bld): 'global-route-manager-impl.cc', 'candidate-queue.cc', ] - headers = bld.create_obj('ns3header') headers.source = [ 'global-router-interface.h', 'global-route-manager.h', 'candidate-queue.h', ] + diff --git a/src/wscript b/src/wscript index 5f18019c9..aa57364be 100644 --- a/src/wscript +++ b/src/wscript @@ -18,7 +18,7 @@ all_modules = ( 'devices/point-to-point', 'devices/csma-cd', 'applications', - 'routing/global', + 'routing/global-routing', 'mobility', ) From 5de2add9c3488ba056b32c76e9ddbdd600c7abb4 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 3 Aug 2007 09:49:02 -0700 Subject: [PATCH 170/278] fix compilation problems and test --- examples/simple-global-routing.cc | 6 +++--- src/routing/{global => global-routing}/candidate-queue.cc | 0 src/routing/{global => global-routing}/candidate-queue.h | 0 .../{global => global-routing}/global-route-manager-impl.cc | 0 .../{global => global-routing}/global-route-manager-impl.h | 0 .../{global => global-routing}/global-route-manager.cc | 0 .../{global => global-routing}/global-route-manager.h | 0 .../{global => global-routing}/global-router-interface.cc | 0 .../{global => global-routing}/global-router-interface.h | 0 src/routing/{global => global-routing}/wscript | 0 10 files changed, 3 insertions(+), 3 deletions(-) rename src/routing/{global => global-routing}/candidate-queue.cc (100%) rename src/routing/{global => global-routing}/candidate-queue.h (100%) rename src/routing/{global => global-routing}/global-route-manager-impl.cc (100%) rename src/routing/{global => global-routing}/global-route-manager-impl.h (100%) rename src/routing/{global => global-routing}/global-route-manager.cc (100%) rename src/routing/{global => global-routing}/global-route-manager.h (100%) rename src/routing/{global => global-routing}/global-router-interface.cc (100%) rename src/routing/{global => global-routing}/global-router-interface.h (100%) rename src/routing/{global => global-routing}/wscript (100%) diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index d5038f389..2a005589a 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -56,14 +56,14 @@ #include "ns3/ascii-trace.h" #include "ns3/pcap-trace.h" #include "ns3/internet-node.h" -#include "ns3/p2p-channel.h" -#include "ns3/p2p-net-device.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" #include "ns3/mac-address.h" #include "ns3/ipv4-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" #include "ns3/ipv4-route.h" -#include "ns3/p2p-topology.h" +#include "ns3/point-to-point-topology.h" #include "ns3/onoff-application.h" #include "ns3/global-route-manager.h" diff --git a/src/routing/global/candidate-queue.cc b/src/routing/global-routing/candidate-queue.cc similarity index 100% rename from src/routing/global/candidate-queue.cc rename to src/routing/global-routing/candidate-queue.cc diff --git a/src/routing/global/candidate-queue.h b/src/routing/global-routing/candidate-queue.h similarity index 100% rename from src/routing/global/candidate-queue.h rename to src/routing/global-routing/candidate-queue.h diff --git a/src/routing/global/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc similarity index 100% rename from src/routing/global/global-route-manager-impl.cc rename to src/routing/global-routing/global-route-manager-impl.cc diff --git a/src/routing/global/global-route-manager-impl.h b/src/routing/global-routing/global-route-manager-impl.h similarity index 100% rename from src/routing/global/global-route-manager-impl.h rename to src/routing/global-routing/global-route-manager-impl.h diff --git a/src/routing/global/global-route-manager.cc b/src/routing/global-routing/global-route-manager.cc similarity index 100% rename from src/routing/global/global-route-manager.cc rename to src/routing/global-routing/global-route-manager.cc diff --git a/src/routing/global/global-route-manager.h b/src/routing/global-routing/global-route-manager.h similarity index 100% rename from src/routing/global/global-route-manager.h rename to src/routing/global-routing/global-route-manager.h diff --git a/src/routing/global/global-router-interface.cc b/src/routing/global-routing/global-router-interface.cc similarity index 100% rename from src/routing/global/global-router-interface.cc rename to src/routing/global-routing/global-router-interface.cc diff --git a/src/routing/global/global-router-interface.h b/src/routing/global-routing/global-router-interface.h similarity index 100% rename from src/routing/global/global-router-interface.h rename to src/routing/global-routing/global-router-interface.h diff --git a/src/routing/global/wscript b/src/routing/global-routing/wscript similarity index 100% rename from src/routing/global/wscript rename to src/routing/global-routing/wscript From b080a339a6b5efd3589a9e02615209464141db62 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 3 Aug 2007 21:39:19 -0700 Subject: [PATCH 171/278] remove README.routing file --- README.routing | 133 ------------------------------------------------- 1 file changed, 133 deletions(-) delete mode 100644 README.routing diff --git a/README.routing b/README.routing deleted file mode 100644 index f787371be..000000000 --- a/README.routing +++ /dev/null @@ -1,133 +0,0 @@ -Static routing overview ---------------- - -This is brief documentation of a proposal to add global static routing to ns-3 -Static routing is used to automatically populate the forwarding tables -in a topology without running a dynamic routing protocol or asking -the user to manually enter routes themselves. - -The previously announced roadmap: -* July 15: Support IPv4 static routing with PointToPoint numbered links -* August 15: Extend IPv4 static routing to Ethernet (shared links), -add static multicast forwarding over Ethernet and PointToPoint -* Sept 15: Add static multicast forwarding over wireless interface - -This code would provide the first bullet above. - -Note: This is orthogonal to Gustavo's OLSR code, but could also exist -as a static routing protocol in the framework that he proposes; right now, -this code just writes directly into the existing Ipv4 routing API - -1. Code: - -- source code is in a routing module src/routing/ -- an example script is in examples/simple-static-routing.cc. It produces the -same output as simple-p2p.cc -- StaticRouteManager is added in the run-tests unit tests - -2. API: - -The public API is very minimal. - -- user scripts include the following: -#include "ns3/routing-environment.h" -#include "ns3/static-route-manager.h" - -- A single default value (default false) enables static routing - Bind ("DoStaticRouting", "true"); - -- The call to build the static routes themselves is a single method, -called after the topology has been addressed: - - if (RoutingEnvironment::StaticRoutingEnabled ()) - { - StaticRouteManager::PopulateRoutingTables (); - } - -3. Approach: - -A singleton object (StaticRouteManager) is responsible for populating -the static routes on each node, using the public Ipv4 API of that node. -It queries each node in the topology for a "staticRouter" interface. -If found, it uses the API of that interface to obtain a "link state -advertisement (LSA)" for the router. Link State Advertisements -are used in OSPF routing, and we follow their formatting. - -The StaticRouteManager populates a link state database with LSAs -gathered from the entire topology. Then, for each router in the topology, -the StaticRouteManager executes the OSPF shortest path first (SPF) -computation on the database, and populates the routing tables on each -node. - -The quagga (http://www.quagga.net) OSPF implementation was used as the -basis for the routing computation logic. -One benefit of following an existing OSPF SPF implementation is that -OSPF already has defined link state advertisements for all common -types of network links: -- point-to-point (serial links) -- point-to-multipoint (Frame Relay, ad hoc wireless) -- non-broadcast multiple access (ATM) -- broadcast (Ethernet) -Therefore, we think that enabling these other link types will be more -straightforward now that the underlying OSPF SPF framework is in place. - -Presently, we can handle IPv4 point-to-point, numbered links, and we do -not do equal-cost multipath. We also do not allow for non-unit-cost -links, although it should be trivially extensible to do so. - -The support for this relies on the node object supporting a StaticRouter -interface. This can be manually added to each node, or alternatively, -we have modified InternetNode::Construct() as follows: - if (RoutingEnvironment::StaticRoutingEnabled()) - { - Ptr staticRouter = Create (this); - Object::AddInterface (staticRouter); - } - -4. Some open issues - -- trying to enable this with the default value framework raised some -questions. Access to an underlying default variable is required -across compilation units. The routing environment was designed -to put everything in one compilation unit. Whether this is good -practice or just overly paranoid is for further discussion. An -alternative may be to define some kind of test with the same default -value system such as -if (IsBound("DoStaticRouting", "true")) ... - -- along the same lines, Bind() is kind of an oddball in the present -system. We do NodeList::Begin (), Simulator::Run (), -CommandLine::Parse (); but simply Bind (). This isn't very consistent. - -(note: the choice of "bind()" was due to ns-2's methods of the same name) - -Perhaps it would be better to do something like, - -Configurator::Set ("DoStaticRouting", "true"); - -if (Configurator::IsEqual ("DoStaticRouting", "true")) - { - } - -- how transparent vs. explicit the enabling of static routing should be -(e.g., if we have a higher layer Inversion-of-Control framework, do these -static routing functions exist in some kind of Init() or Presimulate() -method?). Presently, it is explicitly enabled. - -- whether to add some kind of flag in an InternetNode that is equivalent -to /proc/sys/net/ipv4/ip_forward , so that every InternetNode is not -necessarily a router. - -- whether to continue to write to the existing IPv4 API or load a static -router component into the node such as Gustavo's OLSR code does - -- what to name this. Gustavo had suggestions to pick another name for -the StaticRouteManager. One possibility I would be fine with is to call -it GlobalRouteManager (although I would still argue it adds static routes -into the nodes in any case). - -- this method probably belongs in the Ipv4 (find InterfaceId corresponding -to the provided address) - uint32_t -StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) - From 6e956f6cc3c84fcb4735cd41447b8549a0647d98 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 09:31:52 +0200 Subject: [PATCH 172/278] add Buffer::CreateFullCopy and make TransformInto private --- src/common/buffer.cc | 14 +++++++++++--- src/common/buffer.h | 3 ++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/common/buffer.cc b/src/common/buffer.cc index ef48b3704..196bb4889 100644 --- a/src/common/buffer.cc +++ b/src/common/buffer.cc @@ -410,8 +410,8 @@ Buffer::CreateFragment (uint32_t start, uint32_t length) const return tmp; } -void -Buffer::TransformIntoRealBuffer (void) const +Buffer +Buffer::CreateFullCopy (void) const { if (m_zeroAreaSize != 0) { @@ -428,8 +428,16 @@ Buffer::TransformIntoRealBuffer (void) const Buffer::Iterator i = tmp.End (); i.Prev (dataEnd); i.Write (m_data->m_data+m_data->m_initialStart,dataEnd); - *const_cast (this) = tmp; + return tmp; } + return *this; +} + +void +Buffer::TransformIntoRealBuffer (void) const +{ + Buffer tmp = CreateFullCopy (); + *const_cast (this) = tmp; } diff --git a/src/common/buffer.h b/src/common/buffer.h index d591bad72..229a040fd 100644 --- a/src/common/buffer.h +++ b/src/common/buffer.h @@ -320,7 +320,7 @@ public: */ inline Buffer::Iterator End (void) const; - void TransformIntoRealBuffer (void) const; + Buffer CreateFullCopy (void) const; inline Buffer (Buffer const &o); inline Buffer &operator = (Buffer const &o); @@ -343,6 +343,7 @@ private: }; inline uint8_t *GetStart (void) const; + void TransformIntoRealBuffer (void) const; static void Recycle (struct Buffer::BufferData *data); static struct Buffer::BufferData *Create (void); static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start); From 692946450092b0ab677a51f1a4f1a1b37146f8b3 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 09:32:10 +0200 Subject: [PATCH 173/278] use CreateFullCopy and implement Serialize/Deserialize --- src/common/packet.cc | 41 +++++++++++++++++++++++++++++++++++------ src/common/packet.h | 3 +++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/common/packet.cc b/src/common/packet.cc index 8f989f8f3..7c9f51b5b 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -74,14 +74,14 @@ Packet::GetSize (void) const void Packet::AddAtEnd (Packet packet) { - packet.m_buffer.TransformIntoRealBuffer (); - m_buffer.TransformIntoRealBuffer (); + Buffer src = packet.m_buffer.CreateFullCopy (); + Buffer dst = m_buffer.CreateFullCopy (); - Buffer src = packet.m_buffer; - m_buffer.AddAtEnd (src.GetSize ()); - Buffer::Iterator destStart = m_buffer.End (); + dst.AddAtEnd (src.GetSize ()); + Buffer::Iterator destStart = dst.End (); destStart.Prev (src.GetSize ()); destStart.Write (src.Begin (), src.End ()); + m_buffer = dst; /** * XXX: we might need to merge the tag list of the * other packet into the current packet. @@ -143,7 +143,36 @@ Packet::EnableMetadata (void) PacketMetadata::Enable (); } -}; // namespace ns3 +Buffer +Packet::Serialize (void) +{ + Buffer buffer = m_buffer.CreateFullCopy (); + buffer.AddAtStart (4); + buffer.Begin ().WriteU32 (m_buffer.GetSize ()); + uint32_t tagsSize = m_tags.GetSerializedSize (); + buffer.AddAtEnd (tagsSize); + Buffer::Iterator tagStart = buffer.End (); + tagStart.Prev (tagsSize); + m_tags.Serialize (tagStart, tagsSize); + // serialize metadata. + return buffer; +} +void +Packet::Deserialize (Buffer buffer) +{ + Buffer buf = buffer; + uint32_t packetSize = buf.Begin ().ReadU32 (); + buf.RemoveAtStart (4); + buf.RemoveAtEnd (buffer.GetSize () - packetSize); + m_buffer = buf; + buffer.RemoveAtStart (4 + packetSize); + uint32_t deserialized = m_tags.Deserialize (buffer.Begin ()); + buffer.RemoveAtStart (deserialized); + // deserialize metadata. +} + + +} // namespace ns3 diff --git a/src/common/packet.h b/src/common/packet.h index 93e62f4cf..03400ca03 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -280,6 +280,9 @@ public: * errors will be detected and will abort the program. */ static void EnableMetadata (void); + + Buffer Serialize (void); + void Deserialize (Buffer buffer); private: Packet (Buffer buffer, Tags tags, PacketMetadata metadata); Buffer m_buffer; From cb6943010adcbbf0c90cae53edfa3251aff039e4 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 10:05:51 +0200 Subject: [PATCH 174/278] remove dead forward declaration --- src/common/packet-printer.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/common/packet-printer.h b/src/common/packet-printer.h index c79be0a3b..0c2873785 100644 --- a/src/common/packet-printer.h +++ b/src/common/packet-printer.h @@ -26,10 +26,6 @@ #include "buffer.h" #include -namespace { - class ItemList; -} - namespace ns3 { class Chunk; From 6a1e38d831a683cd211cb1a570f2b64345aaa413 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 13:21:55 +0200 Subject: [PATCH 175/278] forgot to use std::string instead of const char * --- src/internet-node/ipv4-header.cc | 2 +- src/internet-node/ipv4-header.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index 60ed939c2..813d8556a 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -30,7 +30,7 @@ namespace ns3 { bool Ipv4Header::m_calcChecksum = false; -const char * +std::string Ipv4Header::GetUid (void) { return "Ipv4Header.ns3"; diff --git a/src/internet-node/ipv4-header.h b/src/internet-node/ipv4-header.h index 3d9a9b449..b0e6e1868 100644 --- a/src/internet-node/ipv4-header.h +++ b/src/internet-node/ipv4-header.h @@ -32,7 +32,7 @@ namespace ns3 { class Ipv4Header : public Header { public: - static const char *GetUid (void); + static std::string GetUid (void); /** * \brief Construct a null IPv4 header */ From a454a51939a39963f9b07d38f32fa1d08cc3ab84 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 13:22:08 +0200 Subject: [PATCH 176/278] rework the PacketPrinter API and implementation --- samples/main-packet-printer.cc | 17 +-- src/common/chunk-registry.cc | 89 ++++++++++++ src/common/chunk-registry.h | 177 +++++++++++++++++++++++ src/common/packet-metadata-test.cc | 17 +-- src/common/packet-metadata.cc | 10 +- src/common/packet-metadata.h | 9 +- src/common/packet-printer.cc | 151 ++++---------------- src/common/packet-printer.h | 217 +++++------------------------ src/common/packet.cc | 2 +- src/common/wscript | 2 + 10 files changed, 342 insertions(+), 349 deletions(-) create mode 100644 src/common/chunk-registry.cc create mode 100644 src/common/chunk-registry.h diff --git a/samples/main-packet-printer.cc b/samples/main-packet-printer.cc index 771ae83b8..c840a13f0 100644 --- a/samples/main-packet-printer.cc +++ b/samples/main-packet-printer.cc @@ -90,15 +90,6 @@ void DefaultPrint (void) std::cout << std::endl; } -// The below functions are used in place of default versions, in the -// non-default case below. For instance, DoPrintIpv4Header will print -// out less IPv4 header information than the default print function -void -DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size, - std::string &name, struct PacketPrinter::FragmentInformation info) -{ - os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")"; -} void DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size, struct PacketPrinter::FragmentInformation info) @@ -129,14 +120,10 @@ void NonDefaultPrint (void) // set a string separator automatically inserted // between each call to a printing function. printer.SetSeparator (" - "); - // set the default print function: invoked if no - // specialized function has been provided for a header - // or trailer - printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault)); // set the payload print function - printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload)); + printer.SetPayloadPrinter (MakeCallback (&DoPrintPayload)); // set the print function for the header type Ipv4Header. - printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header), + printer.SetHeaderPrinter (MakeCallback (&DoPrintIpv4Header), MakeCallback (&DoPrintIpv4HeaderFragment)); diff --git a/src/common/chunk-registry.cc b/src/common/chunk-registry.cc new file mode 100644 index 000000000..076e4d3f5 --- /dev/null +++ b/src/common/chunk-registry.cc @@ -0,0 +1,89 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "chunk-registry.h" + +namespace ns3 { + +ChunkRegistry::InfoVector * +ChunkRegistry::GetInfoVector (void) +{ + static InfoVector vec; + return &vec; +} + +uint8_t * +ChunkRegistry::GetStaticInstance (uint32_t uid) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.getStaticInstance (); +} +bool +ChunkRegistry::IsHeader (uint32_t uid) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.isHeader; +} +bool +ChunkRegistry::IsTrailer (uint32_t uid) +{ + return !IsHeader (uid); +} +uint32_t +ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.deserialize (instance, i); +} +void +ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.print (instance, os); +} +std::string +ChunkRegistry::GetName (uint32_t uid, uint8_t *instance) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.getName (instance); +} +void +ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + info.invokePrintCallback (instance, os, packetUid, size, callback); +} + + +} // namespace ns3 diff --git a/src/common/chunk-registry.h b/src/common/chunk-registry.h new file mode 100644 index 000000000..56705aaea --- /dev/null +++ b/src/common/chunk-registry.h @@ -0,0 +1,177 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef CHUNK_REGISTRY_H +#define CHUNK_REGISTRY_H + +#include "buffer.h" +#include "ns3/ptr.h" +#include "ns3/callback.h" +#include + +namespace ns3 { + +/** + * \brief this registry keeps track of all different + * types of headers and trailers and assigns to each of them + * a unique integer. + * \internal + */ +class ChunkRegistry +{ +public: + template + static uint32_t GetHeaderUid (void); + template + static uint32_t GetTrailerUid (void); + + static uint8_t *GetStaticInstance (uint32_t uid); + static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i); + static void Print (uint32_t uid, uint8_t *instance, std::ostream &os); + static std::string GetName (uint32_t uid, uint8_t *instance); + static bool IsHeader (uint32_t uid); + static bool IsTrailer (uint32_t uid); + static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback); +private: + typedef uint8_t *(*GetStaticInstanceCb) (void); + typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator); + typedef void (*PrintCb) (uint8_t *,std::ostream &); + typedef std::string (*GetNameCb) (uint8_t *); + typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback); + struct Info { + std::string uidString; + bool isHeader; + GetStaticInstanceCb getStaticInstance; + DeserializeCb deserialize; + PrintCb print; + GetNameCb getName; + InvokePrintCallbackCb invokePrintCallback; + }; + typedef std::vector InfoVector; + static InfoVector *GetInfoVector (void); + template + static uint8_t *DoGetStaticInstance (void); + template + static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i); + template + static void DoPrint (uint8_t *instance, std::ostream &os); + template + static std::string DoGetName (uint8_t *instance); + template + static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback); + template + static uint32_t GetUid (bool isHeader); + +}; + +} // namespace ns3 + +namespace ns3 { + +template +uint32_t +ChunkRegistry::GetHeaderUid (void) +{ + return GetUid (true); +} +template +uint32_t +ChunkRegistry::GetTrailerUid (void) +{ + return GetUid (false); +} + +template +uint32_t +ChunkRegistry::GetUid (bool isHeader) +{ + InfoVector *vec = GetInfoVector (); + uint32_t uid = 1; + for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == T::GetUid ()) + { + return uid; + } + uid++; + } + Info info; + info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance; + info.print = &ChunkRegistry::DoPrint; + info.getName = &ChunkRegistry::DoGetName; + info.deserialize = &ChunkRegistry::DoDeserialize; + info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback; + info.uidString = T::GetUid (); + info.isHeader = isHeader; + vec->push_back (info); + return vec->size (); +} + +template +uint8_t * +ChunkRegistry::DoGetStaticInstance () +{ + static T instance; + return reinterpret_cast (&instance); +} +template +uint32_t +ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i) +{ + T *obj = reinterpret_cast (instance); + return obj->Deserialize (i); +} +template +void +ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os) +{ + T *obj = reinterpret_cast (instance); + obj->Print (os); +} +template +std::string +ChunkRegistry::DoGetName (uint8_t *instance) +{ + T *obj = reinterpret_cast (instance); + return obj->GetName (); +} +template +void +ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback) +{ + T *obj = reinterpret_cast (instance); + Callback cb; + cb.Assign (callback); + cb (os, packetUid, size, obj); +} + + + +} // namespace ns3 + +#endif /* CHUNK_REGISTRY_H */ diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index 9cd7d4c60..ad7ba39b1 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -207,9 +207,6 @@ private: void PrintFragment (std::ostream &os,uint32_t packetUid, uint32_t size,std::string & name, struct PacketPrinter::FragmentInformation info); - void PrintDefault (std::ostream& os,uint32_t packetUid, - uint32_t size,std::string& name, - struct PacketPrinter::FragmentInformation info); void PrintPayload (std::ostream &os,uint32_t packetUid, uint32_t size, struct PacketPrinter::FragmentInformation info); @@ -230,8 +227,7 @@ private: PacketMetadataTest::PacketMetadataTest () : Test ("PacketMetadata") { - m_printer.AddPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this)); - m_printer.AddDefaultPrinter (MakeCallback (&PacketMetadataTest::PrintDefault, this)); + m_printer.SetPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this)); } PacketMetadataTest::~PacketMetadataTest () @@ -244,7 +240,7 @@ PacketMetadataTest::RegisterHeader (void) static bool registered = false; if (!registered) { - m_printer.AddHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader, this), + m_printer.SetHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader, this), MakeCallback (&PacketMetadataTest::PrintFragment, this)); registered = true; } @@ -257,7 +253,7 @@ PacketMetadataTest::RegisterTrailer (void) static bool registered = false; if (!registered) { - m_printer.AddTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer, this), + m_printer.SetTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer, this), MakeCallback (&PacketMetadataTest::PrintFragment, this)); registered = true; } @@ -295,13 +291,6 @@ PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid, m_prints.push_back (size - (info.end + info.start)); } void -PacketMetadataTest::PrintDefault (std::ostream& os,uint32_t packetUid, - uint32_t size,std::string& name, - struct PacketPrinter::FragmentInformation info) -{ - NS_ASSERT (false); -} -void PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid, uint32_t size, struct PacketPrinter::FragmentInformation info) diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 1bb29ca00..99749cc8c 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -964,12 +964,6 @@ PacketMetadata::RemoveAtEnd (uint32_t end) NS_ASSERT (leftToRemove == 0); } -void -PacketMetadata::PrintDefault (std::ostream &os, Buffer buffer) const -{ - Print (os, buffer, PacketPrinter::GetDefault ()); -} - uint32_t PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item, const struct PacketMetadata::ExtraItem *extraItem, @@ -991,13 +985,13 @@ PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item, extraItem->fragmentStart, item->size - extraItem->fragmentEnd); } - else if (PacketPrinter::IsHeader (uid)) + else if (ChunkRegistry::IsHeader (uid)) { ns3::Buffer::Iterator j = data.Begin (); j.Next (offset); printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size); } - else if (PacketPrinter::IsTrailer (uid)) + else if (ChunkRegistry::IsTrailer (uid)) { ns3::Buffer::Iterator j = data.End (); j.Prev (data.GetSize () - (offset + item->size)); diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index 919f35e42..e7944dfac 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -100,7 +100,6 @@ public: uint32_t GetUid (void) const; - void PrintDefault (std::ostream &os, Buffer buffer) const; void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const; static void PrintStats (void); @@ -254,26 +253,26 @@ template void PacketMetadata::AddHeader (T const &header, uint32_t size) { - DoAddHeader (PacketPrinter::GetHeaderUid () << 1, size); + DoAddHeader (ChunkRegistry::GetHeaderUid () << 1, size); } template void PacketMetadata::RemoveHeader (T const &header, uint32_t size) { - DoRemoveHeader (PacketPrinter::GetHeaderUid () << 1, size); + DoRemoveHeader (ChunkRegistry::GetHeaderUid () << 1, size); } template void PacketMetadata::AddTrailer (T const &trailer, uint32_t size) { - DoAddTrailer (PacketPrinter::GetTrailerUid () << 1, size); + DoAddTrailer (ChunkRegistry::GetTrailerUid () << 1, size); } template void PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size) { - DoRemoveTrailer (PacketPrinter::GetTrailerUid () << 1, size); + DoRemoveTrailer (ChunkRegistry::GetTrailerUid () << 1, size); } diff --git a/src/common/packet-printer.cc b/src/common/packet-printer.cc index b5a807d52..b0c55b359 100644 --- a/src/common/packet-printer.cc +++ b/src/common/packet-printer.cc @@ -44,44 +44,10 @@ PacketPrinter::SetSeparator (std::string separator) m_separator = separator; } void -PacketPrinter::AddPayloadPrinter (PayloadPrinter printer) +PacketPrinter::SetPayloadPrinter (PayloadPrinter printer) { m_payloadPrinter = printer; } -void -PacketPrinter::AddDefaultPrinter (DefaultPrinter printer) -{ - m_defaultPrinter = printer; -} - -PacketPrinter::RegisteredChunks * -PacketPrinter::GetRegisteredChunks (void) -{ - static RegisteredChunks registeredChunks; - return ®isteredChunks; -} - -PacketPrinter -PacketPrinter::GetDefault (void) -{ - return *(PacketPrinter::PeekDefault ()); -} -PacketPrinter * -PacketPrinter::PeekDefault (void) -{ - static PacketPrinter *tmp = PacketPrinter::CreateStaticDefault (); - return tmp; -} -PacketPrinter * -PacketPrinter::CreateStaticDefault (void) -{ - static PacketPrinter tmp; - tmp.PrintForward (); - tmp.AddPayloadPrinter (MakeCallback (&PacketPrinter::DoDefaultPrintPayload)); - tmp.SetSeparator (" "); - return &tmp; -} - void PacketPrinter::PrintChunk (uint32_t chunkUid, @@ -90,26 +56,22 @@ PacketPrinter::PrintChunk (uint32_t chunkUid, uint32_t packetUid, uint32_t size) const { - RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (chunkUid >= 1 && chunkUid <= registeredChunks->size ()); + uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid); + ChunkRegistry::Deserialize (chunkUid, instance, start); + for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++) { if (i->m_chunkUid == chunkUid) { - DoPrintCallback cb = (*registeredChunks)[chunkUid-1].printCallback; - cb (i->m_printer, start, os, packetUid, size); + ChunkRegistry::InvokePrintCallback (chunkUid, instance, os, packetUid, size, i->m_printer); return; } } - DoGetNameCallback cb = (*registeredChunks)[chunkUid-1].getNameCallback; - std::string name = cb (); - struct PacketPrinter::FragmentInformation info; - info.start = 0; - info.end = 0; - if (!m_defaultPrinter.IsNull ()) - { - m_defaultPrinter (os, packetUid, size, name, info); - } + // if the over did not override this type of chunk, + // we print something by default. + std::string name = ChunkRegistry::GetName (chunkUid, instance); + os << name; + ChunkRegistry::Print (chunkUid, instance, os); } void PacketPrinter::PrintChunkFragment (uint32_t chunkUid, @@ -119,10 +81,8 @@ PacketPrinter::PrintChunkFragment (uint32_t chunkUid, uint32_t fragmentStart, uint32_t fragmentEnd) const { - RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (chunkUid >= 1 && chunkUid <= registeredChunks->size ()); - DoGetNameCallback cb = (*registeredChunks)[chunkUid-1].getNameCallback; - std::string name = cb (); + uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid); + std::string name = ChunkRegistry::GetName (chunkUid, instance); struct PacketPrinter::FragmentInformation info; info.start = fragmentStart; info.end = fragmentEnd; @@ -130,14 +90,20 @@ PacketPrinter::PrintChunkFragment (uint32_t chunkUid, { if (i->m_chunkUid == chunkUid) { + i->m_fragmentPrinter (os, packetUid, size, name, info); return; } } - if (!m_defaultPrinter.IsNull ()) - { - m_defaultPrinter (os, packetUid, size, name, info); - } + // if the user did not override this type of chunk, + // we print something by default. + NS_ASSERT (info.start != 0 || info.end != 0); + os << name << " " + << "(" + << "length " << size - (info.end + info.start) << " " + << "trim_start " << info.start << " " + << "trim_end " << info.end + << ")"; } void PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size, @@ -149,15 +115,10 @@ PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size if (!m_payloadPrinter.IsNull ()) { m_payloadPrinter (os, packetUid, size, info); + return; } -} - -void -PacketPrinter::DoDefaultPrintPayload (std::ostream & os, - uint32_t packetUid, - uint32_t size, - struct PacketPrinter::FragmentInformation info) -{ + // if the user did not override the payload printer, + // we print something anyway. os << "DATA (" << "length " << size - (info.end + info.start); if (info.start != 0 || info.end != 0) @@ -167,69 +128,7 @@ PacketPrinter::DoDefaultPrintPayload (std::ostream & os, << "trim_end " << info.end; } os << ")"; -} -void -PacketPrinter::DoDefaultPrintDefault (std::ostream & os, - uint32_t packetUid, - uint32_t size, - std::string &name, - struct PacketPrinter::FragmentInformation info) -{ - NS_ASSERT_MSG (false, "This should never happen because we provide a printer for _all_ chunk types."); } -void -PacketPrinter::DoDefaultPrintFragment (std::ostream & os, - uint32_t packetUid, - uint32_t size, - std::string &name, - struct PacketPrinter::FragmentInformation info) -{ - NS_ASSERT (info.start != 0 || info.end != 0); - os << name << " " - << "(" - << "length " << size - (info.end + info.start) << " " - << "trim_start " << info.start << " " - << "trim_end " << info.end - << ")" - ; -} - -void -PacketPrinter::DoAddPrinter (uint32_t uid, - Ptr printer, - Callback fragmentPrinter) -{ - struct PacketPrinter::Printer p; - p.m_chunkUid = uid; - p.m_printer = printer; - p.m_fragmentPrinter = fragmentPrinter; - m_printerList.push_back (p); -} - -bool -PacketPrinter::IsTrailer (uint32_t uid) -{ - RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (uid >= 1 && uid <= registeredChunks->size ()); - bool isHeader = (*registeredChunks)[uid-1].isHeader; - return !isHeader; -} -bool -PacketPrinter::IsHeader (uint32_t uid) -{ - RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks (); - NS_ASSERT (uid >= 1 && uid <= registeredChunks->size ()); - bool isHeader = (*registeredChunks)[uid-1].isHeader; - return isHeader; -} - - - } // namespace ns3 diff --git a/src/common/packet-printer.h b/src/common/packet-printer.h index 0c2873785..632d0f6d6 100644 --- a/src/common/packet-printer.h +++ b/src/common/packet-printer.h @@ -24,12 +24,11 @@ #include "ns3/callback.h" #include "ns3/ptr.h" #include "buffer.h" +#include "chunk-registry.h" #include namespace ns3 { -class Chunk; - /** * \brief hold a list of print callbacks for packet headers and trailers * @@ -88,100 +87,38 @@ public: * Print the content of the packet backward. */ void PrintBackward (void); + /** + * \param separator the new separator + * + * The default separator is a single space character. + */ void SetSeparator (std::string separator); /** * \param printer printer for payload */ - void AddPayloadPrinter (PayloadPrinter printer); + void SetPayloadPrinter (PayloadPrinter printer); /** * \param printer printer for the specified chunk * \param fragmentPrinter printer for a fragment of the specified chunk * - * If the user has not specified a callback for a specific header present - * in a packet, the "default" callback is invoked. If no such callback - * was specified, nothing happens. + * If the user does not force a user-specific printing function through + * a call to SetHeaderPrinter, the default print output is generated. */ template - void AddHeaderPrinter (Callback printer, + void SetHeaderPrinter (Callback printer, ChunkFragmentPrinter fragmentPrinter); /** * \param printer printer for the specified chunk * \param fragmentPrinter printer for a fragment of the specified chunk * - * If the user has not specified a callback for a specific trailer present - * in a packet, the "default" callback is invoked. If no such callback - * was specified, nothing happens. + * If the user does not force a user-specific printing function through + * a call to SetTrailerPrinter, the default print output is generated. */ template - void AddTrailerPrinter (Callback printer, - ChunkFragmentPrinter fragmentPrinter); - /** - * \param printer printer for a chunk for which no callback was specified explicitely - */ - void AddDefaultPrinter (DefaultPrinter printer); - + void SetTrailerPrinter (Callback printer, + ChunkFragmentPrinter fragmentPrinter); private: friend class PacketMetadata; - typedef void (*DoPrintCallback) (Ptr, Buffer::Iterator, std::ostream &, - uint32_t, uint32_t); - typedef std::string (*DoGetNameCallback) (void); - struct Printer - { - uint32_t m_chunkUid; - Ptr m_printer; - Callback - m_fragmentPrinter; - }; - struct RegisteredChunk - { - DoPrintCallback printCallback; - DoGetNameCallback getNameCallback; - std::string uidString; - bool isHeader; - }; - typedef std::vector PrinterList; - typedef std::vector RegisteredChunks; - - - static PacketPrinter GetDefault (void); - static PacketPrinter *PeekDefault (void); - static PacketPrinter *CreateStaticDefault (void); - static void DoDefaultPrintPayload (std::ostream & os, - uint32_t packetUid, - uint32_t size, - struct PacketPrinter::FragmentInformation info); - static void DoDefaultPrintDefault (std::ostream & os, - uint32_t packetUid, - uint32_t size, - std::string &name, - struct PacketPrinter::FragmentInformation info); - template - static void DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk); - static void DoDefaultPrintFragment (std::ostream & os, - uint32_t packetUid, - uint32_t size, - std::string &name, - struct PacketPrinter::FragmentInformation info); - - template - static void DoPrint (Ptr callbackPrinter, - Buffer::Iterator i, - std::ostream &os, - uint32_t packetUid, - uint32_t size); - template - static std::string DoGetName (void); - template - static uint32_t GetTrailerUid (void); - template - static uint32_t GetHeaderUid (void); - template - static uint32_t AllocateUid (bool isHeader); - static RegisteredChunks *GetRegisteredChunks (void); - static bool IsTrailer (uint32_t uid); - static bool IsHeader (uint32_t uid); - - void PrintChunk (uint32_t uid, Buffer::Iterator i, std::ostream &os, @@ -195,16 +132,15 @@ private: uint32_t fragmentEnd) const; void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size, uint32_t fragmentStart, uint32_t fragmentEnd) const; - void DoAddPrinter (uint32_t uid, - Ptr printer, - Callback fragmentPrinter); - - static PacketPrinter m_defaultPacketPrinter; + struct Printer + { + uint32_t m_chunkUid; + Ptr m_printer; + Callback m_fragmentPrinter; + }; + typedef std::vector PrinterList; + PrinterList m_printerList; PayloadPrinter m_payloadPrinter; DefaultPrinter m_defaultPrinter; @@ -218,107 +154,28 @@ namespace ns3 { template void -PacketPrinter::AddHeaderPrinter (Callback printer, - Callback fragmentPrinter) +PacketPrinter::SetHeaderPrinter (Callback printer, + ChunkFragmentPrinter fragmentPrinter) { - static uint32_t uid = PacketPrinter::GetHeaderUid (); - DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter); + Printer p; + p.m_chunkUid = ChunkRegistry::GetHeaderUid (); + p.m_printer = printer.GetImpl (); + p.m_fragmentPrinter = fragmentPrinter; + m_printerList.push_back (p); } template void -PacketPrinter::AddTrailerPrinter (Callback printer, - Callback fragmentPrinter) +PacketPrinter::SetTrailerPrinter (Callback printer, + ChunkFragmentPrinter fragmentPrinter) { - static uint32_t uid = PacketPrinter::GetTrailerUid (); - DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter); + Printer p; + p.m_chunkUid = ChunkRegistry::GetTrailerUid (); + p.m_printer = printer.GetImpl (); + p.m_fragmentPrinter = fragmentPrinter; + m_printerList.push_back (p); } -template -void -PacketPrinter::DoPrint (Ptr printerCallback, - Buffer::Iterator i, - std::ostream &os, - uint32_t packetUid, - uint32_t size) -{ - T chunk = T (); - chunk.Deserialize (i); - Callback callback; - callback.Assign (printerCallback); - callback (os, packetUid, size, &chunk); -} - -template -std::string -PacketPrinter::DoGetName (void) -{ - T chunk = T (); - return chunk.GetName (); -} - -template -uint32_t -PacketPrinter::GetHeaderUid (void) -{ - static uint32_t uid = PacketPrinter::AllocateUid (true); - return uid; -} - -template -uint32_t -PacketPrinter::GetTrailerUid (void) -{ - static uint32_t uid = PacketPrinter::AllocateUid (false); - return uid; -} - -template -uint32_t -PacketPrinter::AllocateUid (bool isHeader) -{ - RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks (); - uint32_t j = 0; - for (RegisteredChunks::iterator i = chunks->begin (); i != chunks->end (); i++) - { - if (i->uidString == T::GetUid ()) - { - return j; - } - j++; - } - RegisteredChunk chunk; - chunk.printCallback = &PacketPrinter::DoPrint; - chunk.getNameCallback = &PacketPrinter::DoGetName; - chunk.isHeader = isHeader; - chunk.uidString = T::GetUid (); - chunks->push_back (chunk); - uint32_t uid = chunks->size (); - PacketPrinter::PeekDefault ()->DoAddPrinter (uid, - MakeCallback (&PacketPrinter::DoDefaultPrint).GetImpl (), - MakeCallback (&PacketPrinter::DoDefaultPrintFragment)); - return uid; -} - -template -void -PacketPrinter::DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk) -{ - os << chunk->GetName () << " "; - chunk->Print (os); -} - - } // namespace ns3 diff --git a/src/common/packet.cc b/src/common/packet.cc index 7c9f51b5b..965aef584 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -128,7 +128,7 @@ Packet::GetUid (void) const void Packet::Print (std::ostream &os) const { - m_metadata.PrintDefault (os, m_buffer); + m_metadata.Print (os, m_buffer, PacketPrinter ()); } void diff --git a/src/common/wscript b/src/common/wscript index c1165026a..ff8c7b60a 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -10,6 +10,7 @@ def build(bld): 'chunk.cc', 'header.cc', 'trailer.cc', + 'chunk-registry.cc', 'packet-printer.cc', 'packet-metadata.cc', 'packet-metadata-test.cc', @@ -35,6 +36,7 @@ def build(bld): 'tags.h', 'packet.h', 'packet-printer.h', + 'chunk-registry.h', 'packet-metadata.h', 'uv-trace-source.h', 'sv-trace-source.h', From 6db993b5898dbde9300c355bd4a105cf9407c55e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 13:28:17 +0200 Subject: [PATCH 177/278] add doxygen documentation, constify --- src/common/packet.cc | 2 +- src/common/packet.h | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/common/packet.cc b/src/common/packet.cc index 965aef584..5caacc09e 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -144,7 +144,7 @@ Packet::EnableMetadata (void) } Buffer -Packet::Serialize (void) +Packet::Serialize (void) const { Buffer buffer = m_buffer.CreateFullCopy (); buffer.AddAtStart (4); diff --git a/src/common/packet.h b/src/common/packet.h index 03400ca03..f4b0af11d 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -281,7 +281,30 @@ public: */ static void EnableMetadata (void); - Buffer Serialize (void); + /** + * \returns a byte buffer + * + * This method creates a serialized representation of a Packet object + * ready to be transmitted over a network to another system. This + * serialized representation contains a copy of the packet byte buffer, + * the tag list, and the packet metadata (if there is one). + * + * This method will typically be used by parallel simulations where + * the simulated system is partitioned and each partition runs on + * a different CPU. + */ + Buffer Serialize (void) const; + /** + * \param a byte buffer + * + * This method reads a byte buffer as created by Packet::Serialize + * and restores the state of the Packet to what it was prio to + * calling Serialize. + * + * This method will typically be used by parallel simulations where + * the simulated system is partitioned and each partition runs on + * a different CPU. + */ void Deserialize (Buffer buffer); private: Packet (Buffer buffer, Tags tags, PacketMetadata metadata); From aff09e3e34db71cfdb9dc2aabd1927b65adab15f Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 14:10:49 +0200 Subject: [PATCH 178/278] implement packet metadata serialization/deserialization --- src/common/chunk-registry.cc | 25 ++++++++ src/common/chunk-registry.h | 2 + src/common/packet-metadata.cc | 106 ++++++++++++++++++++++++++++++++++ src/common/packet-metadata.h | 4 ++ 4 files changed, 137 insertions(+) diff --git a/src/common/chunk-registry.cc b/src/common/chunk-registry.cc index 076e4d3f5..4010b3d77 100644 --- a/src/common/chunk-registry.cc +++ b/src/common/chunk-registry.cc @@ -29,6 +29,31 @@ ChunkRegistry::GetInfoVector (void) return &vec; } +std::string +ChunkRegistry::GetUidStringFromUid (uint32_t uid) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.uidString; +} +uint32_t +ChunkRegistry::GetUidFromUidString (std::string uidString) +{ + uint32_t uid = 1; + InfoVector *vec = GetInfoVector (); + for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == uidString) + { + return uid; + } + } + NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<< + "You could try calling NS_HEADER_ENSURE_REGISTER somewhere."); + return 0; +} + uint8_t * ChunkRegistry::GetStaticInstance (uint32_t uid) { diff --git a/src/common/chunk-registry.h b/src/common/chunk-registry.h index 56705aaea..ce94d1104 100644 --- a/src/common/chunk-registry.h +++ b/src/common/chunk-registry.h @@ -42,6 +42,8 @@ public: template static uint32_t GetTrailerUid (void); + static std::string GetUidStringFromUid (uint32_t uid); + static uint32_t GetUidFromUidString (std::string uidString); static uint8_t *GetStaticInstance (uint32_t uid); static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i); static void Print (uint32_t uid, uint8_t *instance, std::ostream &os); diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 99749cc8c..e949efdca 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -1087,5 +1087,111 @@ PacketMetadata::Print (std::ostream &os, Buffer data, const PacketPrinter &print } } +uint32_t +PacketMetadata::GetSerializedSize (void) const +{ + uint32_t totalSize = 0; + totalSize += 4; + if (!m_enable) + { + return totalSize; + } + struct PacketMetadata::SmallItem item; + struct PacketMetadata::ExtraItem extraItem; + uint32_t current = m_head; + while (current != 0xffff) + { + ReadItems (current, &item, &extraItem); + uint32_t uid = (item.typeUid & 0xfffffffe) >> 1; + totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size () + + 1 + 4 + 2 + 4 + 4 + 4; + if (current == m_tail) + { + break; + } + NS_ASSERT (current != item.next); + current = item.next; + } + return totalSize; +} +void +PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const +{ + uint32_t bytesWritten = 0; + i.WriteU32 (size); + bytesWritten += 4; + struct PacketMetadata::SmallItem item; + struct PacketMetadata::ExtraItem extraItem; + uint32_t current = m_head; + while (current != 0xffff) + { + ReadItems (current, &item, &extraItem); + uint32_t uid = (item.typeUid & 0xfffffffe) >> 1; + std::string uidString = ChunkRegistry::GetUidStringFromUid (uid); + i.WriteU32 (uidString.size ()); + bytesWritten += 4; + i.Write ((uint8_t *)uidString.c_str (), uidString.size ()); + bytesWritten += uidString.size (); + uint8_t isBig = item.typeUid & 0x1; + i.WriteU8 (isBig); + bytesWritten += 1; + i.WriteU32 (item.size); + bytesWritten += 4; + i.WriteU16 (item.chunkUid); + bytesWritten += 2; + i.WriteU32 (extraItem.fragmentStart); + bytesWritten += 4; + i.WriteU32 (extraItem.fragmentEnd); + bytesWritten += 4; + i.WriteU32 (extraItem.packetUid); + bytesWritten += 4; + if (current == m_tail) + { + break; + } + + NS_ASSERT (current != item.next); + current = item.next; + } + NS_ASSERT (bytesWritten == size); +} +uint32_t +PacketMetadata::Deserialize (Buffer::Iterator i) +{ + struct PacketMetadata::SmallItem item; + struct PacketMetadata::ExtraItem extraItem; + uint32_t size = i.ReadU32 (); + size -= 4; + while (size > 0) + { + uint32_t uidStringSize = i.ReadU32 (); + size -= 4; + std::string uidString; + for (uint32_t j = 0; j < uidStringSize; j++) + { + uidString.push_back (i.ReadU8 ()); + size --; + } + uint32_t uid = ChunkRegistry::GetUidFromUidString (uidString); + uint8_t isBig = i.ReadU8 (); + size --; + item.typeUid = (uid << 1) | isBig; + item.size = i.ReadU32 (); + size -= 4; + item.chunkUid = i.ReadU16 (); + size -= 2; + extraItem.fragmentStart = i.ReadU32 (); + size -= 4; + extraItem.fragmentEnd = i.ReadU32 (); + size -= 4; + extraItem.packetUid = i.ReadU32 (); + size -= 4; + uint32_t tmp = AddBig (0xffff, m_tail, &item, &extraItem); + UpdateTail (tmp); + } + return size; +} + + } // namespace ns3 diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index e7944dfac..0c98b2cf7 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -102,6 +102,10 @@ public: void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator i, uint32_t size) const; + uint32_t Deserialize (Buffer::Iterator i); + static void PrintStats (void); private: From d9a9624c6c6a14c7f32c0c9c3339e2941cf3689b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 14:41:33 +0200 Subject: [PATCH 179/278] finish packet serialization/deserialization --- src/common/packet.cc | 48 ++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/common/packet.cc b/src/common/packet.cc index 5caacc09e..cb0712187 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -146,29 +146,51 @@ Packet::EnableMetadata (void) Buffer Packet::Serialize (void) const { - Buffer buffer = m_buffer.CreateFullCopy (); - buffer.AddAtStart (4); - buffer.Begin ().WriteU32 (m_buffer.GetSize ()); - uint32_t tagsSize = m_tags.GetSerializedSize (); - buffer.AddAtEnd (tagsSize); - Buffer::Iterator tagStart = buffer.End (); - tagStart.Prev (tagsSize); - m_tags.Serialize (tagStart, tagsSize); - // serialize metadata. - return buffer; + Buffer buffer; + uint32_t reserve; + + // write metadata + reserve = m_metadata.GetSerializedSize (); + buffer.AddAtStart (reserve); + m_metadata.Serialize (buffer.Begin (), reserve); + + // write tags + reserve = m_tags.GetSerializedSize (); + buffer.AddAtStart (reserve); + m_tags.Serialize (buffer.Begin (), reserve); + + // aggregate byte buffer, metadata, and tags + Buffer tmp = m_buffer.CreateFullCopy (); + buffer.AddAtStart (tmp.GetSize ()); + buffer.Begin ().Write (tmp.Begin (), tmp.End ()); + + // write total size. + tmp.AddAtStart (4); + tmp.Begin ().WriteU32 (m_buffer.GetSize ()); + + return tmp; } void Packet::Deserialize (Buffer buffer) { Buffer buf = buffer; + // read size uint32_t packetSize = buf.Begin ().ReadU32 (); buf.RemoveAtStart (4); + + // read buffer. buf.RemoveAtEnd (buffer.GetSize () - packetSize); m_buffer = buf; + + // read tags buffer.RemoveAtStart (4 + packetSize); - uint32_t deserialized = m_tags.Deserialize (buffer.Begin ()); - buffer.RemoveAtStart (deserialized); - // deserialize metadata. + uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ()); + buffer.RemoveAtStart (tagsDeserialized); + + // read metadata + uint32_t metadataDeserialized = + m_metadata.Deserialize (buffer.Begin ()); + buffer.RemoveAtStart (metadataDeserialized); } From b2ddd93191e8a17fde8b16582ae45826c7386742 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 14:51:09 +0200 Subject: [PATCH 180/278] test Tags serialization/deserialization --- src/common/tags.cc | 70 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/src/common/tags.cc b/src/common/tags.cc index a58591422..0d78334f4 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -301,9 +301,9 @@ class myTagA public: static const char *GetUid (void) {return "myTagA.test.nsnam.org";} void Print (std::ostream &os) const {g_a = true;} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint32_t GetSerializedSize (void) const {return 1;} + void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);} + uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;} uint8_t a; }; @@ -312,9 +312,9 @@ class myTagB public: static const char *GetUid (void) {return "myTagB.test.nsnam.org";} void Print (std::ostream &os) const {g_b = true;} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint32_t GetSerializedSize (void) const {return 4;} + void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);} + uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;} uint32_t b; }; @@ -323,9 +323,9 @@ class myTagC public: static const char *GetUid (void) {return "myTagC.test.nsnam.org";} void Print (std::ostream &os) const {g_c = true;} - uint32_t GetSerializedSize (void) const {return 0;} - void Serialize (Buffer::Iterator i) const {} - uint32_t Deserialize (Buffer::Iterator i) {return 0;} + uint32_t GetSerializedSize (void) const {return Tags::SIZE;} + void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);} + uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;} uint8_t c [Tags::SIZE]; }; class myInvalidTag @@ -521,6 +521,58 @@ TagsTest::RunTests (void) tmp.Remove (smartTag); } + { + Tags source; + myTagA aSource; + aSource.a = 0x66; + source.Add (aSource); + Buffer buffer; + uint32_t serialized = source.GetSerializedSize (); + buffer.AddAtStart (serialized); + source.Serialize (buffer.Begin (), serialized); + Tags dest; + dest.Deserialize (buffer.Begin ()); + myTagA aDest; + aDest.a = 0x55; + dest.Peek (aDest); + if (aDest.a != 0x66) + { + ok = false; + } + } + + { + Tags source; + myTagA aSource; + aSource.a = 0x66; + source.Add (aSource); + myTagZ zSource; + zSource.z = 0x77; + source.Add (zSource); + + Buffer buffer; + uint32_t serialized = source.GetSerializedSize (); + buffer.AddAtStart (serialized); + source.Serialize (buffer.Begin (), serialized); + Tags dest; + dest.Deserialize (buffer.Begin ()); + + myTagA aDest; + aDest.a = 0x55; + dest.Peek (aDest); + if (aDest.a != 0x66) + { + ok = false; + } + myTagZ zDest; + zDest.z = 0x44; + dest.Peek (zDest); + if (zDest.z != 0x44) + { + ok = false; + } + } + return ok; } From fc7802ea0f28aa74da3b4843a7db73d064843c72 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:03:08 +0200 Subject: [PATCH 181/278] avoid fatal error if NS_DEBUG is used before the 'main' function is reached --- src/core/debug.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/core/debug.cc b/src/core/debug.cc index 181bb9622..3dfb998b5 100644 --- a/src/core/debug.cc +++ b/src/core/debug.cc @@ -54,6 +54,7 @@ DebugComponentEnableEnvVar (void) { return; } + bool allFound = true; std::string env = envVar; std::string::size_type cur = 0; std::string::size_type next = 0; @@ -89,7 +90,7 @@ DebugComponentEnableEnvVar (void) } if (!found) { - NS_FATAL_ERROR ("No debug component named=\"" << tmp << "\""); + allFound = false; } if (next == std::string::npos) { @@ -101,6 +102,11 @@ DebugComponentEnableEnvVar (void) break; } } + if (allFound) + { + g_firstDebug = true; + } + #endif } @@ -123,7 +129,6 @@ DebugComponent::IsEnabled (void) if (g_firstDebug) { DebugComponentEnableEnvVar (); - g_firstDebug = false; } return m_isEnabled; } From 7d5a47afe9009b1fb3b2e1a53be727dc8656aec7 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:06:38 +0200 Subject: [PATCH 182/278] make sure we return a correct uid from ChunkRegistry::GetUidFromUidString --- src/common/chunk-registry.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/chunk-registry.cc b/src/common/chunk-registry.cc index 4010b3d77..2732e4941 100644 --- a/src/common/chunk-registry.cc +++ b/src/common/chunk-registry.cc @@ -48,6 +48,7 @@ ChunkRegistry::GetUidFromUidString (std::string uidString) { return uid; } + uid++; } NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<< "You could try calling NS_HEADER_ENSURE_REGISTER somewhere."); From 25c33df302be53289005579cfecce8d1315f0bd2 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:06:59 +0200 Subject: [PATCH 183/278] test packet serialization/deserialization --- src/common/packet-metadata-test.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index ad7ba39b1..a56f6ef4a 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -416,6 +416,15 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t { \ ok = false; \ } \ + Buffer buffer; \ + buffer = p.Serialize (); \ + Packet otherPacket; \ + otherPacket.Deserialize (buffer); \ + if (!CheckHistory (otherPacket, __FILE__, \ + __LINE__, __VA_ARGS__)) \ + { \ + ok = false; \ + } \ } bool From 61c85465b93c4cd306b4b1fab24f194c7b295821 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:07:31 +0200 Subject: [PATCH 184/278] ci fix metadata serialization/deserialization --- src/common/packet-metadata.cc | 62 +++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index e949efdca..6acbd2930 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -1103,8 +1103,15 @@ PacketMetadata::GetSerializedSize (void) const { ReadItems (current, &item, &extraItem); uint32_t uid = (item.typeUid & 0xfffffffe) >> 1; - totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size () + - 1 + 4 + 2 + 4 + 4 + 4; + if (uid == 0) + { + totalSize += 4; + } + else + { + totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size (); + } + totalSize += 1 + 4 + 2 + 4 + 4 + 4; if (current == m_tail) { break; @@ -1126,12 +1133,24 @@ PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const while (current != 0xffff) { ReadItems (current, &item, &extraItem); + NS_DEBUG ("bytesWritten=" << bytesWritten << ", typeUid="< ("MyHeader.test.nsnam.org"); + return uid; } std::string diff --git a/src/common/chunk-registry.cc b/src/common/chunk-registry.cc deleted file mode 100644 index 2732e4941..000000000 --- a/src/common/chunk-registry.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ -#include "chunk-registry.h" - -namespace ns3 { - -ChunkRegistry::InfoVector * -ChunkRegistry::GetInfoVector (void) -{ - static InfoVector vec; - return &vec; -} - -std::string -ChunkRegistry::GetUidStringFromUid (uint32_t uid) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - return info.uidString; -} -uint32_t -ChunkRegistry::GetUidFromUidString (std::string uidString) -{ - uint32_t uid = 1; - InfoVector *vec = GetInfoVector (); - for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) - { - if (i->uidString == uidString) - { - return uid; - } - uid++; - } - NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<< - "You could try calling NS_HEADER_ENSURE_REGISTER somewhere."); - return 0; -} - -uint8_t * -ChunkRegistry::GetStaticInstance (uint32_t uid) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - return info.getStaticInstance (); -} -bool -ChunkRegistry::IsHeader (uint32_t uid) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - return info.isHeader; -} -bool -ChunkRegistry::IsTrailer (uint32_t uid) -{ - return !IsHeader (uid); -} -uint32_t -ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - return info.deserialize (instance, i); -} -void -ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - return info.print (instance, os); -} -std::string -ChunkRegistry::GetName (uint32_t uid, uint8_t *instance) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - return info.getName (instance); -} -void -ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os, - uint32_t packetUid, uint32_t size, - Ptr callback) -{ - InfoVector *vec = GetInfoVector (); - NS_ASSERT (uid >= 1 && uid <= vec->size ()); - Info info = (*vec)[uid - 1]; - info.invokePrintCallback (instance, os, packetUid, size, callback); -} - - -} // namespace ns3 diff --git a/src/common/chunk-registry.h b/src/common/chunk-registry.h deleted file mode 100644 index ce94d1104..000000000 --- a/src/common/chunk-registry.h +++ /dev/null @@ -1,179 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ -#ifndef CHUNK_REGISTRY_H -#define CHUNK_REGISTRY_H - -#include "buffer.h" -#include "ns3/ptr.h" -#include "ns3/callback.h" -#include - -namespace ns3 { - -/** - * \brief this registry keeps track of all different - * types of headers and trailers and assigns to each of them - * a unique integer. - * \internal - */ -class ChunkRegistry -{ -public: - template - static uint32_t GetHeaderUid (void); - template - static uint32_t GetTrailerUid (void); - - static std::string GetUidStringFromUid (uint32_t uid); - static uint32_t GetUidFromUidString (std::string uidString); - static uint8_t *GetStaticInstance (uint32_t uid); - static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i); - static void Print (uint32_t uid, uint8_t *instance, std::ostream &os); - static std::string GetName (uint32_t uid, uint8_t *instance); - static bool IsHeader (uint32_t uid); - static bool IsTrailer (uint32_t uid); - static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os, - uint32_t packetUid, uint32_t size, - Ptr callback); -private: - typedef uint8_t *(*GetStaticInstanceCb) (void); - typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator); - typedef void (*PrintCb) (uint8_t *,std::ostream &); - typedef std::string (*GetNameCb) (uint8_t *); - typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os, - uint32_t packetUid, uint32_t size, - Ptr callback); - struct Info { - std::string uidString; - bool isHeader; - GetStaticInstanceCb getStaticInstance; - DeserializeCb deserialize; - PrintCb print; - GetNameCb getName; - InvokePrintCallbackCb invokePrintCallback; - }; - typedef std::vector InfoVector; - static InfoVector *GetInfoVector (void); - template - static uint8_t *DoGetStaticInstance (void); - template - static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i); - template - static void DoPrint (uint8_t *instance, std::ostream &os); - template - static std::string DoGetName (uint8_t *instance); - template - static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os, - uint32_t packetUid, uint32_t size, - Ptr callback); - template - static uint32_t GetUid (bool isHeader); - -}; - -} // namespace ns3 - -namespace ns3 { - -template -uint32_t -ChunkRegistry::GetHeaderUid (void) -{ - return GetUid (true); -} -template -uint32_t -ChunkRegistry::GetTrailerUid (void) -{ - return GetUid (false); -} - -template -uint32_t -ChunkRegistry::GetUid (bool isHeader) -{ - InfoVector *vec = GetInfoVector (); - uint32_t uid = 1; - for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) - { - if (i->uidString == T::GetUid ()) - { - return uid; - } - uid++; - } - Info info; - info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance; - info.print = &ChunkRegistry::DoPrint; - info.getName = &ChunkRegistry::DoGetName; - info.deserialize = &ChunkRegistry::DoDeserialize; - info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback; - info.uidString = T::GetUid (); - info.isHeader = isHeader; - vec->push_back (info); - return vec->size (); -} - -template -uint8_t * -ChunkRegistry::DoGetStaticInstance () -{ - static T instance; - return reinterpret_cast (&instance); -} -template -uint32_t -ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i) -{ - T *obj = reinterpret_cast (instance); - return obj->Deserialize (i); -} -template -void -ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os) -{ - T *obj = reinterpret_cast (instance); - obj->Print (os); -} -template -std::string -ChunkRegistry::DoGetName (uint8_t *instance) -{ - T *obj = reinterpret_cast (instance); - return obj->GetName (); -} -template -void -ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os, - uint32_t packetUid, uint32_t size, - Ptr callback) -{ - T *obj = reinterpret_cast (instance); - Callback cb; - cb.Assign (callback); - cb (os, packetUid, size, obj); -} - - - -} // namespace ns3 - -#endif /* CHUNK_REGISTRY_H */ diff --git a/src/common/chunk.cc b/src/common/chunk.cc index 52c1112c3..e582d884b 100644 --- a/src/common/chunk.cc +++ b/src/common/chunk.cc @@ -62,4 +62,100 @@ std::ostream& operator<< (std::ostream& os, Chunk const& chunk) return os; } -}; // namespace ns3 + +/************************************** + * The Chunk Registry below + ***************************************/ + + +ChunkRegistry::InfoVector * +ChunkRegistry::GetInfoVector (void) +{ + static InfoVector vec; + return &vec; +} + +std::string +ChunkRegistry::GetUidStringFromUid (uint32_t uid) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.uidString; +} +uint32_t +ChunkRegistry::GetUidFromUidString (std::string uidString) +{ + uint32_t uid = 1; + InfoVector *vec = GetInfoVector (); + for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == uidString) + { + return uid; + } + uid++; + } + NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<< + "You could try calling NS_HEADER_ENSURE_REGISTER somewhere."); + return 0; +} + +uint8_t * +ChunkRegistry::GetStaticInstance (uint32_t uid) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.getStaticInstance (); +} +bool +ChunkRegistry::IsHeader (uint32_t uid) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.isHeader; +} +bool +ChunkRegistry::IsTrailer (uint32_t uid) +{ + return !IsHeader (uid); +} +uint32_t +ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.deserialize (instance, i); +} +void +ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.print (instance, os); +} +std::string +ChunkRegistry::GetName (uint32_t uid, uint8_t *instance) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + return info.getName (instance); +} +void +ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback) +{ + InfoVector *vec = GetInfoVector (); + NS_ASSERT (uid >= 1 && uid <= vec->size ()); + Info info = (*vec)[uid - 1]; + info.invokePrintCallback (instance, os, packetUid, size, callback); +} + + +} // namespace ns3 diff --git a/src/common/chunk.h b/src/common/chunk.h index ab568cd9f..193cb2bba 100644 --- a/src/common/chunk.h +++ b/src/common/chunk.h @@ -25,6 +25,8 @@ #include #include #include "buffer.h" +#include "ns3/ptr.h" +#include "ns3/callback.h" namespace ns3 { @@ -48,6 +50,151 @@ private: std::ostream& operator<< (std::ostream& os, Chunk const& chunk); -}; // namespace ns3 +/** + * \brief this registry keeps track of all different + * types of headers and trailers and assigns to each of them + * a unique integer. + * \internal + */ +class ChunkRegistry +{ +public: + template + static uint32_t RegisterHeader (std::string uuid); + template + static uint32_t RegisterTrailer (std::string uuid); + + static std::string GetUidStringFromUid (uint32_t uid); + static uint32_t GetUidFromUidString (std::string uidString); + static uint8_t *GetStaticInstance (uint32_t uid); + static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i); + static void Print (uint32_t uid, uint8_t *instance, std::ostream &os); + static std::string GetName (uint32_t uid, uint8_t *instance); + static bool IsHeader (uint32_t uid); + static bool IsTrailer (uint32_t uid); + static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback); +private: + typedef uint8_t *(*GetStaticInstanceCb) (void); + typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator); + typedef void (*PrintCb) (uint8_t *,std::ostream &); + typedef std::string (*GetNameCb) (uint8_t *); + typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback); + struct Info { + std::string uidString; + bool isHeader; + GetStaticInstanceCb getStaticInstance; + DeserializeCb deserialize; + PrintCb print; + GetNameCb getName; + InvokePrintCallbackCb invokePrintCallback; + }; + typedef std::vector InfoVector; + static InfoVector *GetInfoVector (void); + template + static uint8_t *DoGetStaticInstance (void); + template + static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i); + template + static void DoPrint (uint8_t *instance, std::ostream &os); + template + static std::string DoGetName (uint8_t *instance); + template + static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback); + template + static uint32_t GetUid (bool isHeader, std::string uidString); + +}; + + +} // namespace ns3 + +namespace ns3 { + +template +uint32_t +ChunkRegistry::RegisterHeader (std::string uuid) +{ + return GetUid (true, uuid); +} +template +uint32_t +ChunkRegistry::RegisterTrailer (std::string uuid) +{ + return GetUid (false, uuid); +} + +template +uint32_t +ChunkRegistry::GetUid (bool isHeader, std::string uidString) +{ + InfoVector *vec = GetInfoVector (); + uint32_t uid = 1; + for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == uidString) + { + return uid; + } + uid++; + } + Info info; + info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance; + info.print = &ChunkRegistry::DoPrint; + info.getName = &ChunkRegistry::DoGetName; + info.deserialize = &ChunkRegistry::DoDeserialize; + info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback; + info.uidString = uidString; + info.isHeader = isHeader; + vec->push_back (info); + return vec->size (); +} + +template +uint8_t * +ChunkRegistry::DoGetStaticInstance () +{ + static T instance; + return reinterpret_cast (&instance); +} +template +uint32_t +ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i) +{ + T *obj = reinterpret_cast (instance); + return obj->Deserialize (i); +} +template +void +ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os) +{ + T *obj = reinterpret_cast (instance); + obj->Print (os); +} +template +std::string +ChunkRegistry::DoGetName (uint8_t *instance) +{ + T *obj = reinterpret_cast (instance); + return obj->GetName (); +} +template +void +ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os, + uint32_t packetUid, uint32_t size, + Ptr callback) +{ + T *obj = reinterpret_cast (instance); + Callback cb; + cb.Assign (callback); + cb (os, packetUid, size, obj); +} + +} // namespace ns3 #endif /* CHUNK_H */ diff --git a/src/common/header.cc b/src/common/header.cc index dae8acb4b..82bb25b09 100644 --- a/src/common/header.cc +++ b/src/common/header.cc @@ -26,4 +26,4 @@ namespace ns3 { Header::~Header () {} -}; // namespace ns3 +} // namespace ns3 diff --git a/src/common/header.h b/src/common/header.h index b70b1d731..e5739a1df 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -63,6 +63,9 @@ namespace ns3 { class Header : public Chunk { public: virtual ~Header (); +protected: + template + static uint32_t Register (std::string uuid); private: /** * \returns a user-readable name to identify this type of header. @@ -115,6 +118,18 @@ private: virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0; }; -}; // namespace ns3 +} // namespace ns3 + +namespace ns3 { + +template +uint32_t +Header::Register (std::string uuid) +{ + return ChunkRegistry::RegisterHeader (uuid); +} + + +} // namespace ns3 #endif /* HEADER_H */ diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index a56f6ef4a..1196a7342 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -35,7 +35,7 @@ template class HistoryHeader : public Header { public: - static std::string GetUid (void); + static uint32_t GetUid (void); HistoryHeader (); bool IsOk (void) const; private: @@ -48,12 +48,13 @@ private: }; template -std::string +uint32_t HistoryHeader::GetUid (void) { std::ostringstream oss; oss << N << "HistoryHeader.ns3"; - return oss.str (); + static uint32_t uid = Header::Register > (oss.str()); + return uid; } template @@ -114,7 +115,7 @@ template class HistoryTrailer : public Trailer { public: - static std::string GetUid (void); + static uint32_t GetUid (void); HistoryTrailer (); bool IsOk (void) const; private: @@ -127,12 +128,13 @@ private: }; template -std::string +uint32_t HistoryTrailer::GetUid (void) { std::ostringstream oss; oss << N << "HistoryTrailer.ns3"; - return oss.str (); + static uint32_t uid = Trailer::Register > (oss.str ()); + return uid; } diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index 0c98b2cf7..b193093f9 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -257,26 +257,26 @@ template void PacketMetadata::AddHeader (T const &header, uint32_t size) { - DoAddHeader (ChunkRegistry::GetHeaderUid () << 1, size); + DoAddHeader (T::GetUid () << 1, size); } template void PacketMetadata::RemoveHeader (T const &header, uint32_t size) { - DoRemoveHeader (ChunkRegistry::GetHeaderUid () << 1, size); + DoRemoveHeader (T::GetUid () << 1, size); } template void PacketMetadata::AddTrailer (T const &trailer, uint32_t size) { - DoAddTrailer (ChunkRegistry::GetTrailerUid () << 1, size); + DoAddTrailer (T::GetUid () << 1, size); } template void PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size) { - DoRemoveTrailer (ChunkRegistry::GetTrailerUid () << 1, size); + DoRemoveTrailer (T::GetUid () << 1, size); } diff --git a/src/common/packet-printer.h b/src/common/packet-printer.h index 632d0f6d6..1799a3d67 100644 --- a/src/common/packet-printer.h +++ b/src/common/packet-printer.h @@ -24,7 +24,7 @@ #include "ns3/callback.h" #include "ns3/ptr.h" #include "buffer.h" -#include "chunk-registry.h" +#include "chunk.h" #include namespace ns3 { @@ -158,7 +158,7 @@ PacketPrinter::SetHeaderPrinter (Callback (); + p.m_chunkUid = T::GetUid (); p.m_printer = printer.GetImpl (); p.m_fragmentPrinter = fragmentPrinter; m_printerList.push_back (p); @@ -170,7 +170,7 @@ PacketPrinter::SetTrailerPrinter (Callback (); + p.m_chunkUid = T::GetUid (); p.m_printer = printer.GetImpl (); p.m_fragmentPrinter = fragmentPrinter; m_printerList.push_back (p); diff --git a/src/common/trailer.h b/src/common/trailer.h index 457c13ccc..ed6f7bc21 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -86,6 +86,9 @@ namespace ns3 { class Trailer : public Chunk { public: virtual ~Trailer (); +protected: + template + static uint32_t Register (std::string uidString); private: /** * \returns a user-readable name to identify this type of header. @@ -142,6 +145,18 @@ private: virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0; }; -}; // namespace ns3 +} // namespace ns3 + +namespace ns3 { + +template +uint32_t +Trailer::Register (std::string uidString) +{ + return ChunkRegistry::RegisterTrailer (uidString); +} + + +} // namespace ns3 #endif /* TRAILER_H */ diff --git a/src/common/wscript b/src/common/wscript index ff8c7b60a..c1165026a 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -10,7 +10,6 @@ def build(bld): 'chunk.cc', 'header.cc', 'trailer.cc', - 'chunk-registry.cc', 'packet-printer.cc', 'packet-metadata.cc', 'packet-metadata-test.cc', @@ -36,7 +35,6 @@ def build(bld): 'tags.h', 'packet.h', 'packet-printer.h', - 'chunk-registry.h', 'packet-metadata.h', 'uv-trace-source.h', 'sv-trace-source.h', diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index e31cebf83..1bdab69b7 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -25,10 +25,11 @@ namespace ns3 { -std::string +uint32_t ArpHeader::GetUid (void) { - return "ArpHeader.ns3"; + static uint32_t uid = Header::Register ("ArpHeader.ns3"); + return uid; } ArpHeader::~ArpHeader () diff --git a/src/internet-node/arp-header.h b/src/internet-node/arp-header.h index c75d268ca..a4e61f49d 100644 --- a/src/internet-node/arp-header.h +++ b/src/internet-node/arp-header.h @@ -34,7 +34,7 @@ namespace ns3 { class ArpHeader : public Header { public: - static std::string GetUid (void); + static uint32_t GetUid (void); virtual ~ArpHeader (); diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index 813d8556a..e16a79db7 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -30,10 +30,11 @@ namespace ns3 { bool Ipv4Header::m_calcChecksum = false; -std::string +uint32_t Ipv4Header::GetUid (void) { - return "Ipv4Header.ns3"; + static uint32_t uid = Header::Register ("Ipv4Header.ns3"); + return uid; } Ipv4Header::Ipv4Header () diff --git a/src/internet-node/ipv4-header.h b/src/internet-node/ipv4-header.h index b0e6e1868..729da4f98 100644 --- a/src/internet-node/ipv4-header.h +++ b/src/internet-node/ipv4-header.h @@ -32,7 +32,7 @@ namespace ns3 { class Ipv4Header : public Header { public: - static std::string GetUid (void); + static uint32_t GetUid (void); /** * \brief Construct a null IPv4 header */ diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index a7f40d8d1..a528f066f 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -26,10 +26,11 @@ namespace ns3 { bool UdpHeader::m_calcChecksum = false; -std::string +uint32_t UdpHeader::GetUid (void) { - return "UdpHeader.ns3"; + static uint32_t uid = Header::Register ("UdpHeader.ns3"); + return uid; } /* The magic values below are used only for debugging. diff --git a/src/internet-node/udp-header.h b/src/internet-node/udp-header.h index 1a28f9ef9..3ab6dc18f 100644 --- a/src/internet-node/udp-header.h +++ b/src/internet-node/udp-header.h @@ -34,7 +34,7 @@ namespace ns3 { class UdpHeader : public Header { public: - static std::string GetUid (void); + static uint32_t GetUid (void); /** * \brief Constructor diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index d88ca027b..7195daff5 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -29,10 +29,11 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetHeader"); namespace ns3 { -std::string +uint32_t EthernetHeader::GetUid (void) { - return "EthernetHeader.ns3"; + static uint32_t uid = Header::Register ("EthernetHeader.ns3"); + return uid; } EthernetHeader::EthernetHeader (bool hasPreamble) diff --git a/src/node/ethernet-header.h b/src/node/ethernet-header.h index bde39cded..cea37705c 100644 --- a/src/node/ethernet-header.h +++ b/src/node/ethernet-header.h @@ -49,7 +49,7 @@ namespace ns3 { class EthernetHeader : public Header { public: - static std::string GetUid (void); + static uint32_t GetUid (void); /** * \brief Construct a null ethernet header diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index d5df680b1..2cf23b4a1 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -30,10 +30,11 @@ namespace ns3 { bool EthernetTrailer::m_calcFcs = false; -std::string +uint32_t EthernetTrailer::GetUid (void) { - return "EthernetTrailer.ns3"; + static uint32_t uid = Trailer::Register ("EthernetTrailer.ns3"); + return uid; } EthernetTrailer::EthernetTrailer () diff --git a/src/node/ethernet-trailer.h b/src/node/ethernet-trailer.h index f0452db75..d8354d3fa 100644 --- a/src/node/ethernet-trailer.h +++ b/src/node/ethernet-trailer.h @@ -37,7 +37,7 @@ namespace ns3 { class EthernetTrailer : public Trailer { public: - static std::string GetUid (void); + static uint32_t GetUid (void); /** * \brief Construct a null ethernet trailer diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index 2c594c206..0812fb152 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -26,10 +26,11 @@ namespace ns3 { -std::string +uint32_t LlcSnapHeader::GetUid (void) { - return "LlcSnapHeader.ns3"; + static uint32_t uid = Header::Register ("LlcSnapHeader.ns3"); + return uid; } LlcSnapHeader::LlcSnapHeader () diff --git a/src/node/llc-snap-header.h b/src/node/llc-snap-header.h index 62b8057a6..df86e5d8b 100644 --- a/src/node/llc-snap-header.h +++ b/src/node/llc-snap-header.h @@ -31,7 +31,7 @@ namespace ns3 { class LlcSnapHeader : public Header { public: - static std::string GetUid (void); + static uint32_t GetUid (void); LlcSnapHeader (); virtual ~LlcSnapHeader (); From 0cb76eb27591db4614478afa9bb785377584ac01 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:49:06 +0200 Subject: [PATCH 187/278] macros to ensure proper initialization --- src/common/header.h | 10 ++++++++++ src/common/trailer.h | 10 ++++++++++ src/internet-node/arp-header.cc | 2 ++ src/internet-node/ipv4-header.cc | 2 ++ src/internet-node/udp-header.cc | 2 ++ src/node/ethernet-header.cc | 2 ++ src/node/ethernet-trailer.cc | 2 ++ src/node/llc-snap-header.cc | 2 ++ 8 files changed, 32 insertions(+) diff --git a/src/common/header.h b/src/common/header.h index e5739a1df..f14d3a10d 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -24,6 +24,16 @@ #include "chunk.h" +#define NS_HEADER_ENSURE_REGISTERED(x) \ +namespace { \ +static class thisisaveryverylongclassname \ +{ \ +public: \ + thisisaveryverylongclassname () \ + { uint32_t uid; uid = x::GetUid ();} \ +} g_thisisanotherveryveryverylongname; \ +} + namespace ns3 { /** diff --git a/src/common/trailer.h b/src/common/trailer.h index ed6f7bc21..c07ea0b6c 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -24,6 +24,16 @@ #include "chunk.h" +#define NS_TRAILER_ENSURE_REGISTERED(x) \ +namespace { \ +static class thisisaveryverylongclassname \ +{ \ +public: \ + thisisaveryverylongclassname () \ + { uint32_t uid; uid = x::GetUid ();} \ +} g_thisisanotherveryveryverylongname; \ +} + namespace ns3 { /** diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index 1bdab69b7..261385fd2 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -23,6 +23,8 @@ #include "ns3/address-utils.h" #include "arp-header.h" +NS_HEADER_ENSURE_REGISTERED (ns3::ArpHeader); + namespace ns3 { uint32_t diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index e16a79db7..6b834991d 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -26,6 +26,8 @@ NS_DEBUG_COMPONENT_DEFINE ("Ipv4Header"); +NS_HEADER_ENSURE_REGISTERED (ns3::Ipv4Header); + namespace ns3 { bool Ipv4Header::m_calcChecksum = false; diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index a528f066f..201ab16a1 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -22,6 +22,8 @@ #include "udp-header.h" #include "ipv4-checksum.h" +NS_HEADER_ENSURE_REGISTERED (ns3::UdpHeader); + namespace ns3 { bool UdpHeader::m_calcChecksum = false; diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index 7195daff5..781c5723a 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -27,6 +27,8 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetHeader"); +NS_HEADER_ENSURE_REGISTERED (ns3::EthernetHeader); + namespace ns3 { uint32_t diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index 2cf23b4a1..d21b2c710 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -26,6 +26,8 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetTrailer"); +NS_TRAILER_ENSURE_REGISTERED (ns3::EthernetTrailer); + namespace ns3 { bool EthernetTrailer::m_calcFcs = false; diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index 0812fb152..30b18d6a3 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -23,6 +23,8 @@ #include "ns3/assert.h" #include +NS_HEADER_ENSURE_REGISTERED (ns3::LlcSnapHeader); + namespace ns3 { From b6618577c7b71b1031ae477d7944793db862bcb0 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:52:01 +0200 Subject: [PATCH 188/278] add doxygen --- src/common/header.h | 13 +++++++++++++ src/common/trailer.h | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/common/header.h b/src/common/header.h index f14d3a10d..e82ae1c16 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -24,6 +24,19 @@ #include "chunk.h" +/** + * \relates Header + * \brief this macro should be instantiated exactly once for each + * new type of Header + * + * This macro will ensure that your new Header type is registered + * within the packet header registry. In most cases, this macro + * is not really needed but, for safety, please, use it all the + * time. + * + * Note: This macro is _absolutely_ needed if you try to run a + * distributed simulation. + */ #define NS_HEADER_ENSURE_REGISTERED(x) \ namespace { \ static class thisisaveryverylongclassname \ diff --git a/src/common/trailer.h b/src/common/trailer.h index c07ea0b6c..6184f8a5f 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -24,6 +24,19 @@ #include "chunk.h" +/** + * \relates Trailer + * \brief this macro should be instantiated exactly once for each + * new type of Trailer + * + * This macro will ensure that your new Trailer type is registered + * within the packet trailer registry. In most cases, this macro + * is not really needed but, for safety, please, use it all the + * time. + * + * Note: This macro is _absolutely_ needed if you try to run a + * distributed simulation. + */ #define NS_TRAILER_ENSURE_REGISTERED(x) \ namespace { \ static class thisisaveryverylongclassname \ From 797d537cb8eb073c5bf38af8f9bfadcf45194b19 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 16:58:16 +0200 Subject: [PATCH 189/278] update dox --- src/common/header.h | 16 ++++++++++------ src/common/packet.h | 12 +++++++++--- src/common/trailer.h | 16 ++++++++++------ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/common/header.h b/src/common/header.h index e82ae1c16..39ff037c6 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -63,20 +63,24 @@ namespace ns3 { * * Each header must also make sure that: * - it defines a public default constructor - * - it defines a public static method named GetUid which returns a string. + * - it defines a public static method named GetUid which returns a 32 bit integer * - * The latter should look like the following to ensure that - * every header returns a unique string. + * The latter should look like the following: * \code + * // in the header, * class MyHeader : public Header * { * public: - * static const char *GetUid (void); + * static uint32_t GetUid (void); * }; * - * const char *MyHeader::GetUid (void) + * // in the source file: + * NS_HEADER_ENSURE_REGISTERED (MyHeader); + * + * uint32_t MyHeader::GetUid (void) * { - * return "MyHeader.unique.prefix"; + * static uint32_t uid = Header::Register ("MyHeader.unique.prefix"); + * return uid; * } * \endcode * diff --git a/src/common/packet.h b/src/common/packet.h index f4b0af11d..ce614d2c6 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -327,6 +327,7 @@ private: * * So, a tag class should look like this: * \code + * // in header file * // note how a tag class does not derive from any other class. * class MyTag * { @@ -334,9 +335,9 @@ private: * // we need a public default constructor * MyTag (); * // we need a public static GetUid - * // GetUid must return a string which uniquely + * // GetUid must return a 32 bit integer which uniquely * // identifies this tag type - * static std::string GetUid (void); + * static uint32_t GetUid (void); * // Print should record in the output stream * // the content of the tag instance. * void Print (std::ostream &os) const; @@ -352,11 +353,16 @@ private: * uint32_t Deserialize (Buffer::Iterator i); * }; * + * // in source file + * + * NS_TAG_ENSURE_REGISTERED (MyTag); + * * std::string MyTag::GetUid (void) * { * // we really want to make sure that this * // string is unique in the universe. - * return "MyTag.unique.prefix"; + * static uint32_t uid = TagRegistry ("MyTag.unique.prefix"); + * return uid; * } * \endcode */ diff --git a/src/common/trailer.h b/src/common/trailer.h index 6184f8a5f..b7a306a17 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -63,20 +63,24 @@ namespace ns3 { * * Each trailer must also make sure that: * - it defines a public default constructor - * - it defines a public static method named GetUid which returns a string. + * - it defines a public static method named GetUid which returns a 32 bit integer. * - * The latter should look like the following to ensure that - * every trailer returns a unique string. + * The latter should look like the following: * \code + * // in the header * class MyTrailer : public Header * { * public: - * static const char *GetUid (void); + * static uint32_t GetUid (void); * }; * - * const char *MyTrailer::GetUid (void) + * // in the source file + * NS_TRAILER_ENSURE_REGISTERED (MyTrailer); + * + * uint32_t MyTrailer::GetUid (void) * { - * return "MyTrailer.unique.prefix"; + * static uint32_t uid = Trailer::Register ("MyTrailer.unique.prefix"); + * return uid; * } * \endcode * From 8e1489d85b5e31ae45ca8d25df8a105f1fa2e91b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 4 Aug 2007 17:14:54 +0200 Subject: [PATCH 190/278] update the Tag API to match the Header/Trailer API --- src/common/packet.h | 2 +- src/common/tags.cc | 50 ++++++++++++------------ src/common/tags.h | 92 +++++++++++++++++++++++---------------------- 3 files changed, 74 insertions(+), 70 deletions(-) diff --git a/src/common/packet.h b/src/common/packet.h index ce614d2c6..c9aa0beb2 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -361,7 +361,7 @@ private: * { * // we really want to make sure that this * // string is unique in the universe. - * static uint32_t uid = TagRegistry ("MyTag.unique.prefix"); + * static uint32_t uid = TagRegistry::Register ("MyTag.unique.prefix"); * return uid; * } * \endcode diff --git a/src/common/tags.cc b/src/common/tags.cc index 0d78334f4..795118981 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -24,21 +24,21 @@ namespace ns3 { -Tag::TagInfoVector * -Tag::GetInfo (void) +TagRegistry::TagInfoVector * +TagRegistry::GetInfo (void) { - static Tag::TagInfoVector vector; + static TagRegistry::TagInfoVector vector; return &vector; } std::string -Tag::GetUidString (uint32_t uid) +TagRegistry::GetUidString (uint32_t uid) { TagInfo info = (*GetInfo ())[uid - 1]; return info.uidString; } uint32_t -Tag::GetUidFromUidString (std::string uidString) +TagRegistry::GetUidFromUidString (std::string uidString) { TagInfoVector *vec = GetInfo (); uint32_t uid = 1; @@ -55,31 +55,31 @@ Tag::GetUidFromUidString (std::string uidString) } void -Tag::Destruct (uint32_t uid, uint8_t data[Tags::SIZE]) +TagRegistry::Destruct (uint32_t uid, uint8_t data[Tags::SIZE]) { TagInfo info = (*GetInfo ())[uid - 1]; info.destruct (data); } void -Tag::Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os) +TagRegistry::Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os) { TagInfo info = (*GetInfo ())[uid - 1]; info.print (data, os); } uint32_t -Tag::GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]) +TagRegistry::GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]) { TagInfo info = (*GetInfo ())[uid - 1]; return info.getSerializedSize (data); } void -Tag::Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) +TagRegistry::Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) { TagInfo info = (*GetInfo ())[uid - 1]; info.serialize (data, start); } uint32_t -Tag::Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) +TagRegistry::Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) { TagInfo info = (*GetInfo ())[uid - 1]; return info.deserialize (data, start); @@ -184,7 +184,7 @@ Tags::Print (std::ostream &os) const { for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - Tag::Print (cur->m_id, cur->m_data, os); + TagRegistry::Print (cur->m_id, cur->m_data, os); } } @@ -194,10 +194,10 @@ Tags::GetSerializedSize (void) const uint32_t totalSize = 4; // reserve space for the size of the tag data. for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - uint32_t size = Tag::GetSerializedSize (cur->m_id, cur->m_data); + uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data); if (size != 0) { - std::string uidString = Tag::GetUidString (cur->m_id); + std::string uidString = TagRegistry::GetUidString (cur->m_id); totalSize += 4; // for the size of the string itself. totalSize += uidString.size (); totalSize += size; @@ -212,14 +212,14 @@ Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const i.WriteU32 (totalSize); for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - uint32_t size = Tag::GetSerializedSize (cur->m_id, cur->m_data); + uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data); if (size != 0) { - std::string uidString = Tag::GetUidString (cur->m_id); + std::string uidString = TagRegistry::GetUidString (cur->m_id); i.WriteU32 (uidString.size ()); uint8_t *buf = (uint8_t *)uidString.c_str (); i.Write (buf, uidString.size ()); - Tag::Serialize (cur->m_id, cur->m_data, i); + TagRegistry::Serialize (cur->m_id, cur->m_data, i); } } } @@ -240,12 +240,12 @@ Tags::Deserialize (Buffer::Iterator i) uidString.push_back (c); } bytesRead += uidStringSize; - uint32_t uid = Tag::GetUidFromUidString (uidString); + uint32_t uid = TagRegistry::GetUidFromUidString (uidString); struct TagData *newStart = AllocData (); newStart->m_count = 1; newStart->m_next = 0; newStart->m_id = uid; - bytesRead += Tag::Deserialize (uid, newStart->m_data, i); + bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i); newStart->m_next = m_next; m_next = newStart; } @@ -299,7 +299,7 @@ public: class myTagA { public: - static const char *GetUid (void) {return "myTagA.test.nsnam.org";} + static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagA.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_a = true;} uint32_t GetSerializedSize (void) const {return 1;} void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);} @@ -310,7 +310,7 @@ public: class myTagB { public: - static const char *GetUid (void) {return "myTagB.test.nsnam.org";} + static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagB.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_b = true;} uint32_t GetSerializedSize (void) const {return 4;} void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);} @@ -321,7 +321,7 @@ public: class myTagC { public: - static const char *GetUid (void) {return "myTagC.test.nsnam.org";} + static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagC.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_c = true;} uint32_t GetSerializedSize (void) const {return Tags::SIZE;} void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);} @@ -331,7 +331,8 @@ public: class myInvalidTag { public: - static const char *GetUid (void) {return "myInvalidTag.test.nsnam.org";} + static uint32_t GetUid (void) + {static uint32_t uid = TagRegistry::Register ("myinvalidTag.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {} uint32_t GetSerializedSize (void) const {return 0;} void Serialize (Buffer::Iterator i) const {} @@ -342,7 +343,7 @@ public: class myTagZ { public: - static const char *GetUid (void) {return "myTagZ.test.nsnam.org";} + static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagZ.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_z = true;} uint32_t GetSerializedSize (void) const {return 0;} void Serialize (Buffer::Iterator i) const {} @@ -354,7 +355,8 @@ public: class MySmartTag { public: - static const char *GetUid (void) {return "mySmartTag.test.nsnam.org";} + static uint32_t GetUid (void) + {static uint32_t uid = TagRegistry::Register ("MySmartTag.test.nsnam.org"); return uid;} MySmartTag () { //std::cout << "construct" << std::endl; diff --git a/src/common/tags.h b/src/common/tags.h index 7442b6439..db89f0694 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -26,6 +26,30 @@ #include #include "buffer.h" +/** + * \ingroup tag + * \brief this macro should be instantiated exactly once for each + * new type of Tag + * + * This macro will ensure that your new Tag type is registered + * within the tag registry. In most cases, this macro + * is not really needed but, for safety, please, use it all the + * time. + * + * Note: This macro is _absolutely_ needed if you try to run a + * distributed simulation. + */ +#define NS_TAG_ENSURE_REGISTERED(x) \ +namespace { \ +static class thisisaveryverylongclassname \ +{ \ +public: \ + thisisaveryverylongclassname () \ + { uint32_t uid; uid = x::GetUid ();} \ +} g_thisisanotherveryveryverylongname; \ +} + + namespace ns3 { template @@ -96,30 +120,18 @@ private: namespace ns3 { /** - * \brief represent a single tag + * \brief a registry of all existing tag types. * \internal * * This class is used to give polymorphic access to the methods * exported by a tag. It also is used to associate a single - * reliable uid to each unique type. The tricky part here is - * that we have to deal correctly with a single type - * being registered multiple times in AllocateUid so, - * AllocateUid must first check in the list of existing - * types if there is already a type registered with the - * same string returned by T::GetUid. - * - * It is important to note that, for example, this code - * will never be triggered on ELF systems (linux, and - * a lot of unixes) because the ELF runtime ensures that - * there exist a single instance of a template instanciation - * even if multiple instanciations of that template are - * present in memory at runtime. + * reliable uid to each unique type. */ -class Tag +class TagRegistry { public: template - static uint32_t GetUid (void); + static uint32_t Register (std::string uidString); static std::string GetUidString (uint32_t uid); static uint32_t GetUidFromUidString (std::string uidString); static void Destruct (uint32_t uid, uint8_t data[Tags::SIZE]); @@ -154,43 +166,41 @@ private: static void DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start); template static uint32_t DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start); - template - static uint32_t AllocateUid (void); static TagInfoVector *GetInfo (void); }; template void -Tag::DoDestruct (uint8_t data[Tags::SIZE]) +TagRegistry::DoDestruct (uint8_t data[Tags::SIZE]) { T *tag = reinterpret_cast (data); tag->~T (); } template void -Tag::DoPrint (uint8_t data[Tags::SIZE], std::ostream &os) +TagRegistry::DoPrint (uint8_t data[Tags::SIZE], std::ostream &os) { T *tag = reinterpret_cast (data); tag->Print (os); } template uint32_t -Tag::DoGetSerializedSize (uint8_t data[Tags::SIZE]) +TagRegistry::DoGetSerializedSize (uint8_t data[Tags::SIZE]) { T *tag = reinterpret_cast (data); return tag->GetSerializedSize (); } template void -Tag::DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) +TagRegistry::DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) { T *tag = reinterpret_cast (data); tag->Serialize (start); } template uint32_t -Tag::DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) +TagRegistry::DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) { T *tag = reinterpret_cast (data); return tag->Deserialize (start); @@ -198,33 +208,25 @@ Tag::DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) template uint32_t -Tag::GetUid (void) -{ - static uint32_t uid = AllocateUid (); - return uid; -} - -template -uint32_t -Tag::AllocateUid (void) +TagRegistry::Register (std::string uidString) { TagInfoVector *vec = GetInfo (); uint32_t j = 0; for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) { - if (i->uidString == T::GetUid ()) + if (i->uidString == uidString) { return j; } j++; } TagInfo info; - info.uidString = T::GetUid (); - info.destruct = &Tag::DoDestruct; - info.print = &Tag::DoPrint; - info.getSerializedSize = &Tag::DoGetSerializedSize; - info.serialize = &Tag::DoSerialize; - info.deserialize = &Tag::DoDeserialize; + info.uidString = uidString; + info.destruct = &TagRegistry::DoDestruct; + info.print = &TagRegistry::DoPrint; + info.getSerializedSize = &TagRegistry::DoGetSerializedSize; + info.serialize = &TagRegistry::DoSerialize; + info.deserialize = &TagRegistry::DoDeserialize; vec->push_back (info); uint32_t uid = vec->size (); return uid; @@ -238,12 +240,12 @@ Tags::Add (T const&tag) // ensure this id was not yet added for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - NS_ASSERT (cur->m_id != Tag::GetUid ()); + NS_ASSERT (cur->m_id != T::GetUid ()); } struct TagData *newStart = AllocData (); newStart->m_count = 1; newStart->m_next = 0; - newStart->m_id = Tag::GetUid (); + newStart->m_id = T::GetUid (); void *buf = &newStart->m_data; new (buf) T (tag); newStart->m_next = m_next; @@ -255,7 +257,7 @@ bool Tags::Remove (T &tag) { NS_ASSERT (sizeof (T) <= Tags::SIZE); - return Remove (Tag::GetUid ()); + return Remove (T::GetUid ()); } template @@ -265,7 +267,7 @@ Tags::Peek (T &tag) const NS_ASSERT (sizeof (T) <= Tags::SIZE); for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { - if (cur->m_id == Tag::GetUid ()) + if (cur->m_id == T::GetUid ()) { /* found tag */ T *data = reinterpret_cast (&cur->m_data); @@ -325,14 +327,14 @@ Tags::RemoveAll (void) } if (prev != 0) { - Tag::Destruct (prev->m_id, prev->m_data); + TagRegistry::Destruct (prev->m_id, prev->m_data); FreeData (prev); } prev = cur; } if (prev != 0) { - Tag::Destruct (prev->m_id, prev->m_data); + TagRegistry::Destruct (prev->m_id, prev->m_data); FreeData (prev); } m_next = 0; From 5c19b67791e6f0714a0981a59f12782d227b75d0 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sun, 5 Aug 2007 14:34:23 +0200 Subject: [PATCH 191/278] fix optimized build --- src/routing/global-routing/global-router-interface.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/routing/global-routing/global-router-interface.cc b/src/routing/global-routing/global-router-interface.cc index 24a84be06..e70d2ec04 100644 --- a/src/routing/global-routing/global-router-interface.cc +++ b/src/routing/global-routing/global-router-interface.cc @@ -535,8 +535,7 @@ GlobalRouter::GetLSA (uint32_t n, GlobalRouterLSA &lsa) const GlobalRouter::GetAdjacent(Ptr nd, Ptr ch) const { - uint32_t nDevices = ch->GetNDevices(); - NS_ASSERT_MSG(nDevices == 2, + NS_ASSERT_MSG(ch->GetNDevices() == 2, "GlobalRouter::GetAdjacent (): Channel with other than two devices"); // // This is a point to point channel with two endpoints. Get both of them. From fbbd5dc9a68c3901fb1b8d57cef5d608f22fbaff Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 10:06:25 +0200 Subject: [PATCH 192/278] use the InetSocketAddress API for ip sockets --- examples/simple-global-routing.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index 2a005589a..4398cbb6a 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -58,10 +58,10 @@ #include "ns3/internet-node.h" #include "ns3/point-to-point-channel.h" #include "ns3/point-to-point-net-device.h" -#include "ns3/mac-address.h" #include "ns3/ipv4-address.h" #include "ns3/ipv4.h" #include "ns3/socket.h" +#include "ns3/inet-socket-address.h" #include "ns3/ipv4-route.h" #include "ns3/point-to-point-topology.h" #include "ns3/onoff-application.h" @@ -82,7 +82,7 @@ int main (int argc, char *argv[]) DebugComponentEnable ("PointToPointChannel"); DebugComponentEnable ("PointToPointNetDevice"); DebugComponentEnable ("GlobalRouter"); - DebugComponentEnable ("GlobalRouteManager"); + DebugComponentEnable ("GlobalRouteMaager"); #endif // Set up some default values for the simulation. Use the Bind () @@ -143,8 +143,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - Ipv4Address ("10.1.3.2"), - 80, + InetSocketAddress ("10.1.3.2", 80).ConvertTo (), "Udp", ConstantVariable (1), ConstantVariable (0)); @@ -155,8 +154,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - Ipv4Address ("10.1.2.1"), - 80, + InetSocketAddress ("10.1.2.1", 80).ConvertTo (), "Udp", ConstantVariable (1), ConstantVariable (0)); From dcdca3338d34bc5d36be9b9f39a665de8cc39487 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 10:09:18 +0200 Subject: [PATCH 193/278] fix memory leak --- src/routing/global-routing/global-route-manager-impl.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 03578cb96..142f613be 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -1191,6 +1191,7 @@ GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) // --------------------------------------------------------------------------- #include "ns3/test.h" +#include "ns3/simulator.h" namespace ns3 { @@ -1392,6 +1393,9 @@ GlobalRouteManagerImplTest::RunTests (void) // because the NodeList is empty srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 + Simulator::Run (); + Simulator::Destroy (); + // This delete clears the srm, which deletes the LSDB, which clears // all of the LSAs, which each destroys the attached LinkRecords. delete srm; From 4946bbcf97c40b7960d465b7b33719204b5101b4 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 10:29:19 +0200 Subject: [PATCH 194/278] main should return a value --- examples/simple-global-routing.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index 4398cbb6a..24bfcf72d 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -178,4 +178,6 @@ int main (int argc, char *argv[]) Simulator::Run (); Simulator::Destroy (); + + return 0; } From f750bcefab796d6136d74663af67dcdf20871639 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 10:29:28 +0200 Subject: [PATCH 195/278] fix memory leak --- src/routing/global-routing/global-router-interface.cc | 7 +++++++ src/routing/global-routing/global-router-interface.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/routing/global-routing/global-router-interface.cc b/src/routing/global-routing/global-router-interface.cc index e70d2ec04..778d91bcc 100644 --- a/src/routing/global-routing/global-router-interface.cc +++ b/src/routing/global-routing/global-router-interface.cc @@ -332,6 +332,13 @@ GlobalRouter::~GlobalRouter () ClearLSAs(); } +void +GlobalRouter::DoDispose () +{ + m_node = 0; + Object::DoDispose (); +} + void GlobalRouter::ClearLSAs () { diff --git a/src/routing/global-routing/global-router-interface.h b/src/routing/global-routing/global-router-interface.h index b2927d631..737643d9e 100644 --- a/src/routing/global-routing/global-router-interface.h +++ b/src/routing/global-routing/global-router-interface.h @@ -565,6 +565,8 @@ protected: Ipv4Address m_routerId; private: + // inherited from Object + virtual void DoDispose (void); /** * @brief Global Router copy construction is disallowed. */ From 988d512b772f3d10af1f4b6b518bbcceffa7e0ce Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 6 Aug 2007 11:55:17 +0100 Subject: [PATCH 196/278] Correct misspelled BreakpointFallback function implementation; fixes OS X build. --- src/core/breakpoint.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/breakpoint.cc b/src/core/breakpoint.cc index c748792bc..41efcbb13 100644 --- a/src/core/breakpoint.cc +++ b/src/core/breakpoint.cc @@ -31,7 +31,7 @@ namespace ns3 { #ifdef HAVE_SIGNAL_H void -Breakpoint (void) +BreakpointFallback (void) { raise (SIGTRAP); } @@ -39,7 +39,7 @@ Breakpoint (void) #else void -Breakpoint (void) +BreakpointFallback (void) { int *a = 0; /** From caf9c39afa465ba2bc7b9cbd1b8290524ab94a5f Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 15:45:29 +0200 Subject: [PATCH 197/278] make the previous merge actually work --- examples/simple-global-routing.cc | 4 ++-- src/devices/csma-cd/csma-cd-net-device.cc | 4 ++-- src/node/eui48-address.cc | 4 ---- src/node/eui64-address.cc | 17 +++++++---------- src/node/eui64-address.h | 21 +++++---------------- src/node/packet-socket-address.cc | 5 +++++ src/node/packet-socket-address.h | 3 ++- src/node/packet-socket.cc | 4 ++-- 8 files changed, 25 insertions(+), 37 deletions(-) diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index 24bfcf72d..3458bb84f 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -143,7 +143,7 @@ int main (int argc, char *argv[]) // 210 bytes at a rate of 448 Kb/s Ptr ooff = Create ( n0, - InetSocketAddress ("10.1.3.2", 80).ConvertTo (), + InetSocketAddress ("10.1.3.2", 80), "Udp", ConstantVariable (1), ConstantVariable (0)); @@ -154,7 +154,7 @@ int main (int argc, char *argv[]) // Create a similar flow from n3 to n1, starting at time 1.1 seconds ooff = Create ( n3, - InetSocketAddress ("10.1.2.1", 80).ConvertTo (), + InetSocketAddress ("10.1.2.1", 80), "Udp", ConstantVariable (1), ConstantVariable (0)); diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index 3d8919fcb..141daf68c 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -36,7 +36,7 @@ NS_DEBUG_COMPONENT_DEFINE ("CsmaCdNetDevice"); namespace ns3 { CsmaCdNetDevice::CsmaCdNetDevice (Ptr node) - : NetDevice (node, Eui48Address::Allocate ().ConvertTo ()), + : NetDevice (node, Eui48Address::Allocate ()), m_bps (DataRate (0xffffffff)) { NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); @@ -516,7 +516,7 @@ CsmaCdNetDevice::Receive (const Packet& packet) } m_rxTrace (p); - ForwardUp (p, protocol, header.GetSource ().ConvertTo ()); + ForwardUp (p, protocol, header.GetSource ()); return; drop: m_dropTrace (p); diff --git a/src/node/eui48-address.cc b/src/node/eui48-address.cc index 4df16c829..d8b62257b 100644 --- a/src/node/eui48-address.cc +++ b/src/node/eui48-address.cc @@ -99,10 +99,6 @@ Eui48Address::operator Address () { return ConvertTo (); } -Eui48Address::Eui48Address (const Address &address) -{ - *this = ConvertFrom (address); -} Address Eui48Address::ConvertTo (void) const { diff --git a/src/node/eui64-address.cc b/src/node/eui64-address.cc index e29150542..3b91353fe 100644 --- a/src/node/eui64-address.cc +++ b/src/node/eui64-address.cc @@ -95,19 +95,10 @@ Eui64Address::IsMatchingType (const Address &address) { return address.CheckCompatible (GetType (), 8); } -Eui48Address::operator Address () +Eui64Address::operator Address () { return ConvertTo (); } -Eui48Address::Eui48Address (const Address &address) -{ - *this = ConvertFrom (address); -} -Address -Eui64Address::ConvertTo (void) const -{ - return Address (GetType (), m_address, 8); -} Eui64Address Eui64Address::ConvertFrom (const Address &address) { @@ -116,6 +107,12 @@ Eui64Address::ConvertFrom (const Address &address) address.CopyTo (retval.m_address); return retval; } +Address +Eui64Address::ConvertTo (void) const +{ + return Address (GetType (), m_address, 8); +} + Eui64Address Eui64Address::Allocate (void) { diff --git a/src/node/eui64-address.h b/src/node/eui64-address.h index f4ef91d48..98b930057 100644 --- a/src/node/eui64-address.h +++ b/src/node/eui64-address.h @@ -28,9 +28,9 @@ namespace ns3 { class Address; /** - * \brief an EUI-48 address + * \brief an EUI-64 address * - * This class can contain 48 bit IEEE addresses. + * This class can contain 64 bit IEEE addresses. */ class Eui64Address { @@ -63,30 +63,19 @@ public: operator Address (); /** * \param address a polymorphic address - * \returns a new Eui48Address from the polymorphic address + * \returns a new Eui64Address from the polymorphic address * * This function performs a type check and asserts if the * type of the input address is not compatible with an - * Eui48Address. + * Eui64Address. */ - static Eui48Address ConvertFrom (const Address &address); + static Eui64Address ConvertFrom (const Address &address); /** * \returns true if the address matches, false otherwise. */ static bool IsMatchingType (const Address &address); /** -<<<<<<< /auto/fugue/u/fugue/home/mlacage/code/ns-3-dev/src/node/eui64-address.h - * \param address a polymorphic address - * - * Convert a polymorphic address to an Eui64Address instance. - * The conversion performs a type check. - */ - static Eui64Address ConvertFrom (const Address &address); - /** * Allocate a new Eui64Address. -======= - * Allocate a new Eui48Address. ->>>>>>> /tmp/eui48-address.h~other.OBFjbL */ static Eui64Address Allocate (void); private: diff --git a/src/node/packet-socket-address.cc b/src/node/packet-socket-address.cc index de7ae5980..1b16b9cb5 100644 --- a/src/node/packet-socket-address.cc +++ b/src/node/packet-socket-address.cc @@ -68,6 +68,11 @@ PacketSocketAddress::GetPhysicalAddress (void) const return m_address; } +PacketSocketAddress::operator Address () const +{ + return ConvertTo (); +} + Address PacketSocketAddress::ConvertTo (void) const { diff --git a/src/node/packet-socket-address.h b/src/node/packet-socket-address.h index ad313f8c4..e280db8df 100644 --- a/src/node/packet-socket-address.h +++ b/src/node/packet-socket-address.h @@ -50,7 +50,7 @@ class PacketSocketAddress * * Convert an instance of this class to a polymorphic Address instance. */ - Address ConvertTo (void) const; + operator Address () const; /** * \param address a polymorphic address * @@ -64,6 +64,7 @@ class PacketSocketAddress static bool IsMatchingType (const Address &address); private: static uint8_t GetType (void); + Address ConvertTo (void) const; uint16_t m_protocol; bool m_isSingleDevice; uint32_t m_device; diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index e2c510e27..700f5f8b5 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -330,11 +330,11 @@ PacketSocket::ForwardUp (Ptr device, const Packet &packet, << " PacketSocket " << this); if (!m_dummyRxCallback.IsNull ()) { - m_dummyRxCallback (this, p.GetSize (), address.ConvertTo ()); + m_dummyRxCallback (this, p.GetSize (), address); } if (!m_rxCallback.IsNull ()) { - m_rxCallback (this, p.PeekData (), p.GetSize (), address.ConvertTo ()); + m_rxCallback (this, p.PeekData (), p.GetSize (), address); } } From 77712a63ad83ff3947820ab0ff826702646fef79 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 17:19:13 +0200 Subject: [PATCH 198/278] work in progress towards a working trace context --- src/common/array-trace-resolver.h | 64 +++----------- src/common/composite-trace-resolver.cc | 84 +++++++++++++----- src/common/composite-trace-resolver.h | 13 ++- src/common/trace-context-element.cc | 34 ++++++++ src/common/trace-context-element.h | 113 +++++++++++++++++++++++++ src/common/trace-context.cc | 38 +++------ src/common/trace-context.h | 32 +------ src/common/trace-root.cc | 2 +- src/common/trace-root.h | 3 - src/common/wscript | 2 + src/node/node-list.cc | 28 +++++- src/node/node-list.h | 16 +++- src/node/queue.cc | 36 +++++++- src/node/queue.h | 19 ++++- 14 files changed, 340 insertions(+), 144 deletions(-) create mode 100644 src/common/trace-context-element.cc create mode 100644 src/common/trace-context-element.h diff --git a/src/common/array-trace-resolver.h b/src/common/array-trace-resolver.h index 572df6e57..740616b42 100644 --- a/src/common/array-trace-resolver.h +++ b/src/common/array-trace-resolver.h @@ -32,38 +32,10 @@ namespace ns3 { * \brief a helper class to offer trace resolution for an array of objects. * \ingroup lowleveltracing */ -template +template class ArrayTraceResolver : public TraceResolver { public: - /** - * \brief array index trace context - * - * During namespace parsing, ns3::ArrayTraceResolver will - * embed an instance of this class in the TraceContext - * associated to every child object of the object stored - * at the index. - * - * The reason why this class exists is to ensure that we - * need to ensure that we can store a unique type as context - * into the TraceContext associated to this trace resolver. - */ - class Index - { - public: - Index (); - Index (uint32_t index); - /** - * The Index is automatically convertible to the - * uin32_t type such that it really behaves like a uint32_t - * array index for the user. - * - * \returns the index itself - */ - operator uint32_t (); - private: - uint32_t m_index; - }; /** * \param context trace context associated to this trace resolver * \param getSize callback which returns dynamically the size of underlying array @@ -91,41 +63,27 @@ private: namespace ns3 { -template -ArrayTraceResolver::Index::Index () - : m_index () -{} -template -ArrayTraceResolver::Index::Index (uint32_t index) - : m_index (index) -{} -template -ArrayTraceResolver::Index::operator uint32_t () -{ - return m_index; -} - -template -ArrayTraceResolver::ArrayTraceResolver (TraceContext const &context, - Callback getSize, - Callback get) +template +ArrayTraceResolver::ArrayTraceResolver (TraceContext const &context, + Callback getSize, + Callback get) : TraceResolver (context), m_getSize (getSize), m_get (get) {} -template +template TraceResolver::TraceResolverList -ArrayTraceResolver::DoLookup (std::string id) const +ArrayTraceResolver::DoLookup (std::string id) const { TraceResolverList list; if (id == "*") { for (uint32_t i = 0; i < m_getSize (); i++) { - TraceContext context = GetContext (); - typename ArrayTraceResolver::Index index = typename ArrayTraceResolver::Index (i); - context.Add (index); - list.push_back (m_get (i)->CreateTraceResolver (context)); + TraceContext context = GetContext (); + INDEX index = i; + context.Add (index); + list.push_back (m_get (i)->CreateTraceResolver (context)); } } return list; diff --git a/src/common/composite-trace-resolver.cc b/src/common/composite-trace-resolver.cc index 2fef9080b..924225342 100644 --- a/src/common/composite-trace-resolver.cc +++ b/src/common/composite-trace-resolver.cc @@ -29,6 +29,14 @@ CompositeTraceResolver::CompositeTraceResolver (TraceContext const &context) CompositeTraceResolver::~CompositeTraceResolver () {} +void +CompositeTraceResolver::Add (std::string name, + Callback createResolver) +{ + TraceContext traceContext = GetContext (); + DoAdd (name, createResolver, traceContext); +} + void CompositeTraceResolver::DoAdd (std::string name, Callback createResolver, @@ -107,20 +115,53 @@ CompositeTraceResolver::DoLookup (std::string id) const #ifdef RUN_SELF_TESTS #include "ns3/test.h" +#include "trace-context-element.h" namespace ns3 { +class TraceSourceTest : public TraceContextElement +{ +public: + enum Sources { + DOUBLEA, + DOUBLEB, + SUBRESOLVER, + }; + static uint16_t GetUid (void) + {static uint16_t uid = Register ("TraceSourceTest"); return uid;} + void Print (std::ostream &os) + {os << "tracesource="; + if (m_sources == DOUBLEA) {os << "doubleA";} + else if (m_sources == DOUBLEB) {os << "doubleB";} + else if (m_sources == SUBRESOLVER) {os << "subresolver";} + } + TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {} + TraceSourceTest (enum Sources sources) :m_sources (sources) {} + bool IsDoubleA (void) {return m_sources == TraceSourceTest::DOUBLEA;} + bool IsDoubleB (void) {return m_sources == TraceSourceTest::DOUBLEB;} +private: + enum TraceSourceTest::Sources m_sources; +}; + +class SubTraceSourceTest : public TraceContextElement +{ +public: + enum Sources { + INT, + }; + static uint16_t GetUid (void) + {static uint16_t uid = Register ("SubTraceSourceTest"); return uid;} + void Print (std::ostream &os) + {os << "subtracesource=int";} + SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {} + SubTraceSourceTest (enum Sources sources) : m_sources (sources) {} +private: + enum Sources m_sources; +}; + class CompositeTraceResolverTest : public Test { public: - enum TraceSources { - TEST_TRACE_DOUBLEA, - TEST_TRACE_DOUBLEB, - TEST_TRACE_SUBRESOLVER, - }; - enum SubTraceSources { - TEST_SUBTRACE_INT, - }; CompositeTraceResolverTest (); virtual ~CompositeTraceResolverTest (); virtual bool RunTests (void); @@ -144,19 +185,19 @@ CompositeTraceResolverTest::~CompositeTraceResolverTest () void CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v) { - enum CompositeTraceResolverTest::TraceSources source; + TraceSourceTest source; context.Get (source); - switch (source) + if (source.IsDoubleA ()) { - case TEST_TRACE_DOUBLEA: m_gotDoubleA = true; - break; - case TEST_TRACE_DOUBLEB: + } + else if (source.IsDoubleB ()) + { m_gotDoubleB = true; - break; - default: + } + else + { NS_FATAL_ERROR ("should not get any other trace source in this sink"); - break; } } @@ -171,7 +212,8 @@ TraceResolver * CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context) { CompositeTraceResolver *subresolver = new CompositeTraceResolver (context); - subresolver->Add ("trace-int", m_traceInt, TEST_SUBTRACE_INT); + subresolver->Add ("trace-int", m_traceInt, + SubTraceSourceTest (SubTraceSourceTest::INT)); return subresolver; } bool @@ -185,8 +227,10 @@ CompositeTraceResolverTest::RunTests (void) CompositeTraceResolver resolver (context) ; - resolver.Add ("trace-double-a", traceDoubleA, TEST_TRACE_DOUBLEA); - resolver.Add ("trace-double-b", traceDoubleB, TEST_TRACE_DOUBLEB); + resolver.Add ("trace-double-a", traceDoubleA, + TraceSourceTest (TraceSourceTest::DOUBLEA)); + resolver.Add ("trace-double-b", traceDoubleB, + TraceSourceTest (TraceSourceTest::DOUBLEB)); resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this)); @@ -279,7 +323,7 @@ CompositeTraceResolverTest::RunTests (void) resolver.Add ("subresolver", MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this), - TEST_TRACE_SUBRESOLVER); + TraceSourceTest (TraceSourceTest::SUBRESOLVER)); resolver.Connect ("/subresolver/trace-int", MakeCallback (&CompositeTraceResolverTest::TraceInt, this)); diff --git a/src/common/composite-trace-resolver.h b/src/common/composite-trace-resolver.h index a9603c609..cadf9da2d 100644 --- a/src/common/composite-trace-resolver.h +++ b/src/common/composite-trace-resolver.h @@ -111,6 +111,18 @@ public: void Add (std::string name, Callback createResolver, T const &context); + + /** + * \param name name of child trace resolver + * \param createResolver a trace resolver constructor + * + * Add a child trace resolver to this resolver. This child + * trace resolver will match the name specified during + * namespace resolution. When this happens, the constructor + * will be invoked to create the child trace resolver. + */ + void Add (std::string name, + Callback createResolver); private: template void DoAddTraceSource (std::string name, @@ -205,7 +217,6 @@ CompositeTraceResolver::Add (std::string name, DoAdd (name, createResolver, traceContext); } - }//namespace ns3 #endif /* COMPOSITE_TRACE_RESOLVER_H */ diff --git a/src/common/trace-context-element.cc b/src/common/trace-context-element.cc new file mode 100644 index 000000000..838250af8 --- /dev/null +++ b/src/common/trace-context-element.cc @@ -0,0 +1,34 @@ +#include "trace-context-element.h" + +namespace ns3 { + +uint32_t +ElementRegistry::GetSize (uint16_t uid) +{ + InfoVector *vec = GetInfoVector (); + struct Info info = (*vec)[uid - 1]; + return info.size; +} +void +ElementRegistry::Print (uint16_t uid, uint8_t *instance, std::ostream &os) +{ + InfoVector *vec = GetInfoVector (); + struct Info info = (*vec)[uid - 1]; + info.print (instance, os); +} +void +ElementRegistry::Destroy (uint16_t uid, uint8_t *instance) +{ + InfoVector *vec = GetInfoVector (); + struct Info info = (*vec)[uid - 1]; + info.destroy (instance); +} +ElementRegistry::InfoVector * +ElementRegistry::GetInfoVector (void) +{ + static InfoVector vector; + return &vector; +} + + +} // namespace ns3 diff --git a/src/common/trace-context-element.h b/src/common/trace-context-element.h new file mode 100644 index 000000000..e9829a2f5 --- /dev/null +++ b/src/common/trace-context-element.h @@ -0,0 +1,113 @@ +#ifndef TRACE_CONTEXT_ELEMENT_H +#define TRACE_CONTEXT_ELEMENT_H + +#include +#include + +#define NS_TRACE_CONTEXT_ELEMENT_ENSURE_REGISTERED(x) \ +namespace { \ +static class thisisaveryverylongclassname \ + { \ + public: \ + thisisaveryverylongclassname () \ + { uint32_t uid; uid = x::GetUid ();} \ + } g_thisisanotherveryveryverylongname; \ +} + +namespace ns3 { + +class TraceContextElement +{ +protected: + template + static uint16_t Register (std::string name); +}; + +} // namespace ns3 + +namespace ns3 { + +/** + * \brief a registry of TraceContextElement subclasses + * \internal + */ +class ElementRegistry +{ +public: + template + static uint16_t Register (std::string name); + + static uint32_t GetSize (uint16_t uid); + static void Print (uint16_t uid, uint8_t *instance, std::ostream &os); + static void Destroy (uint16_t uid, uint8_t *instance); +private: + typedef void (*PrintCb) (uint8_t *instance, std::ostream &os); + typedef void (*DestroyCb) (uint8_t *instance); + struct Info { + uint32_t size; + std::string uidString; + PrintCb print; + DestroyCb destroy; + }; + typedef std::vector InfoVector; + static InfoVector *GetInfoVector (void); + template + static void DoPrint (uint8_t *instance, std::ostream &os); + template + static void DoDestroy (uint8_t *instance); +}; + +template +void +ElementRegistry::DoPrint (uint8_t *instance, std::ostream &os) +{ + static T obj; + // make sure we are aligned. + memcpy ((void*)&obj, instance, sizeof (T)); + obj.Print (os); +} +template +void +ElementRegistry::DoDestroy (uint8_t *instance) +{ + static T obj; + // make sure we are aligned. + memcpy ((void*)&obj, instance, sizeof (T)); + obj.~T (); +} + +template +uint16_t +ElementRegistry::Register (std::string name) +{ + InfoVector *vec = GetInfoVector (); + uint16_t uid = 1; + for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == name) + { + return uid; + } + uid++; + } + struct Info info; + info.size = sizeof (T); + info.uidString = name; + info.print = &ElementRegistry::DoPrint; + info.destroy = &ElementRegistry::DoDestroy; + vec->push_back (info); + return vec->size (); +} + + + +template +uint16_t +TraceContextElement::Register (std::string name) +{ + return ElementRegistry::Register (name); +} + +} // namespace ns3 + +#endif /* TRACE_CONTEXT_ELEMENT_H */ diff --git a/src/common/trace-context.cc b/src/common/trace-context.cc index 786ce9149..871ca262e 100644 --- a/src/common/trace-context.cc +++ b/src/common/trace-context.cc @@ -19,12 +19,11 @@ * Author: Mathieu Lacage */ #include "trace-context.h" +#include "trace-context-element.h" #include "ns3/assert.h" namespace ns3 { -std::vector TraceContext::m_sizes; - TraceContext::TraceContext () : m_data (0) {} @@ -68,12 +67,6 @@ TraceContext::~TraceContext () } } -uint8_t -TraceContext::GetSize (uint8_t uid) -{ - return m_sizes[uid]; -} - void TraceContext::Add (TraceContext const &o) { @@ -81,12 +74,12 @@ TraceContext::Add (TraceContext const &o) { return; } - uint8_t currentUid; + uint16_t currentUid; uint16_t i = 0; while (i < o.m_data->size) { currentUid = o.m_data->data[i]; - uint8_t size = TraceContext::GetSize (currentUid); + uint8_t size = ElementRegistry::GetSize (currentUid); uint8_t *selfBuffer = CheckPresent (currentUid); uint8_t *otherBuffer = &(o.m_data->data[i+1]); if (selfBuffer != 0) @@ -116,7 +109,7 @@ TraceContext::CheckPresent (uint8_t uid) const uint16_t i = 0; do { currentUid = m_data->data[i]; - uint8_t size = TraceContext::GetSize (currentUid); + uint8_t size = ElementRegistry::GetSize (currentUid); if (currentUid == uid) { return &m_data->data[i+1]; @@ -131,7 +124,7 @@ bool TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer) { NS_ASSERT (uid != 0); - uint8_t size = TraceContext::GetSize (uid); + uint8_t size = ElementRegistry::GetSize (uid); uint8_t *present = CheckPresent (uid); if (present != 0) { if (memcmp (present, buffer, size) == 0) @@ -201,7 +194,7 @@ TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const uint16_t i = 0; do { currentUid = m_data->data[i]; - uint8_t size = TraceContext::GetSize (currentUid); + uint8_t size = ElementRegistry::GetSize (currentUid); if (currentUid == uid) { memcpy (buffer, &m_data->data[i+1], size); @@ -212,31 +205,22 @@ TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const return false; } -uint8_t -TraceContext::DoGetNextUid (void) -{ - static uint8_t uid = 0; - if (uid == 0) - { - m_sizes.push_back (0); - } - uid++; - return uid; -} - - }//namespace ns3 #include "ns3/test.h" +#include namespace ns3 { template -class Ctx +class Ctx : public TraceContextElement { public: + static uint16_t GetUid (void) {static uint16_t uid = Register > (GetName ()); return uid;} + static std::string GetName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();} Ctx () : m_v (0) {} Ctx (int v) : m_v (v) {} + void Print (std::ostream &os) {os << N;} int Get (void) const { return N;} private: int m_v; diff --git a/src/common/trace-context.h b/src/common/trace-context.h index 74108b8da..da0935727 100644 --- a/src/common/trace-context.h +++ b/src/common/trace-context.h @@ -85,17 +85,10 @@ private: template bool SafeAdd (T &context); - template - static uint8_t GetUid (void); - template - static uint8_t GetNextUid (void); - static uint8_t DoGetNextUid (void); - static uint8_t GetSize (uint8_t uid); uint8_t *CheckPresent (uint8_t uid) const; bool DoAdd (uint8_t uid, uint8_t const *buffer); bool DoGet (uint8_t uid, uint8_t *buffer) const; - static std::vector m_sizes; struct Data { uint16_t count; uint16_t size; @@ -112,7 +105,7 @@ void TraceContext::Add (T const &context) { uint8_t *data = (uint8_t *) &context; - bool ok = DoAdd (TraceContext::GetUid (), data); + bool ok = DoAdd (T::GetUid (), data); if (!ok) { NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid."); @@ -123,7 +116,7 @@ void TraceContext::Get (T &context) const { uint8_t *data = (uint8_t *) &context; - bool found = DoGet (TraceContext::GetUid (), data); + bool found = DoGet (T::GetUid (), data); if (!found) { NS_FATAL_ERROR ("Type not stored in TraceContext"); @@ -134,7 +127,7 @@ bool TraceContext::SafeGet (T &context) const { uint8_t *data = (uint8_t *) &context; - bool found = DoGet (TraceContext::GetUid (), data); + bool found = DoGet (T::GetUid (), data); return found; } template @@ -142,26 +135,9 @@ bool TraceContext::SafeAdd (T &context) { uint8_t *data = (uint8_t *) &context; - bool ok = DoAdd (TraceContext::GetUid (), data); + bool ok = DoAdd (T::GetUid (), data); return ok; } -template -uint8_t -TraceContext::GetUid (void) -{ - static uint8_t uid = GetNextUid (); - return uid; -} - -template -uint8_t -TraceContext::GetNextUid (void) -{ - uint8_t uid = DoGetNextUid (); - m_sizes.push_back (sizeof (T)); - return uid; -} - }//namespace ns3 #endif /* TRACE_CONTEXT_H */ diff --git a/src/common/trace-root.cc b/src/common/trace-root.cc index 3862408f4..5bb270b8c 100644 --- a/src/common/trace-root.cc +++ b/src/common/trace-root.cc @@ -41,7 +41,7 @@ TraceRoot::Register (std::string name, Callback createResolver) { CompositeTraceResolver *resolver = GetComposite (); - resolver->Add (name, createResolver, TraceRoot::NOTHING); + resolver->Add (name, createResolver); } CompositeTraceResolver * diff --git a/src/common/trace-root.h b/src/common/trace-root.h index 0b2a849a6..a07f923cd 100644 --- a/src/common/trace-root.h +++ b/src/common/trace-root.h @@ -328,9 +328,6 @@ public: Callback createResolver); private: static CompositeTraceResolver *GetComposite (void); - enum TraceType { - NOTHING, - }; }; }// namespace ns3 diff --git a/src/common/wscript b/src/common/wscript index c1165026a..fe34bd31c 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -18,6 +18,7 @@ def build(bld): 'pcap-writer.cc', 'variable-tracer-test.cc', 'trace-context.cc', + 'trace-context-element.cc', 'trace-resolver.cc', 'callback-trace-source.cc', 'empty-trace-resolver.cc', @@ -42,6 +43,7 @@ def build(bld): 'pcap-writer.h', 'callback-trace-source.h', 'trace-context.h', + 'trace-context-element.h', 'trace-resolver.h', 'empty-trace-resolver.h', 'composite-trace-resolver.h', diff --git a/src/node/node-list.cc b/src/node/node-list.cc index 4fed7eb5e..be5ff7122 100644 --- a/src/node/node-list.cc +++ b/src/node/node-list.cc @@ -40,6 +40,30 @@ public: namespace ns3 { +NodeListIndex::NodeListIndex () + : m_index (0) +{} +NodeListIndex::NodeListIndex (uint32_t index) + : m_index (index) +{} +void +NodeListIndex::Print (std::ostream &os) +{ + os << "nodeid=" << m_index; +} +uint16_t +NodeListIndex::GetUid (void) +{ + static uint16_t uid = Register ("NodeListIndex"); + return uid; +} +uint32_t +NodeListIndex::Get (void) const +{ + return m_index; +} + + /** * The private node list used by the static-based API */ @@ -115,8 +139,8 @@ NodeListPriv::GetNode (uint32_t n) TraceResolver * NodeListPriv::CreateTraceResolver (TraceContext const &context) { - ArrayTraceResolver *resolver = - new ArrayTraceResolver + ArrayTraceResolver *resolver = + new ArrayTraceResolver (context, MakeCallback (&NodeListPriv::GetNNodes, this), MakeCallback (&NodeListPriv::PeekNode, this)); diff --git a/src/node/node-list.h b/src/node/node-list.h index 607a47d71..1fdcd9e0e 100644 --- a/src/node/node-list.h +++ b/src/node/node-list.h @@ -23,7 +23,7 @@ #define NODE_LIST_H #include -#include "ns3/array-trace-resolver.h" +#include "ns3/trace-context-element.h" #include "ns3/ptr.h" namespace ns3 { @@ -32,6 +32,19 @@ class Node; class TraceResolver; class TraceContext; +class NodeListIndex : public TraceContextElement +{ +public: + NodeListIndex (); + NodeListIndex (uint32_t index); + void Print (std::ostream &os); + static uint16_t GetUid (void); + uint32_t Get (void) const; +private: + uint32_t m_index; +}; + + /** * \brief the list of simulation nodes. * @@ -40,7 +53,6 @@ class TraceContext; class NodeList { public: - typedef ArrayTraceResolver::Index NodeIndex; typedef std::vector< Ptr >::iterator Iterator; /** diff --git a/src/node/queue.cc b/src/node/queue.cc index 69b23bc0c..e2fc2842d 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -31,6 +31,36 @@ const InterfaceId Queue::iid = MakeInterfaceId ("Queue", Object::iid); static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue", Queue::iid, "DropTailQueue"); + +uint16_t +Queue::TraceType::GetUid (void) +{ + static uint16_t uid = Register ("Queue::TraceType"); + return uid; +} +Queue::TraceType::TraceType () + : m_type (Queue::TraceType::ENQUEUE) +{} +Queue::TraceType::TraceType (enum Type type) + : m_type (type) +{} +void +Queue::TraceType::Print (std::ostream &os) +{ + os << "queue="; + switch (m_type) { + case Queue::TraceType::ENQUEUE: + os << "enqueue"; + break; + case Queue::TraceType::DEQUEUE: + os << "dequeue"; + break; + case Queue::TraceType::DROP: + os << "drop"; + break; + } +} + Queue::Queue() : m_nBytes(0), m_nTotalReceivedBytes(0), @@ -52,9 +82,9 @@ TraceResolver * Queue::CreateTraceResolver (TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - resolver->Add ("enqueue", m_traceEnqueue, Queue::ENQUEUE); - resolver->Add ("dequeue", m_traceDequeue, Queue::DEQUEUE); - resolver->Add ("drop", m_traceDrop, Queue::DROP); + resolver->Add ("enqueue", m_traceEnqueue, Queue::TraceType (Queue::TraceType::ENQUEUE)); + resolver->Add ("dequeue", m_traceDequeue, Queue::TraceType (Queue::TraceType::DEQUEUE)); + resolver->Add ("drop", m_traceDrop, Queue::TraceType (Queue::TraceType::DROP)); return resolver; } diff --git a/src/node/queue.h b/src/node/queue.h index 02f57ca5c..0c56299ac 100644 --- a/src/node/queue.h +++ b/src/node/queue.h @@ -31,6 +31,7 @@ #include "ns3/object.h" #include "ns3/callback-trace-source.h" #include "ns3/trace-resolver.h" +#include "ns3/trace-context-element.h" namespace ns3 { @@ -46,10 +47,20 @@ class Queue : public Object public: static const InterfaceId iid; - enum TraceType { - ENQUEUE, - DEQUEUE, - DROP, + class TraceType : public TraceContextElement + { + public: + enum Type { + ENQUEUE, + DEQUEUE, + DROP + }; + static uint16_t GetUid (void); + TraceType (); + TraceType (enum Type type); + void Print (std::ostream &os); + private: + enum Type m_type; }; Queue (); virtual ~Queue (); From 1a1dda17967ba33d82d322e0b3aae7daf0533825 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 19:40:18 +0200 Subject: [PATCH 199/278] build with the new TraceContextElement API --- src/common/trace-context.cc | 26 ++++++ src/common/trace-context.h | 2 + src/devices/csma-cd/csma-cd-net-device.cc | 36 +++++++- src/devices/csma-cd/csma-cd-net-device.h | 24 ++++-- .../point-to-point-net-device.cc | 20 ++++- .../point-to-point-net-device.h | 16 ++-- src/internet-node/arp-ipv4-interface.cc | 3 +- src/internet-node/arp-ipv4-interface.h | 4 - src/internet-node/ascii-trace.cc | 37 ++------- src/internet-node/internet-node.cc | 3 +- src/internet-node/internet-node.h | 3 - src/internet-node/ipv4-l3-protocol.cc | 83 +++++++++++++++++-- src/internet-node/ipv4-l3-protocol.h | 43 +++++++--- src/internet-node/ipv4-l4-demux.cc | 26 +++++- src/internet-node/ipv4-l4-demux.h | 14 +++- src/internet-node/pcap-trace.cc | 5 +- src/node/node.cc | 38 +++++++-- src/node/node.h | 18 ++-- src/node/queue.cc | 40 ++++++--- src/node/queue.h | 35 ++++---- 20 files changed, 350 insertions(+), 126 deletions(-) diff --git a/src/common/trace-context.cc b/src/common/trace-context.cc index 871ca262e..916079020 100644 --- a/src/common/trace-context.cc +++ b/src/common/trace-context.cc @@ -205,6 +205,32 @@ TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const return false; } +void +TraceContext::Print (std::ostream &os) const +{ + if (m_data == 0) + { + return; + } + uint8_t currentUid; + uint16_t i = 0; + do { + currentUid = m_data->data[i]; + uint8_t size = ElementRegistry::GetSize (currentUid); + uint8_t *instance = &m_data->data[i+1]; + ElementRegistry::Print (currentUid, instance, os); + i += 1 + size; + if (i < m_data->size && currentUid != 0) + { + os << " "; + } + else + { + break; + } + } while (true); +} + }//namespace ns3 #include "ns3/test.h" diff --git a/src/common/trace-context.h b/src/common/trace-context.h index da0935727..560153561 100644 --- a/src/common/trace-context.h +++ b/src/common/trace-context.h @@ -77,6 +77,8 @@ public: */ template void Get (T &context) const; + + void Print (std::ostream &os) const; private: friend class TraceContextTest; // used exclusively for testing code. diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index 141daf68c..fe0216070 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -35,6 +35,32 @@ NS_DEBUG_COMPONENT_DEFINE ("CsmaCdNetDevice"); namespace ns3 { +CsmaCdTraceType::CsmaCdTraceType (enum Type type) + : m_type (type) +{} +CsmaCdTraceType::CsmaCdTraceType () + : m_type (RX) +{} +void +CsmaCdTraceType::Print (std::ostream &os) const +{ + switch (m_type) { + case RX: + os << "mac rx"; + break; + case DROP: + os << "mac drop"; + break; + } +} +uint16_t +CsmaCdTraceType::GetUid (void) +{ + static uint16_t uid = Register ("CsmaCdTraceType"); + return uid; +} + + CsmaCdNetDevice::CsmaCdNetDevice (Ptr node) : NetDevice (node, Eui48Address::Allocate ()), m_bps (DataRate (0xffffffff)) @@ -429,12 +455,14 @@ CsmaCdNetDevice::DoCreateTraceResolver (TraceContext const &context) CompositeTraceResolver *resolver = new CompositeTraceResolver (context); resolver->Add ("queue", MakeCallback (&Queue::CreateTraceResolver, - PeekPointer (m_queue)), - CsmaCdNetDevice::QUEUE); + PeekPointer (m_queue))); resolver->Add ("rx", m_rxTrace, - CsmaCdNetDevice::RX); - return resolver; + CsmaCdTraceType (CsmaCdTraceType::RX)); + resolver->Add ("drop", + m_dropTrace, + CsmaCdTraceType (CsmaCdTraceType::DROP)); + return resolver; } bool diff --git a/src/devices/csma-cd/csma-cd-net-device.h b/src/devices/csma-cd/csma-cd-net-device.h index 05a327127..36a555339 100644 --- a/src/devices/csma-cd/csma-cd-net-device.h +++ b/src/devices/csma-cd/csma-cd-net-device.h @@ -41,6 +41,21 @@ namespace ns3 { class Queue; class CsmaCdChannel; +class CsmaCdTraceType : public TraceContextElement +{ +public: + enum Type { + RX, + DROP + }; + CsmaCdTraceType (enum Type type); + CsmaCdTraceType (); + void Print (std::ostream &os) const; + static uint16_t GetUid (void); +private: + enum Type m_type; +}; + /** * \class CsmaCdNetDevice * \brief A Device for a CsmaCd Network Link. @@ -62,15 +77,6 @@ class CsmaCdChannel; */ class CsmaCdNetDevice : public NetDevice { public: - /** - * Enumeration of the types of traces supported in the class. - * - */ - enum TraceType { - QUEUE, /**< Trace queue events on the attached queue */ - RX, /**< Trace packet reception events (from the channel) */ - DROP /**< Trace packet drop events (from the channel) */ - }; /** * Enumeration of the types of packets supported in the class. diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 7e9d5c601..af3eb21f6 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -40,6 +40,21 @@ DataRateDefaultValue PointToPointNetDevice::g_defaultRate( "The default data rate for point to point links", DataRate ("10Mb/s")); +PointToPointTraceType::PointToPointTraceType () +{} +void +PointToPointTraceType::Print (std::ostream &os) const +{ + os << "device rx"; +} +uint16_t +PointToPointTraceType::GetUid (void) +{ + static uint16_t uid = Register ("PointToPointTraceType"); + return uid; +} + + PointToPointNetDevice::PointToPointNetDevice (Ptr node, const DataRate& rate) : @@ -178,11 +193,10 @@ TraceResolver* PointToPointNetDevice::DoCreateTraceResolver ( { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); resolver->Add ("queue", - MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)), - PointToPointNetDevice::QUEUE); + MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue))); resolver->Add ("rx", m_rxTrace, - PointToPointNetDevice::RX); + PointToPointTraceType ()); return resolver; } diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index 77a55a8dc..b6be56afa 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -38,6 +38,14 @@ namespace ns3 { class Queue; class PointToPointChannel; +class PointToPointTraceType : public TraceContextElement +{ +public: + PointToPointTraceType (); + void Print (std::ostream &os) const; + static uint16_t GetUid (void); +}; + /** * \class PointToPointNetDevice * \brief A Device for a Point to Point Network Link. @@ -63,14 +71,6 @@ class PointToPointChannel; */ class PointToPointNetDevice : public NetDevice { public: - /** - * Enumeration of the types of traces supported in the class. - * - */ - enum TraceType { - QUEUE, /**< Trace queue events on the attached queue */ - RX, /**< Trace packet reception events (from the channel) */ - }; /** * Construct a PointToPointNetDevice * diff --git a/src/internet-node/arp-ipv4-interface.cc b/src/internet-node/arp-ipv4-interface.cc index 313bb5851..efe767531 100644 --- a/src/internet-node/arp-ipv4-interface.cc +++ b/src/internet-node/arp-ipv4-interface.cc @@ -47,8 +47,7 @@ ArpIpv4Interface::DoCreateTraceResolver (TraceContext const &context) if (GetDevice () != 0) { resolver->Add ("netdevice", - MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())), - ArpIpv4Interface::NETDEVICE); + MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ()))); } return resolver; diff --git a/src/internet-node/arp-ipv4-interface.h b/src/internet-node/arp-ipv4-interface.h index b1c0698f1..7df522e01 100644 --- a/src/internet-node/arp-ipv4-interface.h +++ b/src/internet-node/arp-ipv4-interface.h @@ -39,10 +39,6 @@ class Node; class ArpIpv4Interface : public Ipv4Interface { public: - enum TraceType { - NETDEVICE, - ARP, - }; ArpIpv4Interface (Ptr node, Ptr device); virtual ~ArpIpv4Interface (); diff --git a/src/internet-node/ascii-trace.cc b/src/internet-node/ascii-trace.cc index b4e1430cb..cb48f06fc 100644 --- a/src/internet-node/ascii-trace.cc +++ b/src/internet-node/ascii-trace.cc @@ -24,8 +24,7 @@ #include "ns3/trace-root.h" #include "ns3/simulator.h" #include "ns3/node.h" -#include "ns3/queue.h" -#include "ns3/node-list.h" +#include "ns3/packet.h" namespace ns3 { @@ -55,42 +54,18 @@ AsciiTrace::TraceAllNetDeviceRx (void) void AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet) { - enum Queue::TraceType type; - context.Get (type); - switch (type) - { - case Queue::ENQUEUE: - m_os << "+ "; - break; - case Queue::DEQUEUE: - m_os << "- "; - break; - case Queue::DROP: - m_os << "d "; - break; - } m_os << Simulator::Now ().GetSeconds () << " "; - NodeList::NodeIndex nodeIndex; - context.Get (nodeIndex); - m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " "; - Node::NetDeviceIndex deviceIndex; - context.Get (deviceIndex); - m_os << "device=" << deviceIndex << " "; - m_os << "pkt-uid=" << packet.GetUid () << " "; + context.Print (m_os); + m_os << " pkt-uid=" << packet.GetUid () << " "; packet.Print (m_os); m_os << std::endl; } void AsciiTrace::LogDevRx (TraceContext const &context, Packet &p) { - m_os << "r " << Simulator::Now ().GetSeconds () << " "; - NodeList::NodeIndex nodeIndex; - context.Get (nodeIndex); - m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " "; - Node::NetDeviceIndex deviceIndex; - context.Get (deviceIndex); - m_os << "device=" << deviceIndex << " "; - m_os << "pkt-uid=" << p.GetUid () << " "; + m_os << Simulator::Now ().GetSeconds () << " "; + context.Print (m_os); + m_os << " pkt-uid=" << p.GetUid () << " "; p.Print (m_os); m_os << std::endl; } diff --git a/src/internet-node/internet-node.cc b/src/internet-node/internet-node.cc index 580baec0f..5c2a3de72 100644 --- a/src/internet-node/internet-node.cc +++ b/src/internet-node/internet-node.cc @@ -80,8 +80,7 @@ InternetNode::DoFillTraceResolver (CompositeTraceResolver &resolver) Node::DoFillTraceResolver (resolver); Ptr ipv4 = QueryInterface (Ipv4L3Protocol::iid); resolver.Add ("ipv4", - MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)), - InternetNode::IPV4); + MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4))); } void diff --git a/src/internet-node/internet-node.h b/src/internet-node/internet-node.h index 6047a1717..deabd20eb 100644 --- a/src/internet-node/internet-node.h +++ b/src/internet-node/internet-node.h @@ -36,9 +36,6 @@ class Packet; class InternetNode : public Node { public: - enum TraceType { - IPV4, - }; InternetNode(); InternetNode(uint32_t systemId); virtual ~InternetNode (); diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index a012d814c..1e39b5ce8 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -44,6 +44,76 @@ namespace ns3 { const InterfaceId Ipv4L3Protocol::iid = MakeInterfaceId ("Ipv4L3Protocol", Object::iid); const uint16_t Ipv4L3Protocol::PROT_NUMBER = 0x0800; +Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement () + : m_type (TX) +{} +Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement (enum Type type) + : m_type (type) +{} +bool +Ipv4L3ProtocolTraceContextElement::IsTx (void) const +{ + return m_type == TX; +} +bool +Ipv4L3ProtocolTraceContextElement::IsRx (void) const +{ + return m_type == RX; +} +bool +Ipv4L3ProtocolTraceContextElement::IsDrop (void) const +{ + return m_type == DROP; +} +void +Ipv4L3ProtocolTraceContextElement::Print (std::ostream &os) const +{ + os << "ipv4="; + switch (m_type) + { + case TX: + os << "tx"; + break; + case RX: + os << "rx"; + break; + case DROP: + os << "drop"; + break; + } +} +uint16_t +Ipv4L3ProtocolTraceContextElement::GetUid (void) +{ + static uint16_t uid = Register ("Ipv4L3ProtocolTraceContextElement"); + return uid; +} + + +Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex () + : m_index (0) +{} +Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex (uint32_t index) + : m_index (index) +{} +uint32_t +Ipv4l3ProtocolInterfaceIndex::Get (void) const +{ + return m_index; +} +void +Ipv4l3ProtocolInterfaceIndex::Print (std::ostream &os) const +{ + os << "ipv4-interface=" << m_index; +} +uint16_t +Ipv4l3ProtocolInterfaceIndex::GetUid (void) +{ + static uint16_t uid = Register ("Ipv4l3ProtocolInterfaceIndex"); + return uid; +} + + Ipv4L3Protocol::Ipv4L3Protocol(Ptr node) : m_nInterfaces (0), m_defaultTtl (64), @@ -87,20 +157,19 @@ TraceResolver * Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - resolver->Add ("tx", m_txTrace, Ipv4L3Protocol::TX); - resolver->Add ("rx", m_rxTrace, Ipv4L3Protocol::RX); - resolver->Add ("drop", m_dropTrace, Ipv4L3Protocol::DROP); + resolver->Add ("tx", m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX)); + resolver->Add ("rx", m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX)); + resolver->Add ("drop", m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP)); resolver->Add ("interfaces", - MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this), - Ipv4L3Protocol::INTERFACES); + MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this)); return resolver; } TraceResolver * Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const { - ArrayTraceResolver *resolver = - new ArrayTraceResolver + ArrayTraceResolver *resolver = + new ArrayTraceResolver (context, MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this), MakeCallback (&Ipv4L3Protocol::GetInterface, this)); diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index 6130872cd..2cce3efa3 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -25,11 +25,11 @@ #include #include #include "ns3/callback-trace-source.h" -#include "ns3/array-trace-resolver.h" +#include "ns3/trace-context-element.h" #include "ns3/ipv4-address.h" -#include "ipv4-header.h" #include "ns3/ptr.h" #include "ns3/ipv4.h" +#include "ipv4-header.h" #include "ipv4-static-routing.h" namespace ns3 { @@ -44,6 +44,37 @@ class Node; class TraceResolver; class TraceContext; +class Ipv4L3ProtocolTraceContextElement : public TraceContextElement +{ +public: + enum Type { + TX, + RX, + DROP, + }; + Ipv4L3ProtocolTraceContextElement (); + Ipv4L3ProtocolTraceContextElement (enum Type type); + bool IsTx (void) const; + bool IsRx (void) const; + bool IsDrop (void) const; + void Print (std::ostream &os) const; + static uint16_t GetUid (void); +private: + enum Type m_type; +}; + +class Ipv4l3ProtocolInterfaceIndex : public TraceContextElement +{ +public: + Ipv4l3ProtocolInterfaceIndex (); + Ipv4l3ProtocolInterfaceIndex (uint32_t index); + uint32_t Get (void) const; + void Print (std::ostream &os) const; + static uint16_t GetUid (void); +private: + uint32_t m_index; +}; + class Ipv4L3Protocol : public Object { @@ -51,14 +82,6 @@ public: static const InterfaceId iid; static const uint16_t PROT_NUMBER; - enum TraceType { - TX, - RX, - DROP, - INTERFACES, - }; - typedef ArrayTraceResolver::Index InterfaceIndex; - Ipv4L3Protocol(Ptr node); virtual ~Ipv4L3Protocol (); diff --git a/src/internet-node/ipv4-l4-demux.cc b/src/internet-node/ipv4-l4-demux.cc index d39e922df..78c8b0a3a 100644 --- a/src/internet-node/ipv4-l4-demux.cc +++ b/src/internet-node/ipv4-l4-demux.cc @@ -32,6 +32,30 @@ namespace ns3 { const InterfaceId Ipv4L4Demux::iid = MakeInterfaceId ("Ipv4L4Demux", Object::iid); +Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement () + : m_protocolNumber (0) +{} +Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement (int protocolNumber) + : m_protocolNumber (protocolNumber) +{} +int +Ipv4L4ProtocolTraceContextElement::Get (void) const +{ + return m_protocolNumber; +} +void +Ipv4L4ProtocolTraceContextElement::Print (std::ostream &os) const +{ + os << "ipv4-protocol=0x" << std::hex << m_protocolNumber << std::dec; +} +uint16_t +Ipv4L4ProtocolTraceContextElement::GetUid (void) +{ + static uint16_t uid = Register ("Ipv4L4ProtocolTraceContextElement"); + return uid; +} + + Ipv4L4Demux::Ipv4L4Demux (Ptr node) : m_node (node) { @@ -64,7 +88,7 @@ Ipv4L4Demux::CreateTraceResolver (TraceContext const &context) std::string protValue; std::ostringstream oss (protValue); oss << (*i)->GetProtocolNumber (); - Ipv4L4ProtocolTraceType protocolNumber = (*i)->GetProtocolNumber (); + Ipv4L4ProtocolTraceContextElement protocolNumber = (*i)->GetProtocolNumber (); resolver->Add (protValue, MakeCallback (&Ipv4L4Protocol::CreateTraceResolver, PeekPointer (protocol)), protocolNumber); diff --git a/src/internet-node/ipv4-l4-demux.h b/src/internet-node/ipv4-l4-demux.h index f511fcd50..7e7fba62e 100644 --- a/src/internet-node/ipv4-l4-demux.h +++ b/src/internet-node/ipv4-l4-demux.h @@ -28,6 +28,7 @@ #include #include "ns3/object.h" #include "ns3/ptr.h" +#include "ns3/trace-context-element.h" namespace ns3 { @@ -36,6 +37,18 @@ class Node; class TraceResolver; class TraceContext; +class Ipv4L4ProtocolTraceContextElement : public TraceContextElement +{ +public: + Ipv4L4ProtocolTraceContextElement (); + Ipv4L4ProtocolTraceContextElement (int protocolNumber); + int Get (void) const; + void Print (std::ostream &os) const; + static uint16_t GetUid (void); +private: + int m_protocolNumber; +}; + /** * \brief L4 Ipv4 Demux */ @@ -43,7 +56,6 @@ class Ipv4L4Demux : public Object { public: static const InterfaceId iid; - typedef int Ipv4L4ProtocolTraceType; Ipv4L4Demux (Ptr node); virtual ~Ipv4L4Demux(); diff --git a/src/internet-node/pcap-trace.cc b/src/internet-node/pcap-trace.cc index 6fa329d4d..240100fb5 100644 --- a/src/internet-node/pcap-trace.cc +++ b/src/internet-node/pcap-trace.cc @@ -82,10 +82,9 @@ PcapTrace::GetStream (uint32_t nodeId, uint32_t interfaceId) void PcapTrace::LogIp (TraceContext const &context, Packet const &p, uint32_t interfaceIndex) { - NodeList::NodeIndex nodeIndex; + NodeListIndex nodeIndex; context.Get (nodeIndex); - uint32_t nodeId = NodeList::GetNode (nodeIndex)->GetId (); - PcapWriter *writer = GetStream (nodeId, interfaceIndex); + PcapWriter *writer = GetStream (nodeIndex.Get (), interfaceIndex); writer->WritePacket (p); } diff --git a/src/node/node.cc b/src/node/node.cc index 05b61c096..d832cdf42 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -25,11 +25,37 @@ #include "packet-socket-factory.h" #include "ns3/simulator.h" #include "ns3/composite-trace-resolver.h" +#include "ns3/array-trace-resolver.h" namespace ns3{ const InterfaceId Node::iid = MakeInterfaceId ("Node", Object::iid); +NodeNetDeviceIndex::NodeNetDeviceIndex () + : m_index (0) +{} +NodeNetDeviceIndex::NodeNetDeviceIndex (uint32_t index) + : m_index (index) +{} +uint32_t +NodeNetDeviceIndex::Get (void) const +{ + return m_index; +} +void +NodeNetDeviceIndex::Print (std::ostream &os) const +{ + os << "device=" << m_index; +} +uint16_t +NodeNetDeviceIndex::GetUid (void) +{ + static uint16_t uid = Register ("NodeNetDeviceIndex"); + return uid; +} + + + Node::Node() : m_id(0), m_sid(0) @@ -118,10 +144,11 @@ Node::GetNApplications (void) const TraceResolver * Node::CreateDevicesTraceResolver (const TraceContext &context) { - ArrayTraceResolver > *resolver = - new ArrayTraceResolver > (context, - MakeCallback (&Node::GetNDevices, this), - MakeCallback (&Node::GetDevice, this)); + ArrayTraceResolver,NodeNetDeviceIndex> *resolver = + new ArrayTraceResolver,NodeNetDeviceIndex> + (context, + MakeCallback (&Node::GetNDevices, this), + MakeCallback (&Node::GetDevice, this)); return resolver; } @@ -130,8 +157,7 @@ void Node::DoFillTraceResolver (CompositeTraceResolver &resolver) { resolver.Add ("devices", - MakeCallback (&Node::CreateDevicesTraceResolver, this), - Node::DEVICES); + MakeCallback (&Node::CreateDevicesTraceResolver, this)); } void diff --git a/src/node/node.h b/src/node/node.h index e2e99dee3..f4d898f53 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -25,7 +25,7 @@ #include "ns3/object.h" #include "ns3/callback.h" -#include "ns3/array-trace-resolver.h" +#include "ns3/trace-context-element.h" namespace ns3 { @@ -37,6 +37,18 @@ class Packet; class Address; class CompositeTraceResolver; +class NodeNetDeviceIndex : public TraceContextElement +{ +public: + NodeNetDeviceIndex (); + NodeNetDeviceIndex (uint32_t index); + uint32_t Get (void) const; + void Print (std::ostream &os) const; + static uint16_t GetUid (void); +private: + uint32_t m_index; +}; + /** * \brief A network Node. * @@ -58,7 +70,6 @@ class Node : public Object { public: static const InterfaceId iid; - typedef ArrayTraceResolver >::Index NetDeviceIndex; /** * Must be invoked by subclasses only. @@ -204,9 +215,6 @@ private: void Construct (void); TraceResolver *CreateDevicesTraceResolver (const TraceContext &context); - enum TraceSource { - DEVICES - }; struct ProtocolHandlerEntry { ProtocolHandler handler; uint16_t protocol; diff --git a/src/node/queue.cc b/src/node/queue.cc index e2fc2842d..ef91aab5f 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -33,29 +33,45 @@ static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue", uint16_t -Queue::TraceType::GetUid (void) +QueueTraceType::GetUid (void) { - static uint16_t uid = Register ("Queue::TraceType"); + static uint16_t uid = Register ("QueueTraceType"); return uid; } -Queue::TraceType::TraceType () - : m_type (Queue::TraceType::ENQUEUE) +QueueTraceType::QueueTraceType () + : m_type (QueueTraceType::ENQUEUE) {} -Queue::TraceType::TraceType (enum Type type) +QueueTraceType::QueueTraceType (enum Type type) : m_type (type) {} +bool +QueueTraceType::IsEnqueue (void) const +{ + return m_type == ENQUEUE; +} +bool +QueueTraceType::IsDequeue (void) const +{ + return m_type == DEQUEUE; +} +bool +QueueTraceType::IsDrop (void) const +{ + return m_type == DROP; +} + void -Queue::TraceType::Print (std::ostream &os) +QueueTraceType::Print (std::ostream &os) const { os << "queue="; switch (m_type) { - case Queue::TraceType::ENQUEUE: + case QueueTraceType::ENQUEUE: os << "enqueue"; break; - case Queue::TraceType::DEQUEUE: + case QueueTraceType::DEQUEUE: os << "dequeue"; break; - case Queue::TraceType::DROP: + case QueueTraceType::DROP: os << "drop"; break; } @@ -82,9 +98,9 @@ TraceResolver * Queue::CreateTraceResolver (TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - resolver->Add ("enqueue", m_traceEnqueue, Queue::TraceType (Queue::TraceType::ENQUEUE)); - resolver->Add ("dequeue", m_traceDequeue, Queue::TraceType (Queue::TraceType::DEQUEUE)); - resolver->Add ("drop", m_traceDrop, Queue::TraceType (Queue::TraceType::DROP)); + resolver->Add ("enqueue", m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE)); + resolver->Add ("dequeue", m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE)); + resolver->Add ("drop", m_traceDrop, QueueTraceType (QueueTraceType::DROP)); return resolver; } diff --git a/src/node/queue.h b/src/node/queue.h index 0c56299ac..d135fff68 100644 --- a/src/node/queue.h +++ b/src/node/queue.h @@ -37,6 +37,26 @@ namespace ns3 { class StringEnumDefaultValue; +class QueueTraceType : public TraceContextElement +{ +public: + enum Type { + ENQUEUE, + DEQUEUE, + DROP + }; + static uint16_t GetUid (void); + QueueTraceType (); + QueueTraceType (enum Type type); + bool IsEnqueue (void) const; + bool IsDequeue (void) const; + bool IsDrop (void) const; + void Print (std::ostream &os) const; +private: + enum Type m_type; +}; + + /** * \brief Abstract base class for packet Queues * @@ -47,21 +67,6 @@ class Queue : public Object public: static const InterfaceId iid; - class TraceType : public TraceContextElement - { - public: - enum Type { - ENQUEUE, - DEQUEUE, - DROP - }; - static uint16_t GetUid (void); - TraceType (); - TraceType (enum Type type); - void Print (std::ostream &os); - private: - enum Type m_type; - }; Queue (); virtual ~Queue (); From 287416006af1969c4a37c8e5741ce686310d8e23 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 6 Aug 2007 19:43:09 +0200 Subject: [PATCH 200/278] tweak ascii trace output --- src/devices/csma-cd/csma-cd-net-device.cc | 4 ++-- src/devices/point-to-point/point-to-point-net-device.cc | 2 +- src/node/queue.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index fe0216070..f73555ac3 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -46,10 +46,10 @@ CsmaCdTraceType::Print (std::ostream &os) const { switch (m_type) { case RX: - os << "mac rx"; + os << "dev-rx"; break; case DROP: - os << "mac drop"; + os << "dev-drop"; break; } } diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index af3eb21f6..69271bc6e 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -45,7 +45,7 @@ PointToPointTraceType::PointToPointTraceType () void PointToPointTraceType::Print (std::ostream &os) const { - os << "device rx"; + os << "dev-rx"; } uint16_t PointToPointTraceType::GetUid (void) diff --git a/src/node/queue.cc b/src/node/queue.cc index ef91aab5f..377779bc3 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -63,7 +63,7 @@ QueueTraceType::IsDrop (void) const void QueueTraceType::Print (std::ostream &os) const { - os << "queue="; + os << "queue-"; switch (m_type) { case QueueTraceType::ENQUEUE: os << "enqueue"; From b8458246b88d6369f8ff58d2cd0a198bf3d275bd Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 6 Aug 2007 14:40:43 -0700 Subject: [PATCH 201/278] fix opt warnings, let compiler do tail call optimization in csma nd, remove protected access from router iface --- src/devices/csma-cd/csma-cd-net-device.cc | 17 +++++++++++------ .../global-routing/global-router-interface.h | 5 +++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index 141daf68c..d941c2691 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -477,13 +477,15 @@ CsmaCdNetDevice::Receive (const Packet& packet) // Only receive if send side of net device is enabled if (!IsReceiveEnabled()) { - goto drop; + m_dropTrace (p); + return; } if (m_encapMode == RAW) { ForwardUp (packet, 0, GetBroadcast ()); - goto drop; + m_dropTrace (p); + return; } p.RemoveTrailer(trailer); trailer.CheckFcs(p); @@ -495,10 +497,15 @@ CsmaCdNetDevice::Receive (const Packet& packet) (header.GetDestination() != destination)) { // not for us. - goto drop; + m_dropTrace (p); + return; } +// +// protocol must be initialized to avoid a compiler warning in the RAW +// case that breaks the optimized build. +// + uint16_t protocol = 0; - uint16_t protocol; switch (m_encapMode) { case ETHERNET_V1: @@ -518,8 +525,6 @@ CsmaCdNetDevice::Receive (const Packet& packet) m_rxTrace (p); ForwardUp (p, protocol, header.GetSource ()); return; - drop: - m_dropTrace (p); } Ptr diff --git a/src/routing/global-routing/global-router-interface.h b/src/routing/global-routing/global-router-interface.h index 737643d9e..61351d34b 100644 --- a/src/routing/global-routing/global-router-interface.h +++ b/src/routing/global-routing/global-router-interface.h @@ -550,7 +550,7 @@ public: */ bool GetLSA (uint32_t n, GlobalRouterLSA &lsa) const; -protected: +private: virtual ~GlobalRouter (); void ClearLSAs (void); @@ -564,13 +564,14 @@ protected: Ipv4Address m_routerId; -private: // inherited from Object virtual void DoDispose (void); + /** * @brief Global Router copy construction is disallowed. */ GlobalRouter (GlobalRouter& sr); + /** * @brief Global Router assignment operator is disallowed. */ From e6aae4aa5f792e2c5203f89e6c383be13c21f3df Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 7 Aug 2007 00:16:13 +0100 Subject: [PATCH 202/278] Fix compilation of BreakpointFallback on win32/mingw, which has signal.h but does not define SIGTRAP. --- src/core/breakpoint.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/breakpoint.cc b/src/core/breakpoint.cc index 41efcbb13..35eab171e 100644 --- a/src/core/breakpoint.cc +++ b/src/core/breakpoint.cc @@ -28,7 +28,7 @@ namespace ns3 { -#ifdef HAVE_SIGNAL_H +#if defined (HAVE_SIGNAL_H) && defined (SIGTRAP) void BreakpointFallback (void) From 02ccad8fbccc3b4033edcab6eb8ea4fb7699ebf8 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Tue, 7 Aug 2007 20:37:52 -0700 Subject: [PATCH 203/278] add unreachable statement to solve gcc-4.0.x compiler bug for optimized builds on os x --- src/simulator/high-precision-128.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/simulator/high-precision-128.h b/src/simulator/high-precision-128.h index 8ede96ec8..775f59ea0 100644 --- a/src/simulator/high-precision-128.h +++ b/src/simulator/high-precision-128.h @@ -222,7 +222,9 @@ HighPrecision::Compare (HighPrecision const &o) const HP128INC (m_nslowcmps); return SlowCompare (o); } - + // The below statement is unreachable but necessary for optimized + // builds with gcc-4.0.x due to a compiler bug. + return 0; } HighPrecision HighPrecision::Zero (void) From 5c419ea37f1fd0be231460af69ca5274ec72796c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 09:12:55 +0200 Subject: [PATCH 204/278] remove Chunk base class --- samples/main-header.cc | 20 +++++----- src/common/{chunk.cc => chunk-registry.cc} | 46 +--------------------- src/common/{chunk.h => chunk-registry.h} | 24 +---------- src/common/header.cc | 29 -------------- src/common/header.h | 7 ++-- src/common/packet-metadata-test.cc | 36 ++++++++--------- src/common/packet-metadata.cc | 2 +- src/common/packet-printer.cc | 1 + src/common/packet-printer.h | 1 - src/common/packet.h | 36 ++++++++++------- src/common/trailer.cc | 29 -------------- src/common/trailer.h | 7 ++-- src/common/wscript | 6 +-- src/devices/csma-cd/csma-cd-net-device.cc | 2 +- src/internet-node/arp-header.cc | 11 ++---- src/internet-node/arp-header.h | 26 +++--------- src/internet-node/ipv4-header.cc | 10 ++--- src/internet-node/ipv4-header.h | 13 +++--- src/internet-node/udp-header.cc | 18 ++++----- src/internet-node/udp-header.h | 16 ++++---- src/node/ethernet-header.cc | 11 ++---- src/node/ethernet-header.h | 12 +++--- src/node/ethernet-trailer.cc | 11 ++---- src/node/ethernet-trailer.h | 14 +++---- src/node/llc-snap-header.cc | 12 +++--- src/node/llc-snap-header.h | 14 +++---- 26 files changed, 133 insertions(+), 281 deletions(-) rename src/common/{chunk.cc => chunk-registry.cc} (82%) rename src/common/{chunk.h => chunk-registry.h} (89%) delete mode 100644 src/common/header.cc delete mode 100644 src/common/trailer.cc diff --git a/samples/main-header.cc b/samples/main-header.cc index 3094ee7ed..4c8f4920f 100644 --- a/samples/main-header.cc +++ b/samples/main-header.cc @@ -17,13 +17,13 @@ public: void SetData (uint16_t data); uint16_t GetData (void) const; -private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); - virtual uint32_t GetSerializedSize (void) const; + std::string GetName (void) const; + void Print (std::ostream &os) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); + uint32_t GetSerializedSize (void) const; +private: uint16_t m_data; }; @@ -47,14 +47,14 @@ MyHeader::GetUid (void) } std::string -MyHeader::DoGetName (void) const +MyHeader::GetName (void) const { // This string is used to identify the type of // my header by the packet printing routines. return "MYHEADER"; } void -MyHeader::PrintTo (std::ostream &os) const +MyHeader::Print (std::ostream &os) const { // This method is invoked by the packet printing // routines to print the content of my header. @@ -67,14 +67,14 @@ MyHeader::GetSerializedSize (void) const return 2; } void -MyHeader::SerializeTo (Buffer::Iterator start) const +MyHeader::Serialize (Buffer::Iterator start) const { // we can serialize two bytes at the start of the buffer. // we write them in network byte order. start.WriteHtonU16 (m_data); } uint32_t -MyHeader::DeserializeFrom (Buffer::Iterator start) +MyHeader::Deserialize (Buffer::Iterator start) { // we can deserialize two bytes from the start of the buffer. // we read them in network byte order and store them diff --git a/src/common/chunk.cc b/src/common/chunk-registry.cc similarity index 82% rename from src/common/chunk.cc rename to src/common/chunk-registry.cc index e582d884b..7186524ab 100644 --- a/src/common/chunk.cc +++ b/src/common/chunk-registry.cc @@ -19,55 +19,11 @@ * Author: Mathieu Lacage */ -#include "chunk.h" +#include "chunk-registry.h" #include "ns3/assert.h" namespace ns3 { -Chunk::Chunk () -{} - -Chunk::~Chunk () -{} - -std::string -Chunk::GetName (void) const -{ - return DoGetName (); -} -void -Chunk::Print (std::ostream &os) const -{ - PrintTo (os); -} -uint32_t -Chunk::GetSize (void) const -{ - return GetSerializedSize (); -} -void -Chunk::Serialize (Buffer::Iterator start) const -{ - SerializeTo (start); -} -uint32_t -Chunk::Deserialize (Buffer::Iterator start) -{ - uint32_t deserialized = DeserializeFrom (start); - return deserialized; -} -std::ostream& operator<< (std::ostream& os, Chunk const& chunk) -{ - chunk.Print (os); - return os; -} - - -/************************************** - * The Chunk Registry below - ***************************************/ - - ChunkRegistry::InfoVector * ChunkRegistry::GetInfoVector (void) { diff --git a/src/common/chunk.h b/src/common/chunk-registry.h similarity index 89% rename from src/common/chunk.h rename to src/common/chunk-registry.h index 193cb2bba..34e3e42ec 100644 --- a/src/common/chunk.h +++ b/src/common/chunk-registry.h @@ -19,8 +19,8 @@ * Author: Mathieu Lacage */ -#ifndef CHUNK_H -#define CHUNK_H +#ifndef CHUNK_REGISTRY_H +#define CHUNK_REGISTRY_H #include #include @@ -30,26 +30,6 @@ namespace ns3 { -class Chunk { -public: - Chunk (); - virtual ~Chunk (); - - std::string GetName (void) const; - void Print (std::ostream &os) const; - uint32_t GetSize (void) const; - void Serialize (Buffer::Iterator start) const; - uint32_t Deserialize (Buffer::Iterator start); -private: - virtual std::string DoGetName (void) const = 0; - virtual void PrintTo (std::ostream &os) const = 0; - virtual uint32_t GetSerializedSize (void) const = 0; - virtual void SerializeTo (Buffer::Iterator i) const = 0; - virtual uint32_t DeserializeFrom (Buffer::Iterator i) = 0; -}; - -std::ostream& operator<< (std::ostream& os, Chunk const& chunk); - /** * \brief this registry keeps track of all different * types of headers and trailers and assigns to each of them diff --git a/src/common/header.cc b/src/common/header.cc deleted file mode 100644 index 82bb25b09..000000000 --- a/src/common/header.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2005 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ - -#include "header.h" - -namespace ns3 { - -Header::~Header () -{} - -} // namespace ns3 diff --git a/src/common/header.h b/src/common/header.h index 39ff037c6..6d8db4575 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -22,7 +22,7 @@ #ifndef HEADER_H #define HEADER_H -#include "chunk.h" +#include "chunk-registry.h" /** * \relates Header @@ -87,12 +87,12 @@ namespace ns3 { * Sample code which shows how to create a new Header, and how to use it, * is shown in the sample file samples/main-header.cc */ -class Header : public Chunk { +class Header { public: - virtual ~Header (); protected: template static uint32_t Register (std::string uuid); +#if 0 private: /** * \returns a user-readable name to identify this type of header. @@ -143,6 +143,7 @@ private: * Packet::RemoveHeader */ virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0; +#endif }; } // namespace ns3 diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index 1196a7342..c3f829acc 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -38,12 +38,12 @@ public: static uint32_t GetUid (void); HistoryHeader (); bool IsOk (void) const; + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); bool m_ok; }; @@ -71,7 +71,7 @@ HistoryHeader::IsOk (void) const template std::string -HistoryHeader::DoGetName (void) const +HistoryHeader::GetName (void) const { std::ostringstream oss; oss << N; @@ -80,7 +80,7 @@ HistoryHeader::DoGetName (void) const template void -HistoryHeader::PrintTo (std::ostream &os) const +HistoryHeader::Print (std::ostream &os) const { NS_ASSERT (false); } @@ -92,13 +92,13 @@ HistoryHeader::GetSerializedSize (void) const } template void -HistoryHeader::SerializeTo (Buffer::Iterator start) const +HistoryHeader::Serialize (Buffer::Iterator start) const { start.WriteU8 (N, N); } template uint32_t -HistoryHeader::DeserializeFrom (Buffer::Iterator start) +HistoryHeader::Deserialize (Buffer::Iterator start) { m_ok = true; for (int i = 0; i < N; i++) @@ -118,12 +118,12 @@ public: static uint32_t GetUid (void); HistoryTrailer (); bool IsOk (void) const; + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); bool m_ok; }; @@ -152,7 +152,7 @@ HistoryTrailer::IsOk (void) const template std::string -HistoryTrailer::DoGetName (void) const +HistoryTrailer::GetName (void) const { std::ostringstream oss; oss << N; @@ -160,7 +160,7 @@ HistoryTrailer::DoGetName (void) const } template void -HistoryTrailer::PrintTo (std::ostream &os) const +HistoryTrailer::Print (std::ostream &os) const { NS_ASSERT (false); } @@ -172,14 +172,14 @@ HistoryTrailer::GetSerializedSize (void) const } template void -HistoryTrailer::SerializeTo (Buffer::Iterator start) const +HistoryTrailer::Serialize (Buffer::Iterator start) const { start.Prev (N); start.WriteU8 (N, N); } template uint32_t -HistoryTrailer::DeserializeFrom (Buffer::Iterator start) +HistoryTrailer::Deserialize (Buffer::Iterator start) { m_ok = true; start.Prev (N); diff --git a/src/common/packet-metadata.cc b/src/common/packet-metadata.cc index 6acbd2930..4229e15f8 100644 --- a/src/common/packet-metadata.cc +++ b/src/common/packet-metadata.cc @@ -23,8 +23,8 @@ #include "ns3/fatal-error.h" #include "ns3/debug.h" #include "packet-metadata.h" -#include "chunk.h" #include "buffer.h" +#include "chunk-registry.h" NS_DEBUG_COMPONENT_DEFINE ("PacketMetadata"); diff --git a/src/common/packet-printer.cc b/src/common/packet-printer.cc index b0c55b359..1419a0bb7 100644 --- a/src/common/packet-printer.cc +++ b/src/common/packet-printer.cc @@ -20,6 +20,7 @@ */ #include "packet-printer.h" +#include "chunk-registry.h" namespace ns3 { diff --git a/src/common/packet-printer.h b/src/common/packet-printer.h index 1799a3d67..22aede84c 100644 --- a/src/common/packet-printer.h +++ b/src/common/packet-printer.h @@ -24,7 +24,6 @@ #include "ns3/callback.h" #include "ns3/ptr.h" #include "buffer.h" -#include "chunk.h" #include namespace ns3 { diff --git a/src/common/packet.h b/src/common/packet.h index c9aa0beb2..b7f632641 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -118,7 +118,7 @@ public: uint32_t GetSize (void) const; /** * Add header to this packet. This method invokes the - * ns3::Chunk::GetSerializedSize and ns3::Chunk::SerializeTo + * ns3::Header::GetSerializedSize and ns3::Header::SerializeTo * methods to reserve space in the buffer and request the * header to serialize itself in the packet buffer. * @@ -128,7 +128,7 @@ public: void AddHeader (T const &header); /** * Deserialize and remove the header from the internal buffer. - * This method invokes ns3::Chunk::DeserializeFrom. + * This method invokes ns3::Header::DeserializeFrom. * * \param header a reference to the header to remove from the internal buffer. * \returns the number of bytes removed from the packet. @@ -137,7 +137,7 @@ public: uint32_t RemoveHeader (T &header); /** * Add trailer to this packet. This method invokes the - * ns3::Chunk::GetSerializedSize and ns3::Trailer::serializeTo + * ns3::Trailer::GetSerializedSize and ns3::Trailer::serializeTo * methods to reserve space in the buffer and request the trailer * to serialize itself in the packet buffer. * @@ -147,7 +147,7 @@ public: void AddTrailer (T const &trailer); /** * Remove a deserialized trailer from the internal buffer. - * This method invokes the ns3::Chunk::DeserializeFrom method. + * This method invokes the ns3::Trailer::DeserializeFrom method. * * \param trailer a reference to the trailer to remove from the internal buffer. * \returns the number of bytes removed from the end of the packet. @@ -416,9 +416,11 @@ template void Packet::AddHeader (T const &header) { - NS_ASSERT_MSG (dynamic_cast
(&header) != 0, - "Must pass Header subclass to Packet::AddHeader"); - uint32_t size = header.GetSize (); + const Header *testHeader; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Header class + testHeader = &header; + uint32_t size = header.GetSerializedSize (); m_buffer.AddAtStart (size); header.Serialize (m_buffer.Begin ()); m_metadata.AddHeader (header, size); @@ -427,8 +429,10 @@ template uint32_t Packet::RemoveHeader (T &header) { - NS_ASSERT_MSG (dynamic_cast
(&header) != 0, - "Must pass Header subclass to Packet::RemoveHeader"); + Header *testHeader; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Header class + testHeader = &header; uint32_t deserialized = header.Deserialize (m_buffer.Begin ()); m_buffer.RemoveAtStart (deserialized); m_metadata.RemoveHeader (header, deserialized); @@ -438,9 +442,11 @@ template void Packet::AddTrailer (T const &trailer) { - NS_ASSERT_MSG (dynamic_cast (&trailer) != 0, - "Must pass Trailer subclass to Packet::AddTrailer"); - uint32_t size = trailer.GetSize (); + const Trailer *testTrailer; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Trailer class + testTrailer = &trailer; + uint32_t size = trailer.GetSerializedSize (); m_buffer.AddAtEnd (size); Buffer::Iterator end = m_buffer.End (); trailer.Serialize (end); @@ -450,8 +456,10 @@ template uint32_t Packet::RemoveTrailer (T &trailer) { - NS_ASSERT_MSG (dynamic_cast (&trailer) != 0, - "Must pass Trailer subclass to Packet::RemoveTrailer"); + Trailer *testTrailer; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Trailer class + testTrailer = &trailer; uint32_t deserialized = trailer.Deserialize (m_buffer.End ()); m_buffer.RemoveAtEnd (deserialized); m_metadata.RemoveTrailer (trailer, deserialized); diff --git a/src/common/trailer.cc b/src/common/trailer.cc deleted file mode 100644 index 8026d2b92..000000000 --- a/src/common/trailer.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2005 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ - -#include "trailer.h" - -namespace ns3 { - -Trailer::~Trailer () -{} - -}; // namespace ns3 diff --git a/src/common/trailer.h b/src/common/trailer.h index b7a306a17..4b6b91fac 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -22,7 +22,7 @@ #ifndef TRAILER_H #define TRAILER_H -#include "chunk.h" +#include "chunk-registry.h" /** * \relates Trailer @@ -110,12 +110,12 @@ namespace ns3 { * trailers), the input iterator to DeserializeFrom and SerializeTo points * to the end of the trailer, and not its start. */ -class Trailer : public Chunk { +class Trailer { public: - virtual ~Trailer (); protected: template static uint32_t Register (std::string uidString); +#if 0 private: /** * \returns a user-readable name to identify this type of header. @@ -170,6 +170,7 @@ private: * amount when this method is invoked from Packet::RemoveTrailer */ virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0; +#endif }; } // namespace ns3 diff --git a/src/common/wscript b/src/common/wscript index fe34bd31c..432a81e2a 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -7,9 +7,7 @@ def build(bld): common.uselib_local = ['ns3-core', 'ns3-simulator'] common.source = [ 'buffer.cc', - 'chunk.cc', - 'header.cc', - 'trailer.cc', + 'chunk-registry.cc', 'packet-printer.cc', 'packet-metadata.cc', 'packet-metadata-test.cc', @@ -30,7 +28,7 @@ def build(bld): headers = bld.create_obj('ns3header') headers.source = [ 'buffer.h', - 'chunk.h', + 'chunk-registry.h', 'header.h', 'trailer.h', 'tags.h', diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index a67552659..f5a526f06 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -203,7 +203,7 @@ CsmaCdNetDevice::AddHeader (Packet& p, Eui48Address dest, switch (m_encapMode) { case ETHERNET_V1: - lengthType = p.GetSize() + header.GetSize() + trailer.GetSize(); + lengthType = p.GetSize() + header.GetSerializedSize() + trailer.GetSerializedSize(); break; case IP_ARP: lengthType = protocolNumber; diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index dccf80f58..587c7d543 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -34,9 +34,6 @@ ArpHeader::GetUid (void) return uid; } -ArpHeader::~ArpHeader () -{} - void ArpHeader::SetRequest (Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, @@ -93,13 +90,13 @@ ArpHeader::GetDestinationIpv4Address (void) } std::string -ArpHeader::DoGetName (void) const +ArpHeader::GetName (void) const { return "ARP"; } void -ArpHeader::PrintTo (std::ostream &os) const +ArpHeader::Print (std::ostream &os) const { if (IsRequest ()) { @@ -132,7 +129,7 @@ ArpHeader::GetSerializedSize (void) const } void -ArpHeader::SerializeTo (Buffer::Iterator start) const +ArpHeader::Serialize (Buffer::Iterator start) const { Buffer::Iterator i = start; NS_ASSERT (m_macSource.GetLength () == m_macDest.GetLength ()); @@ -150,7 +147,7 @@ ArpHeader::SerializeTo (Buffer::Iterator start) const WriteTo (i, m_ipv4Dest); } uint32_t -ArpHeader::DeserializeFrom (Buffer::Iterator start) +ArpHeader::Deserialize (Buffer::Iterator start) { Buffer::Iterator i = start; i.Next (2+2); diff --git a/src/internet-node/arp-header.h b/src/internet-node/arp-header.h index 79695a329..509530991 100644 --- a/src/internet-node/arp-header.h +++ b/src/internet-node/arp-header.h @@ -36,8 +36,6 @@ class ArpHeader : public Header public: static uint32_t GetUid (void); - virtual ~ArpHeader (); - void SetRequest (Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, Address destinationHardwareAddress, @@ -53,25 +51,11 @@ public: Ipv4Address GetSourceIpv4Address (void); Ipv4Address GetDestinationIpv4Address (void); -private: - virtual std::string DoGetName (void) const; - /** - * \param os - */ - virtual void PrintTo (std::ostream &os) const; - /** - * \return - */ - virtual uint32_t GetSerializedSize (void) const; - /** - * \param start - */ - virtual void SerializeTo (Buffer::Iterator start) const; - /** - * \param start - * \return - */ - virtual uint32_t DeserializeFrom (Buffer::Iterator start); + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); enum ArpType_e { ARP_TYPE_REQUEST = 1, diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index 6b834991d..00dc78ca6 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -49,8 +49,6 @@ Ipv4Header::Ipv4Header () m_fragmentOffset (0), m_goodChecksum (true) {} -Ipv4Header::~Ipv4Header () -{} void Ipv4Header::EnableChecksums (void) @@ -189,13 +187,13 @@ Ipv4Header::IsChecksumOk (void) const } std::string -Ipv4Header::DoGetName (void) const +Ipv4Header::GetName (void) const { return "IPV4"; } void -Ipv4Header::PrintTo (std::ostream &os) const +Ipv4Header::Print (std::ostream &os) const { // ipv4, right ? std::string flags; @@ -238,7 +236,7 @@ Ipv4Header::GetSerializedSize (void) const } void -Ipv4Header::SerializeTo (Buffer::Iterator start) const +Ipv4Header::Serialize (Buffer::Iterator start) const { Buffer::Iterator i = start; @@ -281,7 +279,7 @@ Ipv4Header::SerializeTo (Buffer::Iterator start) const } } uint32_t -Ipv4Header::DeserializeFrom (Buffer::Iterator start) +Ipv4Header::Deserialize (Buffer::Iterator start) { Buffer::Iterator i = start; uint8_t verIhl = i.ReadU8 (); diff --git a/src/internet-node/ipv4-header.h b/src/internet-node/ipv4-header.h index 729da4f98..fe9317d7c 100644 --- a/src/internet-node/ipv4-header.h +++ b/src/internet-node/ipv4-header.h @@ -37,7 +37,6 @@ public: * \brief Construct a null IPv4 header */ Ipv4Header (); - virtual ~Ipv4Header (); /** * \brief Enable checksum calculation for IP (XXX currently has no effect) */ @@ -141,12 +140,12 @@ public: */ bool IsChecksumOk (void) const; + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); enum FlagsE { DONT_FRAGMENT = (1<<0), @@ -167,7 +166,7 @@ private: bool m_goodChecksum; }; -}; // namespace ns3 +} // namespace ns3 #endif /* IPV4_HEADER_H */ diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index 201ab16a1..a90a41215 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -93,7 +93,7 @@ UdpHeader::InitializeChecksum (Ipv4Address source, destination.Serialize (buf+4); buf[8] = 0; buf[9] = protocol; - uint16_t udpLength = m_payloadSize + GetSize (); + uint16_t udpLength = m_payloadSize + GetSerializedSize (); buf[10] = udpLength >> 8; buf[11] = udpLength & 0xff; @@ -101,16 +101,16 @@ UdpHeader::InitializeChecksum (Ipv4Address source, } std::string -UdpHeader::DoGetName (void) const +UdpHeader::GetName (void) const { return "UDP"; } void -UdpHeader::PrintTo (std::ostream &os) const +UdpHeader::Print (std::ostream &os) const { os << "(" - << "length: " << m_payloadSize + GetSize () + << "length: " << m_payloadSize + GetSerializedSize () << ") " << m_sourcePort << " > " << m_destinationPort ; @@ -123,12 +123,12 @@ UdpHeader::GetSerializedSize (void) const } void -UdpHeader::SerializeTo (Buffer::Iterator start) const +UdpHeader::Serialize (Buffer::Iterator start) const { Buffer::Iterator i = start; i.WriteHtonU16 (m_sourcePort); i.WriteHtonU16 (m_destinationPort); - i.WriteHtonU16 (m_payloadSize + GetSize ()); + i.WriteHtonU16 (m_payloadSize + GetSerializedSize ()); i.WriteU16 (0); if (m_calcChecksum) @@ -137,7 +137,7 @@ UdpHeader::SerializeTo (Buffer::Iterator start) const //XXXX uint16_t checksum = Ipv4ChecksumCalculate (m_initialChecksum, buffer->PeekData (), - GetSize () + m_payloadSize); + GetSerializedSize () + m_payloadSize); checksum = Ipv4ChecksumComplete (checksum); i = buffer->Begin (); i.Next (6); @@ -146,12 +146,12 @@ UdpHeader::SerializeTo (Buffer::Iterator start) const } } uint32_t -UdpHeader::DeserializeFrom (Buffer::Iterator start) +UdpHeader::Deserialize (Buffer::Iterator start) { Buffer::Iterator i = start; m_sourcePort = i.ReadNtohU16 (); m_destinationPort = i.ReadNtohU16 (); - m_payloadSize = i.ReadNtohU16 () - GetSize (); + m_payloadSize = i.ReadNtohU16 () - GetSerializedSize (); if (m_calcChecksum) { // XXX verify checksum. diff --git a/src/internet-node/udp-header.h b/src/internet-node/udp-header.h index 3ab6dc18f..70503ef91 100644 --- a/src/internet-node/udp-header.h +++ b/src/internet-node/udp-header.h @@ -42,7 +42,7 @@ public: * Creates a null header */ UdpHeader (); - virtual ~UdpHeader (); + ~UdpHeader (); /** * \brief Enable checksum calculation for UDP (XXX currently has no effect) @@ -84,13 +84,13 @@ public: Ipv4Address destination, uint8_t protocol); -private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); +private: uint16_t m_sourcePort; uint16_t m_destinationPort; uint16_t m_payloadSize; @@ -99,6 +99,6 @@ private: static bool m_calcChecksum; }; -}; // namespace ns3 +} // namespace ns3 #endif /* UDP_HEADER */ diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index 458696a9d..ebbf7cf72 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -48,9 +48,6 @@ EthernetHeader::EthernetHeader () m_lengthType (0) {} -EthernetHeader::~EthernetHeader () -{} - void EthernetHeader::SetLengthType (uint16_t lengthType) { @@ -108,13 +105,13 @@ EthernetHeader::GetHeaderSize (void) const } std::string -EthernetHeader::DoGetName (void) const +EthernetHeader::GetName (void) const { return "ETHERNET"; } void -EthernetHeader::PrintTo (std::ostream &os) const +EthernetHeader::Print (std::ostream &os) const { // ethernet, right ? if (m_enPreambleSfd) @@ -139,7 +136,7 @@ EthernetHeader::GetSerializedSize (void) const } void -EthernetHeader::SerializeTo (Buffer::Iterator start) const +EthernetHeader::Serialize (Buffer::Iterator start) const { Buffer::Iterator i = start; @@ -152,7 +149,7 @@ EthernetHeader::SerializeTo (Buffer::Iterator start) const i.WriteU16 (m_lengthType); } uint32_t -EthernetHeader::DeserializeFrom (Buffer::Iterator start) +EthernetHeader::Deserialize (Buffer::Iterator start) { Buffer::Iterator i = start; diff --git a/src/node/ethernet-header.h b/src/node/ethernet-header.h index a755bae79..b1b3d1998 100644 --- a/src/node/ethernet-header.h +++ b/src/node/ethernet-header.h @@ -62,7 +62,6 @@ public: * By default, does not add or remove an ethernet preamble */ EthernetHeader (); - virtual ~EthernetHeader (); /** * \param size The size of the payload in bytes */ @@ -104,17 +103,16 @@ public: */ uint32_t GetHeaderSize() const; + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); private: static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field static const int LENGTH_SIZE = 2; /// size of the length_type header field static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); - /** * If false, the preamble/sfd are not serialised/deserialised. */ diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index d21b2c710..cf16bf2af 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -44,9 +44,6 @@ EthernetTrailer::EthernetTrailer () Init(); } -EthernetTrailer::~EthernetTrailer () -{} - void EthernetTrailer::Init() { m_fcs = 0; @@ -94,13 +91,13 @@ EthernetTrailer::GetTrailerSize (void) const return GetSerializedSize(); } std::string -EthernetTrailer::DoGetName (void) const +EthernetTrailer::GetName (void) const { return "ETHERNET"; } void -EthernetTrailer::PrintTo (std::ostream &os) const +EthernetTrailer::Print (std::ostream &os) const { os << " fcs=" << m_fcs; } @@ -111,7 +108,7 @@ EthernetTrailer::GetSerializedSize (void) const } void -EthernetTrailer::SerializeTo (Buffer::Iterator end) const +EthernetTrailer::Serialize (Buffer::Iterator end) const { Buffer::Iterator i = end; i.Prev(GetSerializedSize()); @@ -119,7 +116,7 @@ EthernetTrailer::SerializeTo (Buffer::Iterator end) const i.WriteU32 (m_fcs); } uint32_t -EthernetTrailer::DeserializeFrom (Buffer::Iterator end) +EthernetTrailer::Deserialize (Buffer::Iterator end) { Buffer::Iterator i = end; uint32_t size = GetSerializedSize(); diff --git a/src/node/ethernet-trailer.h b/src/node/ethernet-trailer.h index d8354d3fa..c6deeb6ab 100644 --- a/src/node/ethernet-trailer.h +++ b/src/node/ethernet-trailer.h @@ -43,7 +43,7 @@ public: * \brief Construct a null ethernet trailer */ EthernetTrailer (); - virtual ~EthernetTrailer (); + /** * \brief Enable or disabled FCS checking and calculations * \param enable If true, enables FCS calculations. @@ -81,12 +81,12 @@ public: */ uint32_t GetTrailerSize() const; + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator end) const; + uint32_t Deserialize (Buffer::Iterator end); private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator end) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator end); /** * Initializes the trailer parameters during construction. @@ -102,7 +102,7 @@ private: }; -}; // namespace ns3 +} // namespace ns3 #endif /* ETHERNET_TRAILER_H */ diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index 30b18d6a3..52a9021a8 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -38,8 +38,6 @@ LlcSnapHeader::GetUid (void) LlcSnapHeader::LlcSnapHeader () {} -LlcSnapHeader::~LlcSnapHeader () -{} void LlcSnapHeader::SetType (uint16_t type) { @@ -58,13 +56,13 @@ LlcSnapHeader::GetSerializedSize (void) const } std::string -LlcSnapHeader::DoGetName (void) const +LlcSnapHeader::GetName (void) const { return "LLCSNAP"; } void -LlcSnapHeader::PrintTo (std::ostream &os) const +LlcSnapHeader::Print (std::ostream &os) const { os << "(type 0x"; os.setf (std::ios::hex, std::ios::basefield); @@ -74,7 +72,7 @@ LlcSnapHeader::PrintTo (std::ostream &os) const } void -LlcSnapHeader::SerializeTo (Buffer::Iterator start) const +LlcSnapHeader::Serialize (Buffer::Iterator start) const { Buffer::Iterator i = start; uint8_t buf[] = {0xaa, 0xaa, 0x03, 0, 0, 0}; @@ -82,7 +80,7 @@ LlcSnapHeader::SerializeTo (Buffer::Iterator start) const i.WriteHtonU16 (m_etherType); } uint32_t -LlcSnapHeader::DeserializeFrom (Buffer::Iterator start) +LlcSnapHeader::Deserialize (Buffer::Iterator start) { Buffer::Iterator i = start; i.Next (5+1); @@ -91,4 +89,4 @@ LlcSnapHeader::DeserializeFrom (Buffer::Iterator start) } -}; // namespace ns3 +} // namespace ns3 diff --git a/src/node/llc-snap-header.h b/src/node/llc-snap-header.h index df86e5d8b..cfc9a5d9c 100644 --- a/src/node/llc-snap-header.h +++ b/src/node/llc-snap-header.h @@ -34,21 +34,19 @@ public: static uint32_t GetUid (void); LlcSnapHeader (); - virtual ~LlcSnapHeader (); - void SetType (uint16_t type); uint16_t GetType (void); + std::string GetName (void) const; + void Print (std::ostream &os) const; + uint32_t GetSerializedSize (void) const; + void Serialize (Buffer::Iterator start) const; + uint32_t Deserialize (Buffer::Iterator start); private: - virtual std::string DoGetName (void) const; - virtual void PrintTo (std::ostream &os) const; - virtual uint32_t GetSerializedSize (void) const; - virtual void SerializeTo (Buffer::Iterator start) const; - virtual uint32_t DeserializeFrom (Buffer::Iterator start); uint16_t m_etherType; }; -}; // namespace ns3 +} // namespace ns3 #endif /* LLC_SNAP_HEADER_H */ From 55b4291df049095998bd0b49eaf8c0210b9fb53e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 09:49:56 +0200 Subject: [PATCH 205/278] introduce Tag base class similar to Header and Trailer --- src/common/packet.h | 16 +++- src/common/tag-registry.cc | 87 ++++++++++++++++++++++ src/common/tag-registry.h | 149 +++++++++++++++++++++++++++++++++++++ src/common/tag.h | 49 ++++++++++++ src/common/tags.cc | 85 +++------------------ src/common/tags.h | 128 ++++--------------------------- src/common/wscript | 3 + 7 files changed, 330 insertions(+), 187 deletions(-) create mode 100644 src/common/tag-registry.cc create mode 100644 src/common/tag-registry.h create mode 100644 src/common/tag.h diff --git a/src/common/packet.h b/src/common/packet.h index b7f632641..f88052ae9 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -27,6 +27,7 @@ #include "trailer.h" #include "tags.h" #include "packet-metadata.h" +#include "tag.h" #include "ns3/callback.h" #include "ns3/assert.h" @@ -470,18 +471,31 @@ Packet::RemoveTrailer (T &trailer) template void Packet::AddTag (T const& tag) { + const Tag *parent; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Tag class. + parent = &tag; m_tags.Add (tag); } template bool Packet::RemoveTag (T & tag) { + Tag *parent; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Tag class. + parent = &tag; return m_tags.Remove (tag); } template bool Packet::PeekTag (T & tag) const { + Tag *parent; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Tag class. + parent = &tag; return m_tags.Peek (tag); } -}; // namespace ns3 + +} // namespace ns3 #endif /* PACKET_H */ diff --git a/src/common/tag-registry.cc b/src/common/tag-registry.cc new file mode 100644 index 000000000..93778a9f7 --- /dev/null +++ b/src/common/tag-registry.cc @@ -0,0 +1,87 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "tag-registry.h" +#include "ns3/fatal-error.h" + +namespace ns3 { + +TagRegistry::TagInfoVector * +TagRegistry::GetInfo (void) +{ + static TagRegistry::TagInfoVector vector; + return &vector; +} + +std::string +TagRegistry::GetUidString (uint32_t uid) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + return info.uidString; +} +uint32_t +TagRegistry::GetUidFromUidString (std::string uidString) +{ + TagInfoVector *vec = GetInfo (); + uint32_t uid = 1; + for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == uidString) + { + return uid; + } + uid++; + } + NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work."); + return 0; +} + +void +TagRegistry::Destruct (uint32_t uid, uint8_t *data) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + info.destruct (data); +} +void +TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + info.print (data, os); +} +uint32_t +TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + return info.getSerializedSize (data); +} +void +TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + info.serialize (data, start); +} +uint32_t +TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start) +{ + TagInfo info = (*GetInfo ())[uid - 1]; + return info.deserialize (data, start); +} + +} // namespace ns3 diff --git a/src/common/tag-registry.h b/src/common/tag-registry.h new file mode 100644 index 000000000..47cb29128 --- /dev/null +++ b/src/common/tag-registry.h @@ -0,0 +1,149 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef TAG_REGISTRY_H +#define TAG_REGISTRY_H + +#include +#include +#include "buffer.h" + +namespace ns3 { + +/** + * \brief a registry of all existing tag types. + * \internal + * + * This class is used to give polymorphic access to the methods + * exported by a tag. It also is used to associate a single + * reliable uid to each unique type. + */ +class TagRegistry +{ +public: + template + static uint32_t Register (std::string uidString); + static std::string GetUidString (uint32_t uid); + static uint32_t GetUidFromUidString (std::string uidString); + static void Destruct (uint32_t uid, uint8_t *data); + static void Print (uint32_t uid, uint8_t *data, std::ostream &os); + static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data); + static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start); + static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start); +private: + typedef void (*DestructCb) (uint8_t *); + typedef void (*PrintCb) (uint8_t *, std::ostream &); + typedef uint32_t (*GetSerializedSizeCb) (uint8_t *); + typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator); + typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator); + struct TagInfo + { + std::string uidString; + DestructCb destruct; + PrintCb print; + GetSerializedSizeCb getSerializedSize; + SerializeCb serialize; + DeserializeCb deserialize; + }; + typedef std::vector TagInfoVector; + + template + static void DoDestruct (uint8_t *data); + template + static void DoPrint (uint8_t *data, std::ostream &os); + template + static uint32_t DoGetSerializedSize (uint8_t *data); + template + static void DoSerialize (uint8_t *data, Buffer::Iterator start); + template + static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start); + + static TagInfoVector *GetInfo (void); +}; + +} // namespace ns3 + +namespace ns3 { + +template +void +TagRegistry::DoDestruct (uint8_t *data) +{ + T *tag = reinterpret_cast (data); + tag->~T (); +} +template +void +TagRegistry::DoPrint (uint8_t *data, std::ostream &os) +{ + T *tag = reinterpret_cast (data); + tag->Print (os); +} +template +uint32_t +TagRegistry::DoGetSerializedSize (uint8_t *data) +{ + T *tag = reinterpret_cast (data); + return tag->GetSerializedSize (); +} +template +void +TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start) +{ + T *tag = reinterpret_cast (data); + tag->Serialize (start); +} +template +uint32_t +TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start) +{ + T *tag = reinterpret_cast (data); + return tag->Deserialize (start); +} + +template +uint32_t +TagRegistry::Register (std::string uidString) +{ + TagInfoVector *vec = GetInfo (); + uint32_t j = 0; + for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) + { + if (i->uidString == uidString) + { + return j; + } + j++; + } + TagInfo info; + info.uidString = uidString; + info.destruct = &TagRegistry::DoDestruct; + info.print = &TagRegistry::DoPrint; + info.getSerializedSize = &TagRegistry::DoGetSerializedSize; + info.serialize = &TagRegistry::DoSerialize; + info.deserialize = &TagRegistry::DoDeserialize; + vec->push_back (info); + uint32_t uid = vec->size (); + return uid; +} + +} // namespace ns3 + +#endif /* TAG_REGISTRY_H */ diff --git a/src/common/tag.h b/src/common/tag.h new file mode 100644 index 000000000..b09e35dd9 --- /dev/null +++ b/src/common/tag.h @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef TAG_H +#define TAG_H + +namespace ns3 { + +class Tag +{ +protected: + template + static uint32_t AllocateUid (std::string name); +}; + +} // namespace ns3 + +// implementation below. +#include "tag-registry.h" + +namespace ns3 { + +template +uint32_t +Tag::AllocateUid (std::string name) +{ + return TagRegistry::Register (name); +} + +} // namespace ns3 + +#endif /* TAG_H */ diff --git a/src/common/tags.cc b/src/common/tags.cc index 795118981..bcf83b444 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -24,67 +24,6 @@ namespace ns3 { -TagRegistry::TagInfoVector * -TagRegistry::GetInfo (void) -{ - static TagRegistry::TagInfoVector vector; - return &vector; -} - -std::string -TagRegistry::GetUidString (uint32_t uid) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - return info.uidString; -} -uint32_t -TagRegistry::GetUidFromUidString (std::string uidString) -{ - TagInfoVector *vec = GetInfo (); - uint32_t uid = 1; - for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) - { - if (i->uidString == uidString) - { - return uid; - } - uid++; - } - NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work."); - return 0; -} - -void -TagRegistry::Destruct (uint32_t uid, uint8_t data[Tags::SIZE]) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - info.destruct (data); -} -void -TagRegistry::Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - info.print (data, os); -} -uint32_t -TagRegistry::GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - return info.getSerializedSize (data); -} -void -TagRegistry::Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - info.serialize (data, start); -} -uint32_t -TagRegistry::Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start) -{ - TagInfo info = (*GetInfo ())[uid - 1]; - return info.deserialize (data, start); -} - #ifdef USE_FREE_LIST struct Tags::TagData *Tags::gFree = 0; @@ -296,10 +235,10 @@ public: virtual bool RunTests (void); }; -class myTagA +class myTagA : public Tag { public: - static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagA.test.nsnam.org"); return uid;} + static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagA.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_a = true;} uint32_t GetSerializedSize (void) const {return 1;} void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);} @@ -307,10 +246,10 @@ public: uint8_t a; }; -class myTagB +class myTagB : public Tag { public: - static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagB.test.nsnam.org"); return uid;} + static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagB.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_b = true;} uint32_t GetSerializedSize (void) const {return 4;} void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);} @@ -318,21 +257,21 @@ public: uint32_t b; }; -class myTagC +class myTagC : public Tag { public: - static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagC.test.nsnam.org"); return uid;} + static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagC.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_c = true;} uint32_t GetSerializedSize (void) const {return Tags::SIZE;} void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);} uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;} uint8_t c [Tags::SIZE]; }; -class myInvalidTag +class myInvalidTag : public Tag { public: static uint32_t GetUid (void) - {static uint32_t uid = TagRegistry::Register ("myinvalidTag.test.nsnam.org"); return uid;} + {static uint32_t uid = AllocateUid ("myinvalidTag.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {} uint32_t GetSerializedSize (void) const {return 0;} void Serialize (Buffer::Iterator i) const {} @@ -340,10 +279,10 @@ public: uint8_t invalid [Tags::SIZE+1]; }; -class myTagZ +class myTagZ : public Tag { public: - static uint32_t GetUid (void) {static uint32_t uid = TagRegistry::Register ("myTagZ.test.nsnam.org"); return uid;} + static uint32_t GetUid (void) {static uint32_t uid = AllocateUid ("myTagZ.test.nsnam.org"); return uid;} void Print (std::ostream &os) const {g_z = true;} uint32_t GetSerializedSize (void) const {return 0;} void Serialize (Buffer::Iterator i) const {} @@ -352,11 +291,11 @@ public: uint8_t z; }; -class MySmartTag +class MySmartTag : public Tag { public: static uint32_t GetUid (void) - {static uint32_t uid = TagRegistry::Register ("MySmartTag.test.nsnam.org"); return uid;} + {static uint32_t uid = AllocateUid ("MySmartTag.test.nsnam.org"); return uid;} MySmartTag () { //std::cout << "construct" << std::endl; diff --git a/src/common/tags.h b/src/common/tags.h index db89f0694..758ff9b75 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -114,128 +114,22 @@ private: /************************************************************** An implementation of the templates defined above *************************************************************/ +#include "tag-registry.h" +#include "tag.h" #include "ns3/assert.h" #include namespace ns3 { -/** - * \brief a registry of all existing tag types. - * \internal - * - * This class is used to give polymorphic access to the methods - * exported by a tag. It also is used to associate a single - * reliable uid to each unique type. - */ -class TagRegistry -{ -public: - template - static uint32_t Register (std::string uidString); - static std::string GetUidString (uint32_t uid); - static uint32_t GetUidFromUidString (std::string uidString); - static void Destruct (uint32_t uid, uint8_t data[Tags::SIZE]); - static void Print (uint32_t uid, uint8_t data[Tags::SIZE], std::ostream &os); - static uint32_t GetSerializedSize (uint32_t uid, uint8_t data[Tags::SIZE]); - static void Serialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start); - static uint32_t Deserialize (uint32_t uid, uint8_t data[Tags::SIZE], Buffer::Iterator start); -private: - typedef void (*DestructCb) (uint8_t [Tags::SIZE]); - typedef void (*PrintCb) (uint8_t [Tags::SIZE], std::ostream &); - typedef uint32_t (*GetSerializedSizeCb) (uint8_t [Tags::SIZE]); - typedef void (*SerializeCb) (uint8_t [Tags::SIZE], Buffer::Iterator); - typedef uint32_t (*DeserializeCb) (uint8_t [Tags::SIZE], Buffer::Iterator); - struct TagInfo - { - std::string uidString; - DestructCb destruct; - PrintCb print; - GetSerializedSizeCb getSerializedSize; - SerializeCb serialize; - DeserializeCb deserialize; - }; - typedef std::vector TagInfoVector; - - template - static void DoDestruct (uint8_t data[Tags::SIZE]); - template - static void DoPrint (uint8_t data[Tags::SIZE], std::ostream &os); - template - static uint32_t DoGetSerializedSize (uint8_t data[Tags::SIZE]); - template - static void DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start); - template - static uint32_t DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start); - - static TagInfoVector *GetInfo (void); -}; - -template -void -TagRegistry::DoDestruct (uint8_t data[Tags::SIZE]) -{ - T *tag = reinterpret_cast (data); - tag->~T (); -} -template -void -TagRegistry::DoPrint (uint8_t data[Tags::SIZE], std::ostream &os) -{ - T *tag = reinterpret_cast (data); - tag->Print (os); -} -template -uint32_t -TagRegistry::DoGetSerializedSize (uint8_t data[Tags::SIZE]) -{ - T *tag = reinterpret_cast (data); - return tag->GetSerializedSize (); -} -template -void -TagRegistry::DoSerialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) -{ - T *tag = reinterpret_cast (data); - tag->Serialize (start); -} -template -uint32_t -TagRegistry::DoDeserialize (uint8_t data[Tags::SIZE], Buffer::Iterator start) -{ - T *tag = reinterpret_cast (data); - return tag->Deserialize (start); -} - -template -uint32_t -TagRegistry::Register (std::string uidString) -{ - TagInfoVector *vec = GetInfo (); - uint32_t j = 0; - for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++) - { - if (i->uidString == uidString) - { - return j; - } - j++; - } - TagInfo info; - info.uidString = uidString; - info.destruct = &TagRegistry::DoDestruct; - info.print = &TagRegistry::DoPrint; - info.getSerializedSize = &TagRegistry::DoGetSerializedSize; - info.serialize = &TagRegistry::DoSerialize; - info.deserialize = &TagRegistry::DoDeserialize; - vec->push_back (info); - uint32_t uid = vec->size (); - return uid; -} - template void Tags::Add (T const&tag) { + const Tag *parent; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Tag class. + parent = &tag; + NS_ASSERT (sizeof (T) <= Tags::SIZE); // ensure this id was not yet added for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) @@ -256,6 +150,10 @@ template bool Tags::Remove (T &tag) { + Tag *parent; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Tag class. + parent = &tag; NS_ASSERT (sizeof (T) <= Tags::SIZE); return Remove (T::GetUid ()); } @@ -264,6 +162,10 @@ template bool Tags::Peek (T &tag) const { + Tag *parent; + // if the following assignment fails, it is because the + // input to this function is not a subclass of the Tag class. + parent = &tag; NS_ASSERT (sizeof (T) <= Tags::SIZE); for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { diff --git a/src/common/wscript b/src/common/wscript index 432a81e2a..21b1a496d 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -13,6 +13,7 @@ def build(bld): 'packet-metadata-test.cc', 'packet.cc', 'tags.cc', + 'tag-registry.cc', 'pcap-writer.cc', 'variable-tracer-test.cc', 'trace-context.cc', @@ -32,6 +33,8 @@ def build(bld): 'header.h', 'trailer.h', 'tags.h', + 'tag-registry.h', + 'tag.h', 'packet.h', 'packet-printer.h', 'packet-metadata.h', From 5a38178db2b8863ebd5638f4e4141d520f4a8e94 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 10:01:19 +0200 Subject: [PATCH 206/278] Trailer::Register -> Trailer::AllocateUid and Header::Register -> Header::AllocateUid --- samples/main-header.cc | 2 +- src/common/header.h | 4 ++-- src/common/packet-metadata-test.cc | 4 ++-- src/common/trailer.h | 4 ++-- src/internet-node/arp-header.cc | 2 +- src/internet-node/ipv4-header.cc | 2 +- src/internet-node/udp-header.cc | 2 +- src/node/ethernet-header.cc | 2 +- src/node/ethernet-trailer.cc | 2 +- src/node/llc-snap-header.cc | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/samples/main-header.cc b/samples/main-header.cc index 4c8f4920f..df1b0a1bf 100644 --- a/samples/main-header.cc +++ b/samples/main-header.cc @@ -42,7 +42,7 @@ MyHeader::GetUid (void) // code to keep track of the packet metadata. // You need to make sure that this string is absolutely // unique. The code will detect any duplicate string. - static uint32_t uid = Header::Register ("MyHeader.test.nsnam.org"); + static uint32_t uid = AllocateUid ("MyHeader.test.nsnam.org"); return uid; } diff --git a/src/common/header.h b/src/common/header.h index 6d8db4575..d53a0a2b7 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -91,7 +91,7 @@ class Header { public: protected: template - static uint32_t Register (std::string uuid); + static uint32_t AllocateUid (std::string uuid); #if 0 private: /** @@ -152,7 +152,7 @@ namespace ns3 { template uint32_t -Header::Register (std::string uuid) +Header::AllocateUid (std::string uuid) { return ChunkRegistry::RegisterHeader (uuid); } diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index c3f829acc..7f3711735 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -53,7 +53,7 @@ HistoryHeader::GetUid (void) { std::ostringstream oss; oss << N << "HistoryHeader.ns3"; - static uint32_t uid = Header::Register > (oss.str()); + static uint32_t uid = AllocateUid > (oss.str()); return uid; } @@ -133,7 +133,7 @@ HistoryTrailer::GetUid (void) { std::ostringstream oss; oss << N << "HistoryTrailer.ns3"; - static uint32_t uid = Trailer::Register > (oss.str ()); + static uint32_t uid = AllocateUid > (oss.str ()); return uid; } diff --git a/src/common/trailer.h b/src/common/trailer.h index 4b6b91fac..77647c3f4 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -114,7 +114,7 @@ class Trailer { public: protected: template - static uint32_t Register (std::string uidString); + static uint32_t AllocateUid (std::string uidString); #if 0 private: /** @@ -179,7 +179,7 @@ namespace ns3 { template uint32_t -Trailer::Register (std::string uidString) +Trailer::AllocateUid (std::string uidString) { return ChunkRegistry::RegisterTrailer (uidString); } diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index 587c7d543..02a7e287d 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -30,7 +30,7 @@ namespace ns3 { uint32_t ArpHeader::GetUid (void) { - static uint32_t uid = Header::Register ("ArpHeader.ns3"); + static uint32_t uid = AllocateUid ("ArpHeader.ns3"); return uid; } diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index 00dc78ca6..891961cda 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -35,7 +35,7 @@ bool Ipv4Header::m_calcChecksum = false; uint32_t Ipv4Header::GetUid (void) { - static uint32_t uid = Header::Register ("Ipv4Header.ns3"); + static uint32_t uid = AllocateUid ("Ipv4Header.ns3"); return uid; } diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index a90a41215..6469d046d 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -31,7 +31,7 @@ bool UdpHeader::m_calcChecksum = false; uint32_t UdpHeader::GetUid (void) { - static uint32_t uid = Header::Register ("UdpHeader.ns3"); + static uint32_t uid = AllocateUid ("UdpHeader.ns3"); return uid; } diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index ebbf7cf72..fb7629bde 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -34,7 +34,7 @@ namespace ns3 { uint32_t EthernetHeader::GetUid (void) { - static uint32_t uid = Header::Register ("EthernetHeader.ns3"); + static uint32_t uid = AllocateUid ("EthernetHeader.ns3"); return uid; } diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index cf16bf2af..dbb27fc2a 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -35,7 +35,7 @@ bool EthernetTrailer::m_calcFcs = false; uint32_t EthernetTrailer::GetUid (void) { - static uint32_t uid = Trailer::Register ("EthernetTrailer.ns3"); + static uint32_t uid = AllocateUid ("EthernetTrailer.ns3"); return uid; } diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index 52a9021a8..883b4e021 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -31,7 +31,7 @@ namespace ns3 { uint32_t LlcSnapHeader::GetUid (void) { - static uint32_t uid = Header::Register ("LlcSnapHeader.ns3"); + static uint32_t uid = AllocateUid ("LlcSnapHeader.ns3"); return uid; } From 496f1d91d03fc30e47c86ab3ef3849fea00897b9 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 10:06:58 +0200 Subject: [PATCH 207/278] TraceContextElement::Register -> TraceContextElement::AllocateUid --- src/common/composite-trace-resolver.cc | 4 ++-- src/common/trace-context-element.h | 10 +++++----- src/common/trace-context.cc | 2 +- src/devices/csma-cd/csma-cd-net-device.cc | 2 +- .../point-to-point/point-to-point-net-device.cc | 2 +- src/internet-node/ipv4-l3-protocol.cc | 4 ++-- src/internet-node/ipv4-l4-demux.cc | 2 +- src/node/node-list.cc | 2 +- src/node/node.cc | 2 +- src/node/queue.cc | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/common/composite-trace-resolver.cc b/src/common/composite-trace-resolver.cc index 924225342..bf60aa81e 100644 --- a/src/common/composite-trace-resolver.cc +++ b/src/common/composite-trace-resolver.cc @@ -128,7 +128,7 @@ public: SUBRESOLVER, }; static uint16_t GetUid (void) - {static uint16_t uid = Register ("TraceSourceTest"); return uid;} + {static uint16_t uid = AllocateUid ("TraceSourceTest"); return uid;} void Print (std::ostream &os) {os << "tracesource="; if (m_sources == DOUBLEA) {os << "doubleA";} @@ -150,7 +150,7 @@ public: INT, }; static uint16_t GetUid (void) - {static uint16_t uid = Register ("SubTraceSourceTest"); return uid;} + {static uint16_t uid = AllocateUid ("SubTraceSourceTest"); return uid;} void Print (std::ostream &os) {os << "subtracesource=int";} SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {} diff --git a/src/common/trace-context-element.h b/src/common/trace-context-element.h index e9829a2f5..e27076537 100644 --- a/src/common/trace-context-element.h +++ b/src/common/trace-context-element.h @@ -20,7 +20,7 @@ class TraceContextElement { protected: template - static uint16_t Register (std::string name); + static uint16_t AllocateUid (std::string name); }; } // namespace ns3 @@ -35,7 +35,7 @@ class ElementRegistry { public: template - static uint16_t Register (std::string name); + static uint16_t AllocateUid (std::string name); static uint32_t GetSize (uint16_t uid); static void Print (uint16_t uid, uint8_t *instance, std::ostream &os); @@ -78,7 +78,7 @@ ElementRegistry::DoDestroy (uint8_t *instance) template uint16_t -ElementRegistry::Register (std::string name) +ElementRegistry::AllocateUid (std::string name) { InfoVector *vec = GetInfoVector (); uint16_t uid = 1; @@ -103,9 +103,9 @@ ElementRegistry::Register (std::string name) template uint16_t -TraceContextElement::Register (std::string name) +TraceContextElement::AllocateUid (std::string name) { - return ElementRegistry::Register (name); + return ElementRegistry::AllocateUid (name); } } // namespace ns3 diff --git a/src/common/trace-context.cc b/src/common/trace-context.cc index 916079020..50e9d0a73 100644 --- a/src/common/trace-context.cc +++ b/src/common/trace-context.cc @@ -242,7 +242,7 @@ template class Ctx : public TraceContextElement { public: - static uint16_t GetUid (void) {static uint16_t uid = Register > (GetName ()); return uid;} + static uint16_t GetUid (void) {static uint16_t uid = AllocateUid > (GetName ()); return uid;} static std::string GetName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();} Ctx () : m_v (0) {} Ctx (int v) : m_v (v) {} diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma-cd/csma-cd-net-device.cc index f5a526f06..d5dfc8501 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma-cd/csma-cd-net-device.cc @@ -56,7 +56,7 @@ CsmaCdTraceType::Print (std::ostream &os) const uint16_t CsmaCdTraceType::GetUid (void) { - static uint16_t uid = Register ("CsmaCdTraceType"); + static uint16_t uid = AllocateUid ("CsmaCdTraceType"); return uid; } diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 69271bc6e..86c9d9a4c 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -50,7 +50,7 @@ PointToPointTraceType::Print (std::ostream &os) const uint16_t PointToPointTraceType::GetUid (void) { - static uint16_t uid = Register ("PointToPointTraceType"); + static uint16_t uid = AllocateUid ("PointToPointTraceType"); return uid; } diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index 1e39b5ce8..be483dfa0 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -85,7 +85,7 @@ Ipv4L3ProtocolTraceContextElement::Print (std::ostream &os) const uint16_t Ipv4L3ProtocolTraceContextElement::GetUid (void) { - static uint16_t uid = Register ("Ipv4L3ProtocolTraceContextElement"); + static uint16_t uid = AllocateUid ("Ipv4L3ProtocolTraceContextElement"); return uid; } @@ -109,7 +109,7 @@ Ipv4l3ProtocolInterfaceIndex::Print (std::ostream &os) const uint16_t Ipv4l3ProtocolInterfaceIndex::GetUid (void) { - static uint16_t uid = Register ("Ipv4l3ProtocolInterfaceIndex"); + static uint16_t uid = AllocateUid ("Ipv4l3ProtocolInterfaceIndex"); return uid; } diff --git a/src/internet-node/ipv4-l4-demux.cc b/src/internet-node/ipv4-l4-demux.cc index 78c8b0a3a..977b802ba 100644 --- a/src/internet-node/ipv4-l4-demux.cc +++ b/src/internet-node/ipv4-l4-demux.cc @@ -51,7 +51,7 @@ Ipv4L4ProtocolTraceContextElement::Print (std::ostream &os) const uint16_t Ipv4L4ProtocolTraceContextElement::GetUid (void) { - static uint16_t uid = Register ("Ipv4L4ProtocolTraceContextElement"); + static uint16_t uid = AllocateUid ("Ipv4L4ProtocolTraceContextElement"); return uid; } diff --git a/src/node/node-list.cc b/src/node/node-list.cc index db8882abd..eb43727d9 100644 --- a/src/node/node-list.cc +++ b/src/node/node-list.cc @@ -54,7 +54,7 @@ NodeListIndex::Print (std::ostream &os) uint16_t NodeListIndex::GetUid (void) { - static uint16_t uid = Register ("NodeListIndex"); + static uint16_t uid = AllocateUid ("NodeListIndex"); return uid; } uint32_t diff --git a/src/node/node.cc b/src/node/node.cc index d832cdf42..ee83e8588 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -50,7 +50,7 @@ NodeNetDeviceIndex::Print (std::ostream &os) const uint16_t NodeNetDeviceIndex::GetUid (void) { - static uint16_t uid = Register ("NodeNetDeviceIndex"); + static uint16_t uid = AllocateUid ("NodeNetDeviceIndex"); return uid; } diff --git a/src/node/queue.cc b/src/node/queue.cc index 377779bc3..72eafed69 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -35,7 +35,7 @@ static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue", uint16_t QueueTraceType::GetUid (void) { - static uint16_t uid = Register ("QueueTraceType"); + static uint16_t uid = AllocateUid ("QueueTraceType"); return uid; } QueueTraceType::QueueTraceType () From 1e22e6d203fcc0c95aae8ba980091954bd7505d9 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 10:18:55 +0200 Subject: [PATCH 208/278] rework the NS_XX_ENSURE_REGISTERED macros and make sure we typecheck the input to TraceContext::Add and TraceContext::Get methods --- src/common/header.h | 16 +++++++--------- src/common/tag.h | 21 +++++++++++++++++++++ src/common/tags.h | 24 ------------------------ src/common/trace-context-element.h | 6 +++--- src/common/trace-context.h | 21 +++++++++++++++++++-- src/common/trailer.h | 16 +++++++--------- src/internet-node/arp-header.cc | 4 ++-- src/internet-node/ipv4-header.cc | 4 ++-- src/internet-node/udp-header.cc | 4 ++-- src/node/ethernet-header.cc | 4 ++-- src/node/ethernet-trailer.cc | 4 ++-- src/node/llc-snap-header.cc | 5 ++--- 12 files changed, 69 insertions(+), 60 deletions(-) diff --git a/src/common/header.h b/src/common/header.h index d53a0a2b7..6ed053641 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -37,15 +37,13 @@ * Note: This macro is _absolutely_ needed if you try to run a * distributed simulation. */ -#define NS_HEADER_ENSURE_REGISTERED(x) \ -namespace { \ -static class thisisaveryverylongclassname \ -{ \ -public: \ - thisisaveryverylongclassname () \ - { uint32_t uid; uid = x::GetUid ();} \ -} g_thisisanotherveryveryverylongname; \ -} +#define NS_HEADER_ENSURE_REGISTERED(x) \ +static class thisisaveryverylongclassname ##x \ +{ \ + public: \ + thisisaveryverylongclassname ##x () \ + { uint32_t uid; uid = x::GetUid ();} \ +} g_thisisanotherveryveryverylongname ## x; namespace ns3 { diff --git a/src/common/tag.h b/src/common/tag.h index b09e35dd9..5046b8886 100644 --- a/src/common/tag.h +++ b/src/common/tag.h @@ -21,6 +21,27 @@ #ifndef TAG_H #define TAG_H +/** + * \relates Tag + * \brief this macro should be instantiated exactly once for each + * new type of Tag + * + * This macro will ensure that your new Tag type is registered + * within the tag registry. In most cases, this macro + * is not really needed but, for safety, please, use it all the + * time. + * + * Note: This macro is _absolutely_ needed if you try to run a + * distributed simulation. + */ +#define NS_TAG_ENSURE_REGISTERED(x) \ +static class thisisaveryverylongclassname ##x \ +{ \ + public: \ + thisisaveryverylongclassname ##x () \ + { uint32_t uid; uid = x::GetUid ();} \ +} g_thisisanotherveryveryverylongname ## x; + namespace ns3 { class Tag diff --git a/src/common/tags.h b/src/common/tags.h index 758ff9b75..817cb6fa0 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -26,30 +26,6 @@ #include #include "buffer.h" -/** - * \ingroup tag - * \brief this macro should be instantiated exactly once for each - * new type of Tag - * - * This macro will ensure that your new Tag type is registered - * within the tag registry. In most cases, this macro - * is not really needed but, for safety, please, use it all the - * time. - * - * Note: This macro is _absolutely_ needed if you try to run a - * distributed simulation. - */ -#define NS_TAG_ENSURE_REGISTERED(x) \ -namespace { \ -static class thisisaveryverylongclassname \ -{ \ -public: \ - thisisaveryverylongclassname () \ - { uint32_t uid; uid = x::GetUid ();} \ -} g_thisisanotherveryveryverylongname; \ -} - - namespace ns3 { template diff --git a/src/common/trace-context-element.h b/src/common/trace-context-element.h index e27076537..222e92ab9 100644 --- a/src/common/trace-context-element.h +++ b/src/common/trace-context-element.h @@ -6,12 +6,12 @@ #define NS_TRACE_CONTEXT_ELEMENT_ENSURE_REGISTERED(x) \ namespace { \ -static class thisisaveryverylongclassname \ +static class thisisaveryverylongclassname ##x \ { \ public: \ - thisisaveryverylongclassname () \ + thisisaveryverylongclassname ##x () \ { uint32_t uid; uid = x::GetUid ();} \ - } g_thisisanotherveryveryverylongname; \ + } g_thisisanotherveryveryverylongname ##x ; \ } namespace ns3 { diff --git a/src/common/trace-context.h b/src/common/trace-context.h index 560153561..eee3c960c 100644 --- a/src/common/trace-context.h +++ b/src/common/trace-context.h @@ -24,6 +24,7 @@ #include #include #include "ns3/fatal-error.h" +#include "trace-context-element.h" namespace ns3 { @@ -85,7 +86,7 @@ private: template bool SafeGet (T &context) const; template - bool SafeAdd (T &context); + bool SafeAdd (const T &context); uint8_t *CheckPresent (uint8_t uid) const; bool DoAdd (uint8_t uid, uint8_t const *buffer); @@ -106,6 +107,10 @@ template void TraceContext::Add (T const &context) { + const TraceContextElement *parent; + // if the following assignment fails, it is because the input + // to this function is not a subclass of the TraceContextElement class. + parent = &context; uint8_t *data = (uint8_t *) &context; bool ok = DoAdd (T::GetUid (), data); if (!ok) @@ -117,6 +122,10 @@ template void TraceContext::Get (T &context) const { + TraceContextElement *parent; + // if the following assignment fails, it is because the input + // to this function is not a subclass of the TraceContextElement class. + parent = &context; uint8_t *data = (uint8_t *) &context; bool found = DoGet (T::GetUid (), data); if (!found) @@ -128,14 +137,22 @@ template bool TraceContext::SafeGet (T &context) const { + TraceContextElement *parent; + // if the following assignment fails, it is because the input + // to this function is not a subclass of the TraceContextElement class. + parent = &context; uint8_t *data = (uint8_t *) &context; bool found = DoGet (T::GetUid (), data); return found; } template bool -TraceContext::SafeAdd (T &context) +TraceContext::SafeAdd (const T &context) { + const TraceContextElement *parent; + // if the following assignment fails, it is because the input + // to this function is not a subclass of the TraceContextElement class. + parent = &context; uint8_t *data = (uint8_t *) &context; bool ok = DoAdd (T::GetUid (), data); return ok; diff --git a/src/common/trailer.h b/src/common/trailer.h index 77647c3f4..82ffcbad8 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -37,15 +37,13 @@ * Note: This macro is _absolutely_ needed if you try to run a * distributed simulation. */ -#define NS_TRAILER_ENSURE_REGISTERED(x) \ -namespace { \ -static class thisisaveryverylongclassname \ -{ \ -public: \ - thisisaveryverylongclassname () \ - { uint32_t uid; uid = x::GetUid ();} \ -} g_thisisanotherveryveryverylongname; \ -} +#define NS_TRAILER_ENSURE_REGISTERED(x) \ +static class thisisaveryverylongclassname ##x \ +{ \ + public: \ + thisisaveryverylongclassname ##x () \ + { uint32_t uid; uid = x::GetUid ();} \ +} g_thisisanotherveryveryverylongname ##x; namespace ns3 { diff --git a/src/internet-node/arp-header.cc b/src/internet-node/arp-header.cc index 02a7e287d..4fdfe19d7 100644 --- a/src/internet-node/arp-header.cc +++ b/src/internet-node/arp-header.cc @@ -23,10 +23,10 @@ #include "ns3/address-utils.h" #include "arp-header.h" -NS_HEADER_ENSURE_REGISTERED (ns3::ArpHeader); - namespace ns3 { +NS_HEADER_ENSURE_REGISTERED (ArpHeader); + uint32_t ArpHeader::GetUid (void) { diff --git a/src/internet-node/ipv4-header.cc b/src/internet-node/ipv4-header.cc index 891961cda..83750632d 100644 --- a/src/internet-node/ipv4-header.cc +++ b/src/internet-node/ipv4-header.cc @@ -26,10 +26,10 @@ NS_DEBUG_COMPONENT_DEFINE ("Ipv4Header"); -NS_HEADER_ENSURE_REGISTERED (ns3::Ipv4Header); - namespace ns3 { +NS_HEADER_ENSURE_REGISTERED (Ipv4Header); + bool Ipv4Header::m_calcChecksum = false; uint32_t diff --git a/src/internet-node/udp-header.cc b/src/internet-node/udp-header.cc index 6469d046d..96b57beba 100644 --- a/src/internet-node/udp-header.cc +++ b/src/internet-node/udp-header.cc @@ -22,10 +22,10 @@ #include "udp-header.h" #include "ipv4-checksum.h" -NS_HEADER_ENSURE_REGISTERED (ns3::UdpHeader); - namespace ns3 { +NS_HEADER_ENSURE_REGISTERED (UdpHeader); + bool UdpHeader::m_calcChecksum = false; uint32_t diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index fb7629bde..e6bffaf1c 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -27,10 +27,10 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetHeader"); -NS_HEADER_ENSURE_REGISTERED (ns3::EthernetHeader); - namespace ns3 { +NS_HEADER_ENSURE_REGISTERED (EthernetHeader); + uint32_t EthernetHeader::GetUid (void) { diff --git a/src/node/ethernet-trailer.cc b/src/node/ethernet-trailer.cc index dbb27fc2a..6fdb5a845 100644 --- a/src/node/ethernet-trailer.cc +++ b/src/node/ethernet-trailer.cc @@ -26,10 +26,10 @@ NS_DEBUG_COMPONENT_DEFINE ("EthernetTrailer"); -NS_TRAILER_ENSURE_REGISTERED (ns3::EthernetTrailer); - namespace ns3 { +NS_TRAILER_ENSURE_REGISTERED (EthernetTrailer); + bool EthernetTrailer::m_calcFcs = false; uint32_t diff --git a/src/node/llc-snap-header.cc b/src/node/llc-snap-header.cc index 883b4e021..5bcb9714b 100644 --- a/src/node/llc-snap-header.cc +++ b/src/node/llc-snap-header.cc @@ -23,11 +23,10 @@ #include "ns3/assert.h" #include -NS_HEADER_ENSURE_REGISTERED (ns3::LlcSnapHeader); - - namespace ns3 { +NS_HEADER_ENSURE_REGISTERED (LlcSnapHeader); + uint32_t LlcSnapHeader::GetUid (void) { From 7f9545754c2d4bcfa7bae048e291fdd8fe13db76 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:15:45 +0200 Subject: [PATCH 209/278] sample packet tag code --- samples/main-packet-tag.cc | 135 +++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 samples/main-packet-tag.cc diff --git a/samples/main-packet-tag.cc b/samples/main-packet-tag.cc new file mode 100644 index 000000000..3bd1ad2a7 --- /dev/null +++ b/samples/main-packet-tag.cc @@ -0,0 +1,135 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006,2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "ns3/tag.h" +#include "ns3/packet.h" +#include + +using namespace ns3; + +// define this class in a public header +class MyTag : public Tag +{ +public: + // we have to define a public constructor + MyTag (); + // we have to define a public copy constructor + MyTag (const MyTag &other); + // we have to define a public destructor + ~MyTag (); + // we have to define a public static GetUid method + static uint32_t GetUid (void); + // we have to define a public Print method + void Print (std::ostream &os) const; + // we have to define a public GetSerializedSize method + uint32_t GetSerializedSize (void) const; + // we have to define a public Serialize method + void Serialize (Buffer::Iterator i) const; + // we have to define a public Deserialize method + uint32_t Deserialize (Buffer::Iterator i); + + // these are our accessors to our tag structure + void SetSimpleValue (uint8_t value); + uint8_t GetSimpleValue (void) const; +private: + uint8_t m_simpleValue; +}; + +MyTag::MyTag () +{} +MyTag::MyTag (const MyTag &other) + : m_simpleValue (other.m_simpleValue) +{} +MyTag::~MyTag () +{} +uint32_t +MyTag::GetUid (void) +{ + // we input a unique string to AllocateUid + // to avoid name collisions. + static uint32_t uid = AllocateUid ("MyTag.tests.nsnam.org"); + return uid; +} +void +MyTag::Print (std::ostream &os) const +{ + // print the content of this tag for Packet::PrintTags + os << (uint32_t)m_simpleValue; +} +uint32_t +MyTag::GetSerializedSize (void) const +{ + // we do not want to deal with parallel simulations + // so we return 0. + return 0; +} +void +MyTag::Serialize (Buffer::Iterator i) const +{ + // we will never be invoked because we are not doing + // parallel simulations so, we assert. + NS_ASSERT (false); +} +uint32_t +MyTag::Deserialize (Buffer::Iterator i) +{ + // we will never be invoked because we are not doing + // parallel simulations so, we assert. + NS_ASSERT (false); + // theoretically, return the number of bytes read + return 0; +} + + +void +MyTag::SetSimpleValue (uint8_t value) +{ + m_simpleValue = value; +} +uint8_t +MyTag::GetSimpleValue (void) const +{ + return m_simpleValue; +} + + +int main (int argc, char *argv[]) +{ + // create a tag. + MyTag tag; + tag.SetSimpleValue (0x56); + + // store the tag in a packet. + Packet p; + p.AddTag (tag); + + // create a copy of the packet + Packet aCopy = p; + + // read the tag from the packet copy + MyTag tagCopy; + p.PeekTag (tagCopy); + + // the copy and the original are the same ! + NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ()); + + aCopy.PrintTags (std::cout); + + return 0; +} From 1f73d0d258df2081b141b934c236dc35e2b1df8c Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:16:11 +0200 Subject: [PATCH 210/278] remove dead code --- src/common/tags.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/common/tags.h b/src/common/tags.h index 817cb6fa0..ff52a49fe 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -28,9 +28,6 @@ namespace ns3 { -template -class TagPrettyPrinter; - /** * \ingroup constants * \brief Tag maximum size From d6f35d7c5c1750b5b49c37a0d6398519344c54b5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:16:41 +0200 Subject: [PATCH 211/278] make sure we include a space between tag printed output --- src/common/tags.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/tags.cc b/src/common/tags.cc index bcf83b444..635f82b65 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -124,6 +124,10 @@ Tags::Print (std::ostream &os) const for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { TagRegistry::Print (cur->m_id, cur->m_data, os); + if (cur->m_next != 0) + { + os << " "; + } } } From 57464209b8278753d3328acb66da855418b29fc1 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:18:49 +0200 Subject: [PATCH 212/278] update reference to header sample code --- src/common/header.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/header.h b/src/common/header.h index 6ed053641..82d6d4158 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -83,7 +83,7 @@ namespace ns3 { * \endcode * * Sample code which shows how to create a new Header, and how to use it, - * is shown in the sample file samples/main-header.cc + * is shown in the sample file samples/main-packet-header.cc */ class Header { public: From 042f45511396b9117c58e242a2d816fb04d57667 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:19:19 +0200 Subject: [PATCH 213/278] add Packet::PrintTags and move tag documentation to tag.h --- src/common/packet.cc | 6 +++++ src/common/packet.h | 61 ++++++-------------------------------------- 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/src/common/packet.cc b/src/common/packet.cc index d1424a23a..4c1a3b87d 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -125,6 +125,12 @@ Packet::GetUid (void) const return m_metadata.GetUid (); } +void +Packet::PrintTags (std::ostream &os) const +{ + m_tags.Print (os); +} + void Packet::Print (std::ostream &os) const { diff --git a/src/common/packet.h b/src/common/packet.h index f88052ae9..8cda0f294 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -242,6 +242,14 @@ public: */ uint32_t GetUid (void) const; + /** + * \param os output stream in which the data should be printed. + * + * Iterate over the tags present in this packet, and + * invoke the Print method of each tag stored in the packet. + */ + void PrintTags (std::ostream &os) const; + /** * \param os output stream in which the data should be printed. * @@ -315,59 +323,6 @@ private: static uint32_t m_globalUid; }; -/** - * \defgroup tags Packet Tags - * - * A tag is a class which must define: - * - a public default constructor - * - a public static method named GetUid - * - a public method named Print - * - a public method named GetSerializedSize - * - a public method named Serialize - * - a public method named Deserialize - * - * So, a tag class should look like this: - * \code - * // in header file - * // note how a tag class does not derive from any other class. - * class MyTag - * { - * public: - * // we need a public default constructor - * MyTag (); - * // we need a public static GetUid - * // GetUid must return a 32 bit integer which uniquely - * // identifies this tag type - * static uint32_t GetUid (void); - * // Print should record in the output stream - * // the content of the tag instance. - * void Print (std::ostream &os) const; - * // GetSerializedSize should return the number of bytes needed - * // to store the state of a tag instance - * uint32_t GetSerializedSize (void) const; - * // Serialize should store its state in the input - * // buffer with the help of the iterator. It should - * // write exactly size bytes. - * void Serialize (Buffer::Iterator i, uint32_t size) const; - * // Deserialize should restore the state of a Tag instance - * // from a byte buffer with the help of the iterator - * uint32_t Deserialize (Buffer::Iterator i); - * }; - * - * // in source file - * - * NS_TAG_ENSURE_REGISTERED (MyTag); - * - * std::string MyTag::GetUid (void) - * { - * // we really want to make sure that this - * // string is unique in the universe. - * static uint32_t uid = TagRegistry::Register ("MyTag.unique.prefix"); - * return uid; - * } - * \endcode - */ - /** * \defgroup packetperf Packet Performance * The current implementation of the byte buffers and tag list is based From 771bf92f7859bf6b91ccd1ee5c59eb8a2640c421 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:19:39 +0200 Subject: [PATCH 214/278] Tag doxygen documentation --- src/common/tag.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/common/tag.h b/src/common/tag.h index 5046b8886..9a333af8b 100644 --- a/src/common/tag.h +++ b/src/common/tag.h @@ -21,6 +21,9 @@ #ifndef TAG_H #define TAG_H +#include +#include + /** * \relates Tag * \brief this macro should be instantiated exactly once for each @@ -44,9 +47,62 @@ static class thisisaveryverylongclassname ##x \ namespace ns3 { +/** + * \brief a tag can be stored in a packet. + * + * A tag is a blob of 16 bytes of data which can be stored in + * a packet: a packet can contain an arbitrary number of tags + * and these tags are considered as "on-the-side" per-packet + * data structures which are not taken into account when calculating + * the size of the payload of a packet. They exist solely as + * simulation-specific objects. + * + * Tags are typically used to: + * - implement per-packet cross-layer communication + * - implement packet coloring: you could store a "color" tag + * in a packet to mark various types of packet for + * simulation analysis + * + * To create a new type of tag, you must create a subclass + * of the Tag base class which defines: + * - a public default constructor: needed for implementation + * purposes of the Packet code. + * - a public copy constructor: needed to copy a tag into + * a packet tag buffer when the user invokes Packet::AddTag + * - a public destructor: needed to destroy the copy of a tag + * stored in a packet buffer when the user invokes Packet::RemoveTag + * or when the packet is destroyed and the last reference to + * a tag instance disapears. + * - a public static method named GetUid: needed to uniquely + * the type of each tag instance. + * - a public method named Print: needed to print the content + * of a tag when the user calls Packet::PrintTags + * - a public method named GetSerializedSize: needed to serialize + * the content of a tag to a byte buffer when a packet must + * be sent from one computing node to another in a parallel + * simulation. If this method returns 0, it means that the + * tag does not need to be transfered from computing node to + * computing node + * - a public method named Serialize: perform the serialization + * to a byte buffer upon transfer to a new computing node in a + * parallel simulation. + * - a public method named Deserialize: invert the serialization + * from a byte buffer after being transfered to a new computing + * node in a parallel simulation. + * + * A detailed example of what these methods should look like + * and how they should be implemented is described in samples/main-packet-tag.cc + */ class Tag { protected: + /** + * \param name the unique name of the new type of tag + * \returns a newly-allocated uid + * + * This method should be used by subclasses to implement + * their static public GetUid method. + */ template static uint32_t AllocateUid (std::string name); }; From 1242430e2f5d39de4c6062d68411285b8be7ba2e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:20:09 +0200 Subject: [PATCH 215/278] improve print output --- samples/main-packet-tag.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/main-packet-tag.cc b/samples/main-packet-tag.cc index 3bd1ad2a7..a23a8a904 100644 --- a/samples/main-packet-tag.cc +++ b/samples/main-packet-tag.cc @@ -70,7 +70,7 @@ void MyTag::Print (std::ostream &os) const { // print the content of this tag for Packet::PrintTags - os << (uint32_t)m_simpleValue; + os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec; } uint32_t MyTag::GetSerializedSize (void) const @@ -130,6 +130,7 @@ int main (int argc, char *argv[]) NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ()); aCopy.PrintTags (std::cout); + std::cout << std::endl; return 0; } From 1bd35c2b55a93d68f7b015205b1ae4e80545e994 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:20:35 +0200 Subject: [PATCH 216/278] make sure udp-header.h is exported for main-packet-printer --- src/internet-node/wscript | 1 + 1 file changed, 1 insertion(+) diff --git a/src/internet-node/wscript b/src/internet-node/wscript index e0af13434..8a34a6963 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -37,4 +37,5 @@ def build(bld): 'ascii-trace.h', 'pcap-trace.h', 'ipv4-header.h', + 'udp-header.h', ] From b5f68770a386ec38f878f78630f475196d28e584 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:20:49 +0200 Subject: [PATCH 217/278] move header sample and build tag sample --- samples/{main-header.cc => main-packet-header.cc} | 0 samples/wscript | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) rename samples/{main-header.cc => main-packet-header.cc} (100%) diff --git a/samples/main-header.cc b/samples/main-packet-header.cc similarity index 100% rename from samples/main-header.cc rename to samples/main-packet-header.cc diff --git a/samples/wscript b/samples/wscript index eb4e4f208..d11a6462d 100644 --- a/samples/wscript +++ b/samples/wscript @@ -14,7 +14,10 @@ def build(bld): obj = create_ns_prog('main-ptr', 'main-ptr.cc') #obj = create_ns_prog('main-trace', 'main-trace.cc') obj = create_ns_prog('main-simulator', 'main-simulator.cc') - obj = create_ns_prog('main-header', 'main-header.cc') + obj = create_ns_prog('main-packet-header', 'main-packet-header.cc') + obj = create_ns_prog('main-packet-tag', 'main-packet-tag.cc') + obj = create_ns_prog('main-packet-printer', 'main-packet-printer.cc', + deps=['node', 'internet-node']) obj = create_ns_prog('main-test', 'main-test.cc') obj = create_ns_prog('main-simple', 'main-simple.cc', deps=['node', 'internet-node', 'applications']) From d3672ded33bb8c42551b3ee3356698c356108153 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 11:27:17 +0200 Subject: [PATCH 218/278] beautify packet API doxygen --- src/common/packet.h | 47 +++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/common/packet.h b/src/common/packet.h index 8cda0f294..686d850f9 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -63,15 +63,11 @@ class PacketPrinter; * * Implementing a new type of Header or Trailer for a new protocol is * pretty easy and is a matter of creating a subclass of the ns3::Header - * or of the ns3::Trailer base class, and implementing the 5 pure virtual - * methods defined in either of the two base classes. Users _must_ - * also make sure that they class defines a public default constructor and - * a public method named GetUid, as documented in the ns3::Header and ns::Trailer - * API documentations. + * or of the ns3::Trailer base class, and implementing the methods + * described in their respective API documentation. * * Implementing a new type of Tag requires roughly the same amount of - * work: users must implement a total of 6 methods which are described in - * \ref tags + * work and this work is described in the ns3::Tag API documentation. * * The performance aspects of the Packet API are discussed in * \ref packetperf @@ -119,7 +115,7 @@ public: uint32_t GetSize (void) const; /** * Add header to this packet. This method invokes the - * ns3::Header::GetSerializedSize and ns3::Header::SerializeTo + * GetSerializedSize and Serialize * methods to reserve space in the buffer and request the * header to serialize itself in the packet buffer. * @@ -129,7 +125,7 @@ public: void AddHeader (T const &header); /** * Deserialize and remove the header from the internal buffer. - * This method invokes ns3::Header::DeserializeFrom. + * This method invokes Deserialize. * * \param header a reference to the header to remove from the internal buffer. * \returns the number of bytes removed from the packet. @@ -138,7 +134,7 @@ public: uint32_t RemoveHeader (T &header); /** * Add trailer to this packet. This method invokes the - * ns3::Trailer::GetSerializedSize and ns3::Trailer::serializeTo + * GetSerializedSize and Serialize * methods to reserve space in the buffer and request the trailer * to serialize itself in the packet buffer. * @@ -148,7 +144,7 @@ public: void AddTrailer (T const &trailer); /** * Remove a deserialized trailer from the internal buffer. - * This method invokes the ns3::Trailer::DeserializeFrom method. + * This method invokes the Deserialize method. * * \param trailer a reference to the trailer to remove from the internal buffer. * \returns the number of bytes removed from the end of the packet. @@ -158,7 +154,8 @@ public: /** * Attach a tag to this packet. The tag is fully copied * in a packet-specific internal buffer. This operation - * is expected to be really fast. + * is expected to be really fast. The copy constructor of the + * tag is invoked to copy it into the tag buffer. * * \param tag a pointer to the tag to attach to this packet. */ @@ -185,6 +182,8 @@ public: /** * Copy a tag stored internally to the input tag. If no instance * of this tag is present internally, the input tag is not modified. + * The copy constructor of the tag is invoked to copy it into the + * input tag variable. * * \param tag a pointer to the tag to read from this packet * \returns true if an instance of this tag type is stored @@ -197,6 +196,14 @@ public: * much much faster than invoking removeTag n times. */ void RemoveAllTags (void); + /** + * \param os output stream in which the data should be printed. + * + * Iterate over the tags present in this packet, and + * invoke the Print method of each tag stored in the packet. + */ + void PrintTags (std::ostream &os) const; + /** * Concatenate the input packet at the end of the current * packet. This does not alter the uid of either packet. @@ -242,14 +249,6 @@ public: */ uint32_t GetUid (void) const; - /** - * \param os output stream in which the data should be printed. - * - * Iterate over the tags present in this packet, and - * invoke the Print method of each tag stored in the packet. - */ - void PrintTags (std::ostream &os) const; - /** * \param os output stream in which the data should be printed. * @@ -298,6 +297,9 @@ public: * serialized representation contains a copy of the packet byte buffer, * the tag list, and the packet metadata (if there is one). * + * This method will trigger calls to the Serialize and GetSerializedSize + * methods of each tag stored in this packet. + * * This method will typically be used by parallel simulations where * the simulated system is partitioned and each partition runs on * a different CPU. @@ -307,9 +309,12 @@ public: * \param a byte buffer * * This method reads a byte buffer as created by Packet::Serialize - * and restores the state of the Packet to what it was prio to + * and restores the state of the Packet to what it was prior to * calling Serialize. * + * This method will trigger calls to the Deserialize method + * of each tag stored in this packet. + * * This method will typically be used by parallel simulations where * the simulated system is partitioned and each partition runs on * a different CPU. From 635374075f4bd9706a051cdc1d4950162eb25dd5 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 12:18:11 +0200 Subject: [PATCH 219/278] re-write header and trailer doxygen API doc --- src/common/header.h | 124 +++++++++++----------------------- src/common/trailer.h | 154 ++++++++++++------------------------------- 2 files changed, 80 insertions(+), 198 deletions(-) diff --git a/src/common/header.h b/src/common/header.h index 82d6d4158..64c87f981 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -51,97 +51,51 @@ namespace ns3 { * \brief Protocol header serialization and deserialization. * * Every Protocol header which needs to be inserted or removed - * from a Packet instance must derive from this abstract base class - * and implement the private pure virtual methods listed below: - * - ns3::Header::SerializeTo - * - ns3::Header::DeserializeFrom - * - ns3::Header::GetSerializedSize - * - ns3::Header::PrintTo - * - ns3::Header::DoGetName + * from a Packet instance must derive from this base class and + * implement the following public methods: + * - a default constructor: is used by the internal implementation + * if the Packet class. + * - a static method named GetUid: is used to uniquely identify + * the type of each header. This method shall return a unique + * integer allocated with Header::AllocateUid. + * - a method named Serialize: is used by Packet::AddHeader to + * store a header into the byte buffer of a packet. + * The input iterator points to the start of the byte buffer in + * which the header should write its data. The data written + * is expected to match bit-for-bit the representation of this + * header in a real network. + * - a method named GetSerializedSize: is used by Packet::AddHeader + * to store a header into the byte buffer of a packet. This method + * should return the number of bytes which are needed to store + * the full header data by Serialize. + * - a method named Deserialize: is used by Packet::RemoveHeader to + * re-create a header from the byte buffer of a packet. The input + * iterator points to the start of the byte buffer from which + * the header should read its data. The data read is expected to + * match bit-for-bit the representation of this header in real + * networks. This method shall return an integer which identifies + * the number of bytes read. + * - a method named Print: is used by Packet::Print to print the + * content of a header as ascii data to a c++ output stream. + * Although the header is free to format its output as it + * wishes, it is recommended to follow a few rules to integrate + * with the packet pretty printer: start with flags, small field + * values located between a pair of parens. Values should be separated + * by whitespace. Follow the parens with the important fields, + * separated by whitespace. + * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5 + * - a method named GetName: is used by Packet::Print to print + * header fragments. This method should return a user-readable + * single word as all capitalized letters. * - * Each header must also make sure that: - * - it defines a public default constructor - * - it defines a public static method named GetUid which returns a 32 bit integer - * - * The latter should look like the following: - * \code - * // in the header, - * class MyHeader : public Header - * { - * public: - * static uint32_t GetUid (void); - * }; - * - * // in the source file: - * NS_HEADER_ENSURE_REGISTERED (MyHeader); - * - * uint32_t MyHeader::GetUid (void) - * { - * static uint32_t uid = Header::Register ("MyHeader.unique.prefix"); - * return uid; - * } - * \endcode - * - * Sample code which shows how to create a new Header, and how to use it, + * Sample code which shows how to create a new type of Header, and how to use it, * is shown in the sample file samples/main-packet-header.cc */ -class Header { -public: +class Header +{ protected: template static uint32_t AllocateUid (std::string uuid); -#if 0 -private: - /** - * \returns a user-readable name to identify this type of header. - * - * The string returned is expected to be a single word with - * all capital letters - */ - virtual std::string DoGetName (void) const = 0; - /** - * \param os the std output stream in which this - * protocol header must print itself. - * - * Although the header is free to format its output as it - * wishes, it is recommended to follow a few rules to integrate - * with the packet pretty printer: - * - start with flags, small field values located between a - * pair of parens. Values should be separated by whitespace. - * - follow the parens with the important fields, separated by - * whitespace. - * i.e.: - * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5 - */ - virtual void PrintTo (std::ostream &os) const = 0; - - /** - * \returns the size of the serialized Header. - * - * This method is used by Packet::AddHeader to reserve - * enough room in the packet byte buffer prior to calling - * Header::Serialize. - */ - virtual uint32_t GetSerializedSize (void) const = 0; - - /** - * \param start the buffer iterator in which the protocol header - * must serialize itself. This iterator identifies - * the start of the buffer. - */ - virtual void SerializeTo (Buffer::Iterator start) const = 0; - /** - * \param start the buffer iterator from which the protocol header must - * deserialize itself. This iterator identifies - * the start of the buffer. - * \returns the number of bytes read from the buffer - * - * The value returned is used to trim the packet byte buffer of the - * corresponding amount when this method is invoked from - * Packet::RemoveHeader - */ - virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0; -#endif }; } // namespace ns3 diff --git a/src/common/trailer.h b/src/common/trailer.h index 82ffcbad8..9b34d255f 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -51,124 +51,52 @@ namespace ns3 { * \brief Protocol trailer serialization and deserialization. * * Every Protocol trailer which needs to be inserted or removed - * from a Packet instance must derive from this abstract base class - * and implement the private pure virtual methods listed below: - * - ns3::Trailer::SerializeTo - * - ns3::Trailer::DeserializeFrom - * - ns3::Trailer::GetSerializedSize - * - ns3::Trailer::PrintTo - * - ns3::Trailer::DoGetName + * from a Packet instance must derive from this base class and + * implement the following public methods: + * - a default constructor: is used by the internal implementation + * if the Packet class. + * - a static method named GetUid: is used to uniquely identify + * the type of each trailer. This method shall return a unique + * integer allocated with Trailer::AllocateUid. + * - a method named Serialize: is used by Packet::AddTrailer to + * store a trailer into the byte buffer of a packet. + * The input iterator points to the end of the byte buffer in + * which the trailer should write its data: the user is thus + * required to call Buffer::Iterator::Prev prior to writing + * any data in the buffer. The data written is expected to + * match bit-for-bit the representation of this trailer in a + * real network. + * - a method named GetSerializedSize: is used by Packet::AddTrailer + * to store a trailer into the byte buffer of a packet. This method + * should return the number of bytes which are needed to store + * the full trailer data by Serialize. + * - a method named Deserialize: is used by Packet::RemoveTrailer to + * re-create a trailer from the byte buffer of a packet. The input + * iterator points to the end of the byte buffer from which + * the trailer should read its data: the user is thus required to + * call Buffer::Iterator::Prev prior to reading any data from the + * buffer. The data read is expected to match bit-for-bit the + * representation of this trailer in real networks. This method + * shall return an integer which identifies the number of bytes read. + * - a method named Print: is used by Packet::Print to print the + * content of a trailer as ascii data to a c++ output stream. + * Although the trailer is free to format its output as it + * wishes, it is recommended to follow a few rules to integrate + * with the packet pretty printer: start with flags, small field + * values located between a pair of parens. Values should be separated + * by whitespace. Follow the parens with the important fields, + * separated by whitespace. + * i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5 + * - a method named GetName: is used by Packet::Print to print + * trailer fragments. This method should return a user-readable + * single word as all capitalized letters. * - * Each trailer must also make sure that: - * - it defines a public default constructor - * - it defines a public static method named GetUid which returns a 32 bit integer. - * - * The latter should look like the following: - * \code - * // in the header - * class MyTrailer : public Header - * { - * public: - * static uint32_t GetUid (void); - * }; - * - * // in the source file - * NS_TRAILER_ENSURE_REGISTERED (MyTrailer); - * - * uint32_t MyTrailer::GetUid (void) - * { - * static uint32_t uid = Trailer::Register ("MyTrailer.unique.prefix"); - * return uid; - * } - * \endcode - * - * Note that the SerializeTo and DeserializeFrom methods behave - * in a way which might seem surprising to users: the input iterator - * really points to the end of the buffer to which and from which - * the user is expected to write and read respectively. This means that - * if the trailer has a fixed size and if the user wishes to read or - * write that trailer from front to back, the user must rewind the - * iterator by hand to go to the start of the trailer. Typical code - * looks like this: - * \code - * void CrcTrailer::SerializeTo (Buffer::Iterator end) - * { - * end.Prev (4); - * end.WriteHtonU32 (m_crc); - * } - * \endcode - * - * Some users would have expected that the iterator would be rewinded - * to the "start" of the trailer before calling SerializeTo and DeserializeFrom. - * However, this behavior was not implemented because it cannot be made to - * work reliably for trailers which have a variable size. i.e., if the trailer - * contains options, the code which calls DeserializeFrom cannot rewind - * to the start of the trailer because it does not know the real size of the - * trailer. Hence, to make this legitimate use-case work (variable-sized - * trailers), the input iterator to DeserializeFrom and SerializeTo points - * to the end of the trailer, and not its start. */ -class Trailer { -public: +class Trailer +{ protected: template static uint32_t AllocateUid (std::string uidString); -#if 0 -private: - /** - * \returns a user-readable name to identify this type of header. - * - * The string returned is expected to be a single word with - * all capital letters - */ - virtual std::string DoGetName (void) const = 0; - /** - * \param os the std output stream in which this - * protocol trailer must print itself. - * - * Although the header is free to format its output as it - * wishes, it is recommended to follow a few rules to integrate - * with the packet pretty printer: - * - start with flags, small field values located between a - * pair of parens. Values should be separated by whitespace. - * - follow the parens with the important fields, separated by - * whitespace. - * i.e.: - * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5 - */ - virtual void PrintTo (std::ostream &os) const = 0; - - /** - * \returns the size of the serialized Trailer. - * - * This method is used by Packet::AddTrailer to reserve - * enough room in the packet byte buffer prior to calling - * Trailer::Serialize. - */ - virtual uint32_t GetSerializedSize (void) const = 0; - - /** - * \param end the buffer iterator in which the protocol trailer - * must serialize itself. This iterator identifies - * the end of the buffer. - * - * This iterator must be typically moved with the Buffer::Iterator::Prev - * method before writing any byte in the buffer. - */ - virtual void SerializeTo (Buffer::Iterator end) const = 0; - /** - * \param end the buffer iterator from which the protocol trailer must - * deserialize itself. This iterator identifies - * the end of the buffer. - * \returns the number of bytes read from the buffer - * - * This iterator must be typically moved with the Buffer::Iterator::Prev - * method before reading any byte in the buffer. The value returned - * is used to trim the packet byte buffer of the corresponding - * amount when this method is invoked from Packet::RemoveTrailer - */ - virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0; -#endif }; } // namespace ns3 From 7ad0b274606961a532ffb3894e91f2805604fd66 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 12:33:14 +0200 Subject: [PATCH 220/278] revert part of gustavo's patch for 'better breakpoints' --- src/core/assert.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/core/assert.h b/src/core/assert.h index eb0b6e028..8dc935cdb 100644 --- a/src/core/assert.h +++ b/src/core/assert.h @@ -27,6 +27,17 @@ #include "breakpoint.h" +/** + * \defgroup assert Assert + * \brief assert functions and macros + * + * The assert macros are used to verify + * at runtime that a certain condition is true. If it is + * not true, the program halts. These checks are built + * into the program only in debugging builds. They are + * removed in optimized builds. + */ + /** * \ingroup assert * \param condition condition to verifiy. From aceebd88bbb73a6cb917be913786041dc8c3196d Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 12:33:33 +0200 Subject: [PATCH 221/278] fix dox warning --- src/common/packet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/packet.h b/src/common/packet.h index 686d850f9..00c540600 100644 --- a/src/common/packet.h +++ b/src/common/packet.h @@ -306,7 +306,7 @@ public: */ Buffer Serialize (void) const; /** - * \param a byte buffer + * \param buffer a byte buffer * * This method reads a byte buffer as created by Packet::Serialize * and restores the state of the Packet to what it was prior to From 32cd28829aa39934f338e5b406ada642b1b2a6f1 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 12:34:18 +0200 Subject: [PATCH 222/278] fix dox warning --- src/core/callback.h | 2 +- src/core/random-variable.h | 1 + src/node/ipv4-address.h | 2 +- src/simulator/scheduler.h | 9 +++------ 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/callback.h b/src/core/callback.h index 79597cca0..94e58ca92 100644 --- a/src/core/callback.h +++ b/src/core/callback.h @@ -358,7 +358,7 @@ private: /** * \ingroup MakeCallback - * \param mem_ptr class method member pointer + * \param memPtr class method member pointer * \param objPtr class instance * \return a wrapper Callback * Build Callbacks for class method members which takes no arguments diff --git a/src/core/random-variable.h b/src/core/random-variable.h index 7759ea157..ce4cebd4d 100644 --- a/src/core/random-variable.h +++ b/src/core/random-variable.h @@ -772,6 +772,7 @@ public: /** * \param s Low end of the range * \param l High end of the range + * \param mean mean of the distribution * \return A triangularly distributed random number between s and l */ static double GetSingleValue(double s, double l, double mean); diff --git a/src/node/ipv4-address.h b/src/node/ipv4-address.h index 8bf91f5c9..6589edcf9 100644 --- a/src/node/ipv4-address.h +++ b/src/node/ipv4-address.h @@ -116,7 +116,7 @@ public: * (bitwise and) with a network mask, yielding an IPv4 network * address. * - * \param a network mask + * \param mask a network mask */ Ipv4Address CombineMask (Ipv4Mask const &mask) const; diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index 33917a870..d8dea8672 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -58,9 +58,7 @@ class Scheduler { virtual ~Scheduler () = 0; /** - * \param event event to store in the event list - * \param key timecode associated to this new event - * \returns an event id which identifies the event inserted + * \param id event to store in the event list * * This method takes ownership of the event pointer. */ @@ -83,9 +81,8 @@ class Scheduler { virtual EventId RemoveNext (void) = 0; /** * \param id the id of the event to remove - * \param key the timecode of the event removed - * \returns a pointer to the event removed. The caller - * takes ownership of the returned pointer. + * \returns true if the id was found and removed + * successfully, false otherwise. * * This methods cannot be invoked if the list is empty. */ From 6ae06014c57e62c64851f00970bdc011dd478d54 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 12:51:12 +0200 Subject: [PATCH 223/278] fix dox warning --- src/core/component-manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/component-manager.h b/src/core/component-manager.h index ccecc4b15..fc2929eac 100644 --- a/src/core/component-manager.h +++ b/src/core/component-manager.h @@ -348,7 +348,7 @@ public: * result. */ template - static Ptr Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5); + static Ptr Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); private: friend void RegisterCallback (ClassId classId, CallbackBase *callback, From 9b33c46995f4155d3dd2fb8b29660f041bd3258a Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 12:54:21 +0200 Subject: [PATCH 224/278] make sure assert macros are documented --- doc/doxygen.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen.conf b/doc/doxygen.conf index a8b337f0a..fc6fd25fa 100644 --- a/doc/doxygen.conf +++ b/doc/doxygen.conf @@ -999,7 +999,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE +PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE NS3_ASSERT_ENABLE # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. From 4b8e9cf7d17665f87e7757352e5a474e23236947 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 13:13:09 +0200 Subject: [PATCH 225/278] use full reference for \relates tag --- src/common/header.h | 4 ++-- src/common/tag.h | 2 +- src/common/trailer.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/header.h b/src/common/header.h index 64c87f981..c983dd18d 100644 --- a/src/common/header.h +++ b/src/common/header.h @@ -25,7 +25,7 @@ #include "chunk-registry.h" /** - * \relates Header + * \relates ns3::Header * \brief this macro should be instantiated exactly once for each * new type of Header * @@ -45,6 +45,7 @@ static class thisisaveryverylongclassname ##x \ { uint32_t uid; uid = x::GetUid ();} \ } g_thisisanotherveryveryverylongname ## x; + namespace ns3 { /** @@ -109,7 +110,6 @@ Header::AllocateUid (std::string uuid) return ChunkRegistry::RegisterHeader (uuid); } - } // namespace ns3 #endif /* HEADER_H */ diff --git a/src/common/tag.h b/src/common/tag.h index 9a333af8b..f85e797ab 100644 --- a/src/common/tag.h +++ b/src/common/tag.h @@ -25,7 +25,7 @@ #include /** - * \relates Tag + * \relates ns3::Tag * \brief this macro should be instantiated exactly once for each * new type of Tag * diff --git a/src/common/trailer.h b/src/common/trailer.h index 9b34d255f..5311d8910 100644 --- a/src/common/trailer.h +++ b/src/common/trailer.h @@ -25,7 +25,7 @@ #include "chunk-registry.h" /** - * \relates Trailer + * \relates ns3::Trailer * \brief this macro should be instantiated exactly once for each * new type of Trailer * From 9cb258d9200e928d445d746d042e9d5aa673fa70 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 13:13:24 +0200 Subject: [PATCH 226/278] doxygen API documentation for TraceContextElement base class --- src/common/trace-context-element.h | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/common/trace-context-element.h b/src/common/trace-context-element.h index 222e92ab9..e1c36c4d9 100644 --- a/src/common/trace-context-element.h +++ b/src/common/trace-context-element.h @@ -16,9 +16,85 @@ static class thisisaveryverylongclassname ##x \ namespace ns3 { +/** + * \brief an item stored in a TraceContext + * + * To store trace context information in a TraceContext instance, + * users must subclass this base class and store subclass instances + * in a TraceContext with TraceContext::Add. + * + * Each subclass should define and implement: + * - a public default constructor: it is used by the internals + * of the implementation of TraceContext. + * - a public destructor: it is also used by the internals of + * the implementation of TraceContext. + * - a public static method named GetUid which returns a 16 bit + * integer. The integer returned from this method should be + * allocated with the protected AllocatedUid method. + * - a public Print method: this method is used by the + * TraceContext::Print method to print the content of each + * of the trace context element stored in the trace context. + * This method takes a c++ output stream and argument and is + * expected to write an ascii string describing its content + * in this output stream. + * + * A typical subclass should look like this: + * \code + * class MyContext : public TraceContextElement + * { + * public: + * // the _required_ public API + * static uint16_t GetUid (void); + * MyContext (); + * ~MyContext (); + * void Print (std::ostream &os) const; + * + * // the user-specific API to manipulate the context. + * void SetData (uint8_t data); + * uint8_t GetData (void) const; + * private: + * uint8_t m_myContextData; + * }; + * + * uint16_t + * MyContext::GetUid (void) + * { + * static uint16_t uid = AllocateUid ("MyContext"); + * return uid; + * } + * MyContext::MyContext () + * {} + * MyContext::~MyContext () + * {} + * void + * MyContext::Print (std::ostream &os) const + * { + * os << "mycontext=" << (uint32_t) m_myContextData; + * } + * void + * MyContext::SetData (uint8_t data) + * { + * m_myContextData = data; + * } + * uint8_t + * MyContext::GetData (void) const + * { + * return m_myContextData; + * } + * \endcode + */ class TraceContextElement { protected: + /** + * \param name a string which uniquely identifies the type + * of the subclass which is calling this method. + * \returns a unique 32 bit integer associated to the + * input string. + * + * Subclasses are expected to call this method from their + * public static GetUid method. + */ template static uint16_t AllocateUid (std::string name); }; From f302d055e9622e0e811ff8f8dc56ec14e5d37313 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 8 Aug 2007 12:36:59 +0100 Subject: [PATCH 227/278] WAF: handle --doxygen before building; now only generates docs and does not build anything. --- src/wscript | 9 ++++++++- wscript | 7 ++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/wscript b/src/wscript index aa57364be..ad3a80d59 100644 --- a/src/wscript +++ b/src/wscript @@ -47,11 +47,18 @@ def configure(conf): ## Used to link the 'run-tests' program with all of ns-3 code conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] - +def create_ns3_module(bld, name, dependencies=()): + module = bld.create_obj('cpp', 'shlib') + module.name = 'ns3-' + name + module.target = module.name + module.uselib_local = ['ns3-' + dep for dep in dependencies] + return module + def build(bld): Object.register('ns3header', Ns3Header) Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE') + bld.create_ns3_module = create_ns3_module bld.add_subdirs(list(all_modules)) diff --git a/wscript b/wscript index e91740cbe..2241433dd 100644 --- a/wscript +++ b/wscript @@ -144,6 +144,10 @@ def build(bld): run_shell() raise SystemExit(0) + if Params.g_options.doxygen: + doxygen() + raise SystemExit(0) + check_shell() # process subfolders from here @@ -166,9 +170,6 @@ def shutdown(): if Params.g_options.lcov_report: lcov_report() - if Params.g_options.doxygen: - doxygen() - if Params.g_options.run: run_program(Params.g_options.run, Params.g_options.command_template) raise SystemExit(0) From a34d15da0198eb9e91a0f909bb9f2e737c5cd24b Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 8 Aug 2007 14:11:29 +0100 Subject: [PATCH 228/278] Revert experimental code in src/wscript accidentally committed. --- src/wscript | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/wscript b/src/wscript index ad3a80d59..092c7f4c8 100644 --- a/src/wscript +++ b/src/wscript @@ -47,18 +47,10 @@ def configure(conf): ## Used to link the 'run-tests' program with all of ns-3 code conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] -def create_ns3_module(bld, name, dependencies=()): - module = bld.create_obj('cpp', 'shlib') - module.name = 'ns3-' + name - module.target = module.name - module.uselib_local = ['ns3-' + dep for dep in dependencies] - return module - def build(bld): Object.register('ns3header', Ns3Header) Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE') - bld.create_ns3_module = create_ns3_module bld.add_subdirs(list(all_modules)) From d668f7749f0e77a3e67fd080cb34f407c64d69ec Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 15:43:05 +0200 Subject: [PATCH 229/278] use NS_TEST_ASSERT macros --- src/core/default-value.cc | 104 ++++++++------------------------------ 1 file changed, 22 insertions(+), 82 deletions(-) diff --git a/src/core/default-value.cc b/src/core/default-value.cc index 9fad9b6b2..0569a2b18 100644 --- a/src/core/default-value.cc +++ b/src/core/default-value.cc @@ -341,84 +341,39 @@ DefaultValueTest::DefaultValueTest () bool DefaultValueTest::RunTests (void) { - bool ok = true; + bool result = true; BooleanDefaultValue a ("bool-a", "help a", true); - if (!a.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (a.GetValue ()); Bind ("bool-a", "false"); - if (a.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (!a.GetValue ()); BooleanDefaultValue b ("bool-b", "help b", false); Bind ("bool-b", "true"); - if (!b.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (b.GetValue ()); Bind ("bool-b", "0"); - if (b.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (!b.GetValue ()); Bind ("bool-b", "1"); - if (!b.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (b.GetValue ()); Bind ("bool-b", "f"); - if (b.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (!b.GetValue ()); Bind ("bool-b", "t"); - if (!b.GetValue ()) - { - ok = false; - } + NS_TEST_ASSERT (b.GetValue ()); Bind ("bool-b", "false"); - if (b.GetValue ()) - { - ok = false; - } - if (BindSafe ("bool-b", "tr") != INVALID_VALUE) - { - ok = false; - } + NS_TEST_ASSERT (!b.GetValue ()); + NS_TEST_ASSERT_EQUAL (BindSafe ("bool-b", "tr"), INVALID_VALUE) NumericDefaultValue i ("test-i", "help-i", -1); - if (i.GetValue () != -1) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (i.GetValue (), -1); Bind ("test-i", "-2"); - if (i.GetValue () != -2) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (i.GetValue (), -2); Bind ("test-i", "+2"); - if (i.GetValue () != 2) - { - ok = false; - } - if (i.GetType () != "int32_t(-2147483648:2147483647)") - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (i.GetValue (), 2); + NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)"); NumericDefaultValue ui32 ("test-ui32", "help-ui32", 10); - if (ui32.GetType () != "uint32_t(0:4294967295)") - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)"); NumericDefaultValue c ("test-c", "help-c", 10); - if (c.GetValue () != 10) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (c.GetValue (), 10); Bind ("test-c", "257"); NumericDefaultValue x ("test-x", "help-x", 10.0); NumericDefaultValue y ("test-y", "help-y", 10.0); @@ -429,19 +384,10 @@ DefaultValueTest::RunTests (void) MY_ENUM_A, "A", MY_ENUM_B, "B", 0, (void*)0); - if (e.GetValue () != MY_ENUM_C) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C); Bind ("test-e", "B"); - if (e.GetValue () != MY_ENUM_B) - { - ok = false; - } - if (BindSafe ("test-e", "D") != INVALID_VALUE) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B); + NS_TEST_ASSERT_EQUAL (BindSafe ("test-e", "D"), INVALID_VALUE); class MyEnumSubclass : public EnumDefaultValue { @@ -456,15 +402,9 @@ DefaultValueTest::RunTests (void) AddPossibleValue (MY_ENUM_D, "D"); } } e1 ; - if (e1.GetValue () != MY_ENUM_B) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B); Bind ("test-e1", "D"); - if (e1.GetValue () != MY_ENUM_D) - { - ok = false; - } + NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D); DefaultValueList::Remove ("test-e1"); DefaultValueList::Remove ("test-e"); @@ -474,7 +414,7 @@ DefaultValueTest::RunTests (void) DefaultValueList::Remove ("test-c"); DefaultValueList::Remove ("test-ui32"); - return ok; + return result; } static DefaultValueTest g_default_value_tests; From f346815b18e9b108031fbf9a72793d93d2f228ee Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 15:59:08 +0200 Subject: [PATCH 230/278] use fixed-width types to avoid portability problems --- src/core/default-value.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/default-value.cc b/src/core/default-value.cc index 0569a2b18..c9f2f6db4 100644 --- a/src/core/default-value.cc +++ b/src/core/default-value.cc @@ -363,7 +363,7 @@ DefaultValueTest::RunTests (void) NS_TEST_ASSERT (!b.GetValue ()); NS_TEST_ASSERT_EQUAL (BindSafe ("bool-b", "tr"), INVALID_VALUE) - NumericDefaultValue i ("test-i", "help-i", -1); + NumericDefaultValue i ("test-i", "help-i", -1); NS_TEST_ASSERT_EQUAL (i.GetValue (), -1); Bind ("test-i", "-2"); NS_TEST_ASSERT_EQUAL (i.GetValue (), -2); @@ -372,7 +372,7 @@ DefaultValueTest::RunTests (void) NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)"); NumericDefaultValue ui32 ("test-ui32", "help-ui32", 10); NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)"); - NumericDefaultValue c ("test-c", "help-c", 10); + NumericDefaultValue c ("test-c", "help-c", 10); NS_TEST_ASSERT_EQUAL (c.GetValue (), 10); Bind ("test-c", "257"); NumericDefaultValue x ("test-x", "help-x", 10.0); From 0eca73234a22c72fe39246e89be458b70fa5122a Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 8 Aug 2007 15:10:36 +0100 Subject: [PATCH 231/278] WAF: add new bld.create_ns3_module() and bld.create_ns3_program() methods to make declaration of modules and programs simpler, and allowing us to change how ns-3 is built in a centralized way, without needing to change every module wscript file. --- examples/wscript | 26 +++++++------- samples/wscript | 57 +++++++++++++++++------------- src/applications/wscript | 5 +-- src/common/wscript | 5 +-- src/core/wscript | 4 +-- src/devices/csma-cd/wscript | 5 +-- src/devices/point-to-point/wscript | 5 +-- src/internet-node/wscript | 5 +-- src/mobility/wscript | 5 +-- src/node/wscript | 5 +-- src/routing/global-routing/wscript | 5 +-- src/simulator/wscript | 6 +--- src/wscript | 9 +++++ utils/wscript | 17 ++++----- wscript | 15 ++++++-- 15 files changed, 83 insertions(+), 91 deletions(-) diff --git a/examples/wscript b/examples/wscript index 71efc3a9e..93e8f83d6 100644 --- a/examples/wscript +++ b/examples/wscript @@ -1,19 +1,17 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -import Params def build(bld): - def create_ns_prog(name, source, deps=['core', 'common', 'simulator']): - obj = bld.create_obj('cpp', 'program') - obj.target = name - obj.uselib_local = ["ns3-%s" % dep for dep in deps] - obj.source = source - return obj - obj = create_ns_prog('simple-global-routing', 'simple-global-routing.cc', - deps=['point-to-point', 'internet-node', 'global-routing']) - obj = create_ns_prog('simple-point-to-point', 'simple-point-to-point.cc', - deps=['point-to-point', 'internet-node']) - obj = create_ns_prog('csma-cd-one-subnet', 'csma-cd-one-subnet.cc', - deps=['csma-cd', 'internet-node']) - obj = create_ns_prog('csma-cd-packet-socket', 'csma-cd-packet-socket.cc', deps=['csma-cd', 'internet-node']) + obj = bld.create_ns3_program('simple-global-routing', + ['point-to-point', 'internet-node', 'global-routing']) + obj.source = 'simple-global-routing.cc' + + obj = bld.create_ns3_program('simple-point-to-point', ['point-to-point', 'internet-node']) + obj.source = 'simple-point-to-point.cc' + + obj = bld.create_ns3_program('csma-cd-one-subnet', ['csma-cd', 'internet-node']) + obj.source = 'csma-cd-one-subnet.cc' + + obj = bld.create_ns3_program('csma-cd-packet-socket', ['csma-cd', 'internet-node']) + obj.source = 'csma-cd-packet-socket.cc' diff --git a/samples/wscript b/samples/wscript index eb4e4f208..0ac6004e1 100644 --- a/samples/wscript +++ b/samples/wscript @@ -1,28 +1,37 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- -import Params def build(bld): - def create_ns_prog(name, source, deps=['core', 'common', 'simulator']): - obj = bld.create_obj('cpp', 'program') - obj.target = name - obj.uselib_local = ["ns3-%s" % dep for dep in deps] - obj.source = source - return obj - - obj = create_ns_prog('main-debug', ['main-debug.cc', 'main-debug-other.cc']) - obj = create_ns_prog('main-callback', 'main-callback.cc') - obj = create_ns_prog('main-ptr', 'main-ptr.cc') - #obj = create_ns_prog('main-trace', 'main-trace.cc') - obj = create_ns_prog('main-simulator', 'main-simulator.cc') - obj = create_ns_prog('main-header', 'main-header.cc') - obj = create_ns_prog('main-test', 'main-test.cc') - obj = create_ns_prog('main-simple', 'main-simple.cc', - deps=['node', 'internet-node', 'applications']) - #obj = create_ns_prog('main-simple-p2p', 'main-simple-p2p.cc', deps=['node', 'point-to-point']) - obj = create_ns_prog('main-default-value', 'main-default-value.cc', - deps=['core', 'simulator', 'node', 'point-to-point']) - obj = create_ns_prog('main-grid-topology', 'main-grid-topology.cc', - deps=['core', 'simulator', 'mobility', 'internet-node']) - obj = create_ns_prog('main-random-topology', 'main-random-topology.cc', - deps=['core', 'simulator', 'mobility']) + obj = bld.create_ns3_program('main-debug') + obj.source = ['main-debug.cc', 'main-debug-other.cc'] + + obj = bld.create_ns3_program('main-callback') + obj.source = 'main-callback.cc' + + obj = bld.create_ns3_program('main-ptr') + obj.source = 'main-ptr.cc' + + obj = bld.create_ns3_program('main-simulator') + obj.source = 'main-simulator.cc' + + obj = bld.create_ns3_program('main-header', ['common', 'simulator']) + obj.source = 'main-header.cc' + + obj = bld.create_ns3_program('main-test') + obj.source = 'main-test.cc' + + obj = bld.create_ns3_program('main-simple', + ['node', 'internet-node', 'applications']) + obj.source = 'main-simple.cc' + + obj = bld.create_ns3_program('main-default-value', + ['core', 'simulator', 'node', 'point-to-point']) + obj.source = 'main-default-value.cc' + + obj = bld.create_ns3_program('main-grid-topology', + ['core', 'simulator', 'mobility', 'internet-node']) + obj.source = 'main-grid-topology.cc' + + obj = bld.create_ns3_program('main-random-topology', + ['core', 'simulator', 'mobility']) + obj.source = 'main-random-topology.cc' diff --git a/src/applications/wscript b/src/applications/wscript index 0874d58ab..02aa11f7f 100644 --- a/src/applications/wscript +++ b/src/applications/wscript @@ -1,10 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - obj = bld.create_obj('cpp', 'shlib') - obj.name = 'ns3-applications' - obj.target = obj.name - obj.uselib_local = ['ns3-node'] + obj = bld.create_ns3_module('applications', ['node']) obj.source = [ 'onoff-application.cc', ] diff --git a/src/common/wscript b/src/common/wscript index c1165026a..5f3df68b9 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -1,10 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - common = bld.create_obj('cpp', 'shlib') - common.name = 'ns3-common' - common.target = common.name - common.uselib_local = ['ns3-core', 'ns3-simulator'] + common = bld.create_ns3_module('common', ['core', 'simulator']) common.source = [ 'buffer.cc', 'chunk.cc', diff --git a/src/core/wscript b/src/core/wscript index 139f1c56b..bba53ae71 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -26,9 +26,7 @@ def configure(conf): def build(bld): - core = bld.create_obj('cpp', 'shlib') - core.name = 'ns3-core' - core.target = core.name + core = bld.create_ns3_module('core') core.source = [ 'callback-test.cc', 'debug.cc', diff --git a/src/devices/csma-cd/wscript b/src/devices/csma-cd/wscript index 31497fd51..e82c41b58 100644 --- a/src/devices/csma-cd/wscript +++ b/src/devices/csma-cd/wscript @@ -2,10 +2,7 @@ def build(bld): - obj = bld.create_obj('cpp', 'shlib') - obj.name = 'ns3-csma-cd' - obj.target = obj.name - obj.uselib_local = ['ns3-node'] + obj = bld.create_ns3_module('csma-cd', ['node']) obj.source = [ 'backoff.cc', 'csma-cd-net-device.cc', diff --git a/src/devices/point-to-point/wscript b/src/devices/point-to-point/wscript index 77c26fd80..c788a7880 100644 --- a/src/devices/point-to-point/wscript +++ b/src/devices/point-to-point/wscript @@ -2,10 +2,7 @@ def build(bld): - module = bld.create_obj('cpp', 'shlib') - module.name = 'ns3-point-to-point' - module.target = module.name - module.uselib_local = ['ns3-node'] + module = bld.create_ns3_module('point-to-point', ['node']) module.source = [ 'point-to-point-net-device.cc', 'point-to-point-channel.cc', diff --git a/src/internet-node/wscript b/src/internet-node/wscript index e0af13434..6dbc4f164 100644 --- a/src/internet-node/wscript +++ b/src/internet-node/wscript @@ -2,10 +2,7 @@ def build(bld): - obj = bld.create_obj('cpp', 'shlib') - obj.name = 'ns3-internet-node' - obj.target = obj.name - obj.uselib_local = ['ns3-node', 'ns3-applications'] + obj = bld.create_ns3_module('internet-node', ['node', 'applications']) obj.source = [ 'internet-node.cc', 'ipv4-l4-demux.cc', diff --git a/src/mobility/wscript b/src/mobility/wscript index b20c5af67..66d9dfb4f 100644 --- a/src/mobility/wscript +++ b/src/mobility/wscript @@ -1,10 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - mobility = bld.create_obj('cpp', 'shlib') - mobility.name = 'ns3-mobility' - mobility.target = mobility.name - mobility.uselib_local = ['ns3-core', 'ns3-simulator'] + mobility = bld.create_ns3_module('mobility', ['core', 'simulator']) mobility.source = [ 'grid-topology.cc', 'hierarchical-mobility-model.cc', diff --git a/src/node/wscript b/src/node/wscript index 17714f897..b9fd9552a 100644 --- a/src/node/wscript +++ b/src/node/wscript @@ -1,10 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - node = bld.create_obj('cpp', 'shlib') - node.name = 'ns3-node' - node.target = node.name - node.uselib_local = ['ns3-core', 'ns3-common', 'ns3-simulator'] + node = bld.create_ns3_module('node', ['core', 'common', 'simulator']) node.source = [ 'address.cc', 'eui48-address.cc', diff --git a/src/routing/global-routing/wscript b/src/routing/global-routing/wscript index 787ef9308..b14a5c502 100644 --- a/src/routing/global-routing/wscript +++ b/src/routing/global-routing/wscript @@ -1,10 +1,7 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- def build(bld): - module = bld.create_obj('cpp', 'shlib') - module.name = 'ns3-global-routing' - module.target = module.name - module.uselib_local = ['ns3-node'] + module = bld.create_ns3_module('global-routing', ['node']) module.source = [ 'global-router-interface.cc', 'global-route-manager.cc', diff --git a/src/simulator/wscript b/src/simulator/wscript index 9c7925f22..970a43aea 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -47,11 +47,7 @@ def configure(conf): def build(bld): - sim = bld.create_obj('cpp', 'shlib') - sim.name = 'ns3-simulator' - sim.target = sim.name - sim.uselib_local = ['ns3-core'] - + sim = bld.create_ns3_module('simulator', ['core']) sim.source = [ 'high-precision.cc', 'time.cc', diff --git a/src/wscript b/src/wscript index 092c7f4c8..3f42d122e 100644 --- a/src/wscript +++ b/src/wscript @@ -2,6 +2,7 @@ import os, os.path import shutil +import types import Action import Common @@ -47,10 +48,18 @@ def configure(conf): ## Used to link the 'run-tests' program with all of ns-3 code conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] +def create_ns3_module(bld, name, dependencies=()): + module = bld.create_obj('cpp', 'shlib') + module.name = 'ns3-' + name + module.target = module.name + module.uselib_local = ['ns3-' + dep for dep in dependencies] + return module + def build(bld): Object.register('ns3header', Ns3Header) Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE') + bld.create_ns3_module = types.MethodType(create_ns3_module, bld) bld.add_subdirs(list(all_modules)) diff --git a/utils/wscript b/utils/wscript index 27c509c01..68385e0d6 100644 --- a/utils/wscript +++ b/utils/wscript @@ -4,20 +4,15 @@ def build(bld): env = bld.env_of_name('default') - def create_ns_prog(name, source): - obj = bld.create_obj('cpp', 'program') - obj.target = name - obj.source = source - return obj - - unit_tests = create_ns_prog('run-tests', 'run-tests.cc') + unit_tests = bld.create_ns3_program('run-tests') unit_tests.install_var = 0 # do not install unit_tests.unit_test = 1 # runs on 'waf check' + unit_tests.source = 'run-tests.cc' ## link unit test program with all ns3 modules unit_tests.uselib_local = env['NS3_MODULES'] - obj = create_ns_prog('bench-simulator', 'bench-simulator.cc') - obj.uselib_local = "ns3-core ns3-common ns3-simulator" + obj = bld.create_ns3_program('bench-simulator', ['simulator']) + obj.source = 'bench-simulator.cc' - obj = create_ns_prog('replay-simulation', 'replay-simulation.cc') - obj.uselib_local = "ns3-core ns3-common ns3-simulator" + obj = bld.create_ns3_program('replay-simulation', ['simulator']) + obj.source = 'replay-simulation.cc' diff --git a/wscript b/wscript index 2241433dd..12600338c 100644 --- a/wscript +++ b/wscript @@ -2,12 +2,13 @@ import sys import shlex import shutil +import types +import optparse +import os.path import Params import Object import pproc as subprocess -import optparse -import os.path Params.g_autoconfig = 1 @@ -135,7 +136,17 @@ def configure(conf): conf.sub_config('src') +def create_ns3_program(bld, name, dependencies=('simulator',)): + program = bld.create_obj('cpp', 'program') + program.name = name + program.target = program.name + program.uselib_local = ['ns3-' + dep for dep in dependencies] + return program + + def build(bld): + bld.create_ns3_program = types.MethodType(create_ns3_program, bld) + variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT'] variant_env = bld.env_of_name(variant_name) bld.m_allenvs['default'] = variant_env # switch to the active variant From 7f3f471f1255d3103cb26a672ef146392f4e9d6d Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 16:41:59 +0200 Subject: [PATCH 232/278] rename Bind to DefaultValue::Bind. fix bug 62 --- examples/csma-cd-one-subnet.cc | 2 +- examples/simple-global-routing.cc | 12 ++-- examples/simple-point-to-point.cc | 8 +-- samples/main-default-value.cc | 2 +- samples/main-random-topology.cc | 10 +-- src/core/default-value.cc | 116 +++++++++++++++--------------- src/core/default-value.h | 32 +++++---- src/simulator/simulator.cc | 8 +-- src/simulator/time.cc | 12 ++-- 9 files changed, 106 insertions(+), 96 deletions(-) diff --git a/examples/csma-cd-one-subnet.cc b/examples/csma-cd-one-subnet.cc index db0731a23..743e92bc9 100644 --- a/examples/csma-cd-one-subnet.cc +++ b/examples/csma-cd-one-subnet.cc @@ -82,7 +82,7 @@ int main (int argc, char *argv[]) // The below Bind command tells the queue factory which class to // instantiate, when the queue factory is invoked in the topology code - Bind ("Queue", "DropTailQueue"); + DefaultValue::Bind ("Queue", "DropTailQueue"); // Allow the user to override any of the defaults and the above // Bind()s at run-time, via command-line arguments diff --git a/examples/simple-global-routing.cc b/examples/simple-global-routing.cc index 3458bb84f..75879be23 100644 --- a/examples/simple-global-routing.cc +++ b/examples/simple-global-routing.cc @@ -85,21 +85,21 @@ int main (int argc, char *argv[]) DebugComponentEnable ("GlobalRouteMaager"); #endif - // Set up some default values for the simulation. Use the Bind () + // Set up some default values for the simulation. Use the DefaultValue::Bind () // technique to tell the system what subclass of Queue to use, // and what the queue limit is // The below Bind command tells the queue factory which class to // instantiate, when the queue factory is invoked in the topology code - Bind ("Queue", "DropTailQueue"); + DefaultValue::Bind ("Queue", "DropTailQueue"); - Bind ("OnOffApplicationPacketSize", "210"); - Bind ("OnOffApplicationDataRate", "448kb/s"); + DefaultValue::Bind ("OnOffApplicationPacketSize", "210"); + DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s"); - //Bind ("DropTailQueue::m_maxPackets", 30); + //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30); // Allow the user to override any of the defaults and the above - // Bind ()s at run-time, via command-line arguments + // DefaultValue::Bind ()s at run-time, via command-line arguments CommandLine::Parse (argc, argv); // Here, we will explicitly create four nodes. In more sophisticated diff --git a/examples/simple-point-to-point.cc b/examples/simple-point-to-point.cc index fa826ab5c..9b185143b 100644 --- a/examples/simple-point-to-point.cc +++ b/examples/simple-point-to-point.cc @@ -87,12 +87,12 @@ int main (int argc, char *argv[]) // The below Bind command tells the queue factory which class to // instantiate, when the queue factory is invoked in the topology code - Bind ("Queue", "DropTailQueue"); + DefaultValue::Bind ("Queue", "DropTailQueue"); - Bind ("OnOffApplicationPacketSize", "210"); - Bind ("OnOffApplicationDataRate", "448kb/s"); + DefaultValue::Bind ("OnOffApplicationPacketSize", "210"); + DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s"); - //Bind ("DropTailQueue::m_maxPackets", 30); + //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30); // Allow the user to override any of the defaults and the above // Bind()s at run-time, via command-line arguments diff --git a/samples/main-default-value.cc b/samples/main-default-value.cc index 014a7d18d..f125a7181 100644 --- a/samples/main-default-value.cc +++ b/samples/main-default-value.cc @@ -73,7 +73,7 @@ int main (int argc, char* argv[]) // global variable and value (string) to overwrite the default. // Here, the default value of 33 for testInt1 is overwritten with 57 // - Bind("testInt1", "57"); + DefaultValue::Bind("testInt1", "57"); TestClass* testclass = new TestClass (); NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")"); diff --git a/samples/main-random-topology.cc b/samples/main-random-topology.cc index 05f7f26c1..3fb52a0d9 100644 --- a/samples/main-random-topology.cc +++ b/samples/main-random-topology.cc @@ -24,12 +24,12 @@ CourseChange (Ptr position) int main (int argc, char *argv[]) { - Bind ("RandomDiscPositionX", "100"); - Bind ("RandomDiscPositionY", "50"); - Bind ("RandomDiscPositionRho", "Uniform:0:30"); + DefaultValue::Bind ("RandomDiscPositionX", "100"); + DefaultValue::Bind ("RandomDiscPositionY", "50"); + DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30"); - Bind ("RandomTopologyPositionType", "RandomDiscPosition"); - Bind ("RandomTopologyMobilityType", "StaticMobilityModel"); + DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition"); + DefaultValue::Bind ("RandomTopologyMobilityType", "StaticMobilityModel"); CommandLine::Parse (argc, argv); diff --git a/src/core/default-value.cc b/src/core/default-value.cc index c9f2f6db4..4dcfcacbc 100644 --- a/src/core/default-value.cc +++ b/src/core/default-value.cc @@ -23,6 +23,52 @@ namespace ns3 { +namespace DefaultValue { + +enum BindStatus { + OK, + INVALID_VALUE, + NOT_FOUND +}; + + +static +enum BindStatus +BindSafe (std::string name, std::string value) +{ + for (DefaultValueList::Iterator i = DefaultValueList::Begin (); + i != DefaultValueList::End (); i++) + { + DefaultValueBase *cur = *i; + if (cur->GetName () == name) + { + if (!cur->ParseValue (value)) + { + return INVALID_VALUE; + } + return OK; + } + } + return NOT_FOUND; +} + +void +Bind (std::string name, std::string value) +{ + switch (BindSafe (name, value)) { + case INVALID_VALUE: + NS_FATAL_ERROR ("Invalid value: "<GetName () == name) - { - if (!cur->ParseValue (value)) - { - return INVALID_VALUE; - } - return OK; - } - } - return NOT_FOUND; -} - -void -Bind (std::string name, std::string value) -{ - switch (BindSafe (name, value)) { - case INVALID_VALUE: - NS_FATAL_ERROR ("Invalid value: "< i ("test-i", "help-i", -1); NS_TEST_ASSERT_EQUAL (i.GetValue (), -1); - Bind ("test-i", "-2"); + DefaultValue::Bind ("test-i", "-2"); NS_TEST_ASSERT_EQUAL (i.GetValue (), -2); - Bind ("test-i", "+2"); + DefaultValue::Bind ("test-i", "+2"); NS_TEST_ASSERT_EQUAL (i.GetValue (), 2); NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)"); NumericDefaultValue ui32 ("test-ui32", "help-ui32", 10); NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)"); NumericDefaultValue c ("test-c", "help-c", 10); NS_TEST_ASSERT_EQUAL (c.GetValue (), 10); - Bind ("test-c", "257"); + DefaultValue::Bind ("test-c", "257"); NumericDefaultValue x ("test-x", "help-x", 10.0); NumericDefaultValue y ("test-y", "help-y", 10.0); @@ -385,9 +389,9 @@ DefaultValueTest::RunTests (void) MY_ENUM_B, "B", 0, (void*)0); NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C); - Bind ("test-e", "B"); + DefaultValue::Bind ("test-e", "B"); NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B); - NS_TEST_ASSERT_EQUAL (BindSafe ("test-e", "D"), INVALID_VALUE); + NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("test-e", "D"), DefaultValue::INVALID_VALUE); class MyEnumSubclass : public EnumDefaultValue { @@ -403,7 +407,7 @@ DefaultValueTest::RunTests (void) } } e1 ; NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B); - Bind ("test-e1", "D"); + DefaultValue::Bind ("test-e1", "D"); NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D); DefaultValueList::Remove ("test-e1"); diff --git a/src/core/default-value.h b/src/core/default-value.h index f57b3b4e0..b43f013be 100644 --- a/src/core/default-value.h +++ b/src/core/default-value.h @@ -31,6 +31,25 @@ namespace ns3 { +namespace DefaultValue +{ + +/** + * \ingroup config + * \param name name of variable to bind + * \param value value to bind to the specified variable + * + * If the variable name does not match any existing + * variable or if the value is not compatible with + * the variable type, this function will abort + * at runtime and print an error message detailing + * which variable or value triggered the problem. + */ +void Bind (std::string name, std::string value); + +} + + class DefaultValueBase { public: @@ -83,19 +102,6 @@ class DefaultValueList static List *GetList (void); }; -/** - * \ingroup config - * \param name name of variable to bind - * \param value value to bind to the specified variable - * - * If the variable name does not match any existing - * variable or if the value is not compatible with - * the variable type, this function will abort - * at runtime and print an error message detailing - * which variable or value triggered the problem. - */ -void Bind (std::string name, std::string value); - /** * \brief A Boolean variable for ns3::Bind * \ingroup config diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 8190aeb79..e6f2d332b 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -337,20 +337,20 @@ SimulatorPrivate *Simulator::m_priv = 0; void Simulator::SetLinkedList (void) { - Bind ("Scheduler", "List"); + DefaultValue::Bind ("Scheduler", "List"); } void Simulator::SetBinaryHeap (void) { - Bind ("Scheduler", "BinaryHeap"); + DefaultValue::Bind ("Scheduler", "BinaryHeap"); } void Simulator::SetStdMap (void) { - Bind ("Scheduler", "Map"); + DefaultValue::Bind ("Scheduler", "Map"); } void Simulator::SetExternal (const std::string &external) { - Bind ("Scheduler", external); + DefaultValue::Bind ("Scheduler", external); } void Simulator::EnableLogTo (char const *filename) { diff --git a/src/simulator/time.cc b/src/simulator/time.cc index 4adc49cc3..8c0e43e35 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -414,12 +414,12 @@ bool TimeTests::RunTests (void) TimeStepPrecision::Set (TimeStepPrecision::NS); - Bind ("TimeStepPrecision", "S"); - Bind ("TimeStepPrecision", "MS"); - Bind ("TimeStepPrecision", "US"); - Bind ("TimeStepPrecision", "NS"); - Bind ("TimeStepPrecision", "PS"); - Bind ("TimeStepPrecision", "FS"); + DefaultValue::Bind ("TimeStepPrecision", "S"); + DefaultValue::Bind ("TimeStepPrecision", "MS"); + DefaultValue::Bind ("TimeStepPrecision", "US"); + DefaultValue::Bind ("TimeStepPrecision", "NS"); + DefaultValue::Bind ("TimeStepPrecision", "PS"); + DefaultValue::Bind ("TimeStepPrecision", "FS"); return ok; } From 69ccebd108e32a38dc973e7e02dda5578a1cf7c3 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 8 Aug 2007 23:23:24 +0200 Subject: [PATCH 233/278] avoid initialization ordering problem --- src/common/trace-context.cc | 12 +++++++++--- src/common/trace-context.h | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/common/trace-context.cc b/src/common/trace-context.cc index 786ce9149..b967270eb 100644 --- a/src/common/trace-context.cc +++ b/src/common/trace-context.cc @@ -23,7 +23,6 @@ namespace ns3 { -std::vector TraceContext::m_sizes; TraceContext::TraceContext () : m_data (0) @@ -68,10 +67,17 @@ TraceContext::~TraceContext () } } +TraceContext::Sizes * +TraceContext::GetSizes (void) +{ + static Sizes sizes; + return &sizes; +} + uint8_t TraceContext::GetSize (uint8_t uid) { - return m_sizes[uid]; + return (*GetSizes ())[uid]; } void @@ -218,7 +224,7 @@ TraceContext::DoGetNextUid (void) static uint8_t uid = 0; if (uid == 0) { - m_sizes.push_back (0); + GetSizes ()->push_back (0); } uid++; return uid; diff --git a/src/common/trace-context.h b/src/common/trace-context.h index 74108b8da..acc2ee268 100644 --- a/src/common/trace-context.h +++ b/src/common/trace-context.h @@ -95,7 +95,8 @@ private: bool DoAdd (uint8_t uid, uint8_t const *buffer); bool DoGet (uint8_t uid, uint8_t *buffer) const; - static std::vector m_sizes; + typedef std::vector Sizes; + static Sizes *GetSizes (void); struct Data { uint16_t count; uint16_t size; @@ -158,7 +159,7 @@ uint8_t TraceContext::GetNextUid (void) { uint8_t uid = DoGetNextUid (); - m_sizes.push_back (sizeof (T)); + GetSizes ()->push_back (sizeof (T)); return uid; } From bac11af00e0b9053df170727314e06a9e057e975 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 8 Aug 2007 21:07:52 +0100 Subject: [PATCH 234/278] Build all modules as a single ns3 shared library. --- src/wscript | 14 +++++++++++--- utils/wscript | 2 +- wscript | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/wscript b/src/wscript index 3f42d122e..0d50d0889 100644 --- a/src/wscript +++ b/src/wscript @@ -39,9 +39,9 @@ def configure(conf): conf.sub_config('simulator') blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) + conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir, 'src')] for module in all_modules: module_path = os.path.join(blddir, 'src', module) - conf.env.append_value('NS3_MODULE_PATH', module_path) if Params.g_options.enable_rpath: conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (module_path,)) @@ -49,10 +49,11 @@ def configure(conf): conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] def create_ns3_module(bld, name, dependencies=()): - module = bld.create_obj('cpp', 'shlib') + module = bld.create_obj('cpp', 'objects') module.name = 'ns3-' + name module.target = module.name - module.uselib_local = ['ns3-' + dep for dep in dependencies] + module.add_objects = ['ns3-' + dep for dep in dependencies] + module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS']) return module @@ -63,6 +64,13 @@ def build(bld): bld.add_subdirs(list(all_modules)) + ## Create a single ns3 library containing all modules + lib = bld.create_obj('cpp', 'shlib') + lib.name = 'ns3' + lib.target = 'ns3' + lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES']) + + class Ns3Header(Object.genobj): """A set of NS-3 header files""" def __init__(self, env=None): diff --git a/utils/wscript b/utils/wscript index 68385e0d6..d64d46dc5 100644 --- a/utils/wscript +++ b/utils/wscript @@ -9,7 +9,7 @@ def build(bld): unit_tests.unit_test = 1 # runs on 'waf check' unit_tests.source = 'run-tests.cc' ## link unit test program with all ns3 modules - unit_tests.uselib_local = env['NS3_MODULES'] + unit_tests.uselib_local = 'ns3' obj = bld.create_ns3_program('bench-simulator', ['simulator']) obj.source = 'bench-simulator.cc' diff --git a/wscript b/wscript index 12600338c..6801b7e56 100644 --- a/wscript +++ b/wscript @@ -140,7 +140,7 @@ def create_ns3_program(bld, name, dependencies=('simulator',)): program = bld.create_obj('cpp', 'program') program.name = name program.target = program.name - program.uselib_local = ['ns3-' + dep for dep in dependencies] + program.uselib_local = 'ns3' return program From 08062bc3c5ef49c062b78fe2482d9427c3e13c1b Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 8 Aug 2007 21:17:48 +0100 Subject: [PATCH 235/278] By popular demand, add the working waf snapshot to the ns-3 source tree. --- waf | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100755 waf diff --git a/waf b/waf new file mode 100755 index 000000000..d4f80d72a --- /dev/null +++ b/waf @@ -0,0 +1,338 @@ +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +import os, sys +if 'PSYCOWAF' in os.environ: + try: + import psyco + psyco.full() + except: + pass + +VERSION="1.1.1" +REVISION="1272724989" +INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local' +cwd = os.getcwd() + +def decodeAscii85(s): + out=[] + app=out.append + s=''.join(s.split()).replace('z','!!!!!') + p1,p2=divmod(len(s), 5) + stop=5*p1 + p3,p4=s[0:stop],s[stop:] + for i in range(p1): + off=i*5 + a=ord(p3[off])-33 + b=ord(p3[off+1])-33 + c=ord(p3[off+2])-33 + d=ord(p3[off+3])-33 + e=ord(p3[off+4])-33 + num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e + x,p=divmod(num,256) + x,o=divmod(x,256) + m,n=divmod(x,256) + app(chr(m)+chr(n)+chr(o)+chr(p)) + if p2: + while len(p4)<5: p4=p4+'!' + a=ord(p4[0])-33 + b=ord(p4[1])-33 + c=ord(p4[2])-33 + d=ord(p4[3])-33 + e=ord(p4[4])-33 + num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e + x,p=divmod(num,256) + x,o=divmod(x,256) + m,n=divmod(x, 256) + if p2==2: app(chr(m)) + elif p2==3: app(chr(m)+chr(n)) + elif p2==4: app(chr(m)+chr(n)+chr(o)) + return ''.join(out) + +# wafdir is needed to parse the command-line arguments or print the version number +wafdir=None # SPECIAL LINE + +def uncompress_wafdir(newdir): + file = open(sys.argv[0], 'rb') + while 1: + line = file.readline() + if not line: + print "This is a stripped-down waf, there is no wafadmin directory available" + print "Please set WAFDIR to a directory containing a directory named wafadmin" + print "Or use the full waf version available freely at http://freehackers.org/~tnagy/bksys.html" + print "\033[91mNo wafadmin: cannot execute anything (error)\033[0m" + sys.exit(1) + line=line.rstrip() + if line=='# ===>BEGIN WOOF<===': + cnt = file.readline() + if not cnt: + print "Corrupted waf (1)" + sys.exit(1) + + line = file.readline().rstrip() + if line!='# ===>END WOOF<===': + print "Corrupted waf (2)" + sys.exit(1) + break + if not cnt: + print "Corrupted waf (3)" + sys.exit(1) + + cnt = decodeAscii85(cnt[1:]) + + # create wafadmin + import shutil + try: shutil.rmtree(newdir) + except OSError: pass + try: os.makedirs(newdir) + except OSError: + print "Could uncompress waf-local into %s"%newdir + print "Please install waf system-wide or move waf in a writeable directory" + sys.exit(1) + + os.chdir(newdir) + file = open('wafadmin.tar.bz2', 'wb') + file.write(cnt) + file.close() + + # now we have the tar file to open + import tarfile + tar = tarfile.open('wafadmin.tar.bz2') + for tarinfo in tar: + tar.extract(tarinfo) + tar.close() + + # cleanup the tarfile and chdir to the previous directory + os.chmod('wafadmin', 0755) + os.chmod('wafadmin'+os.sep+'Tools', 0755) + os.unlink('wafadmin.tar.bz2') + os.chdir(cwd) + + global wafdir + wafdir = newdir + +def try_wafdir(dir): + global wafdir + if wafdir: return + try: + os.stat(os.path.join(dir, 'wafadmin')) + wafdir = os.path.abspath(dir) + except OSError: + pass + +def find_wafadmin(): + global wafdir + name = sys.argv[0] + + # wafadmin may be in $WAFDIR (developers) + if 'WAFDIR' in os.environ: + try_wafdir(os.environ['WAFDIR']) + if wafdir: return + + # waf-light is a special beast + if name[-5:] == 'light': + try_wafdir(os.path.dirname(os.path.abspath(name))) + if wafdir: return + print "\033[91mwaf-light in use, wafadmin not found -> export WAFDIR=/folder\033[0m" + sys.exit(1) + + if not wafdir: + dir = "/lib/waf-%s-%s/" % (VERSION, REVISION) + for i in [INSTALL, '/usr', '/usr/local', '/opt']: + try_wafdir(i+dir) + if wafdir: return + + # remove $HOME/.waf-version if asked to + if wafdir: + if "--nocache" in sys.argv: + import shutil + print "removing the local wafdir", wafdir + try: shutil.rmtree(wafdir) + except OSError: pass + try: os.stat(wafdir) + except OSError: wafdir=None + + if wafdir: return + + # look in the directory containing waf + if sys.platform == 'win32': s='waf-%s-%s' + else: s='.waf-%s-%s' + dir = os.path.join(os.path.dirname(os.path.abspath(name)), s % (VERSION, REVISION)) + try_wafdir(dir) + if wafdir: return + + # not found, uncompress + wafdir = dir + uncompress_wafdir(dir) + +# run the test +find_wafadmin() +if "-vv" in sys.argv: print "wafdir is ", wafdir + +# Update sys.path and import our modules +wafadmindir = os.path.join(wafdir, 'wafadmin') +tooldir = os.path.join(wafadmindir, 'Tools') +sys.path = [wafadmindir, tooldir] + sys.path + +import Options, Params, Utils +from Params import fatal, warning + +# Set the directory containing the tools +Params.g_tooldir = [tooldir] +Params.g_cwd_launch = cwd + +if Params.g_version != VERSION: + fatal('version mismatch waf %s <-> wafadmin %s (wafdir %s)' % (VERSION, Params.g_version, wafdir)) + +# some command-line options can be processed immediately +if '--version' in sys.argv: + opt_obj = Options.Handler() + opt_obj.parse_args() + sys.exit(0) + +# now find the wscript file +msg1 = 'Waf: *** Nothing to do! Please run waf from a directory containing a file named "wscript"' + +# Some people want to configure their projects gcc-style: +# mkdir build && cd build && ../waf configure && ../waf +# check that this is really what is wanted +build_dir_override = None +candidate = None + +lst = os.listdir(cwd) +xml = 0 +#check if a wscript or a wscript_xml file is in current directory +if (not 'wscript' in lst) and (not 'wscript_xml' in lst): + if 'configure' in sys.argv: + #set the build directory with the current directory + build_dir_override = cwd + if 'wscript_build' in lst: + #try to find the wscript root + candidate = cwd +else: + #wscript or wscript_xml is in current directory, use this directory as candidate + candidate = cwd + +try: + #check the following dirs for wscript or wscript_xml + search_for_candidate = True + if not candidate: + #check first the calldir if there is wscript or wscript_xml + #for example: /usr/src/configure the calldir would be /usr/src + calldir = os.path.abspath(os.path.dirname(sys.argv[0])) + lst_calldir = os.listdir(calldir) + if 'wscript' in lst_calldir: + candidate = calldir + search_for_candidate = False + if 'wscript_xml' in lst_calldir: + candidate = calldir + xml = 1 + search_for_candidate = False + if "--make-waf" in sys.argv and candidate: + search_for_candidate = False + + #check all directories above current dir for wscript or wscript_xml if still not found + while search_for_candidate: + if len(cwd) <= 3: + break # stop at / or c: + dirlst = os.listdir(cwd) + if 'wscript' in dirlst: + candidate = cwd + xml = 0 + if 'wscript_xml' in dirlst: + candidate = cwd + xml = 1 + break + if 'configure' in sys.argv and candidate: + break + if Params.g_lockfile in dirlst: + break + cwd = cwd[:cwd.rfind(os.sep)] # climb up +except: + fatal(msg1) + +if not candidate: + # check if the user only wanted to display the help + if '-h' in sys.argv or '--help' in sys.argv: + warning('No wscript file found: the help message may be incomplete') + opt_obj = Options.Handler() + opt_obj.parse_args() + sys.exit(0) + else: + fatal(msg1) + +# We have found wscript, but there is no guarantee that it is valid +os.chdir(candidate) + +# xml -> jump to the parser +if xml: + from XMLScripting import compile + compile(candidate+os.sep+'wscript_xml') +else: + # define the main module containing the functions init, shutdown, .. + Utils.set_main_module(os.path.join(candidate, 'wscript')) + +if build_dir_override: + try: + # test if user has set the blddir in wscript. + blddir = Utils.g_module.blddir + msg = 'Overriding build directory %s with %s' % (blddir, build_dir_override) + Params.niceprint(msg, 'WARNING', 'waf') + except: + pass + Utils.g_module.blddir = build_dir_override + +# fetch the custom command-line options recursively and in a procedural way +opt_obj = Options.Handler() +opt_obj.sub_options('') # will look in wscript +opt_obj.parse_args() + +# use the parser results +if Params.g_commands['dist']: + # try to use the user-defined dist function first, fallback to the waf scheme + try: + Utils.g_module.dist() + sys.exit(0) + except AttributeError: + pass + try: appname = Utils.g_module.APPNAME + except: appname = 'noname' + + try: + get_version = Utils.g_module.get_version + except AttributeError: + try: + version = Utils.g_module.VERSION + except AttributeError: + version = '1.0' + else: + version = get_version() + + from Scripting import Dist + Dist(appname, version) + sys.exit(0) +elif Params.g_commands['distclean']: + # try to use the user-defined distclean first, fallback to the waf scheme + try: + Utils.g_module.distclean() + sys.exit(0) + except AttributeError: + pass + from Scripting import DistClean + DistClean() + sys.exit(0) + +try: Utils.g_module.init() +except AttributeError: pass + +import Scripting +try: Scripting.Main() +except KeyboardInterrupt: Params.fatal('build interrupted') +#import hotshot +#prof=hotshot.Profile("/tmp/proftest.txt") +#prof.runcall(Scripting.Main) +#prof.close() +# ===>BEGIN WOOF<=== +#6<\%_0gSqh;d"&i4hUq"'EA+4s8;Tjs8W-!s8W-!s8W+l!!!?/+s8Ri#QQOmTF;*7jW*^\\1'ZCz!!!!q-n#&q!!"DJF2"&p-aW8SQY$K"!EWV\h!&gY=W_6RV_sr\722cZ@k5kdqqg'$4*["='$#2".3/jH9s\UR>BX?ohY0*=H[;!kmGlsVII%EnT7)!(/U>#5gO6P<#sP`m!Um]ST#;0S]:$Hk8J3V550%G+n!@)?&(e/H?7rG4)HopHecsJV&*NLld/Hf'i_/tW]OXF=:('"e7,sVH,!!!'c"B6'9h=&$=^$;/b<7!LN[75n*Zqu06hetOCfNT/9Dgh)`hX=R2Efmj*fjoK.pmJmh!ZlhGA_fKbKkV"UYb%$WeaM<&g4,qXHU?d8^JOF*%JYrh=IR.4^RKF+eA55]5<0hXk9hhme9(rh6nrgMn6Nkn!3?hPcO46ZarrBDYD60?/F#=^#"+FY%MhCpYKIuY'4`L\G(EBC%lKlo_[gcA*S!'f@;scf6;#ph"9uKijR_*D0sg5$f:Wk<&O(2&%?WII<;NeC$o1g)ql6Ep?UE"Nr&N6G4/jfDnaO=GIt<\efO_Thd*tkIJ(4`BhH+Q#Q^mriANd<)9A\4n"42=kb]#^DkT=Q+gDA3H_e&T"!!)5_8bRSiDY<_tcb@q:I-rM#g:)F^8p<2]2gLe?Ch*\7]tNjs020r>=5RnDp%7PBoC![Th72o`a:#<,9:j0fl5oft]63B-8kZn]AUbg83'YpRHGrfg4g+/H\r+?>S>Dp@l24g/m%jC0ZVQ)bTehQ#4*Z0as)4J9k`J:5(m&jtEVkI2Cd(dA8ktHLJ>Oq"f]f[(ArhIYKc]5c[J4lPj>D'k5f4*NGO&PAu:]C+\NPC%]toII(/+.rjfDHbJ5>YJ"KR9b7j=!Wi@V5S+A-^`Z.ASs`%sVkPt8ct"&3+92BEVEkcF#RCJ7dh#E,Ua`\jeFbS3IT5tX)L@B"cl+_GW#>Xm!!!'e,X>9.":V:+!hL&PR0f"X"2lLC,L^ae2!71_m!MBDm!$Oo>7Ynt_-@c@Y'Z*!^lAs)Wb%=WB+[&Uq:JF)fo`,M!)?9a<-DDVJ5ThD;C,#pWnI_3hrA9lerC5s2rjl;?[PrL=C^1!mZZe!*tIsVMZ(`(aR.`!.f;1JL3$GX5;7lqq$d-4`p%rY43r4;oek6HHf2F7+PXA[5XV*Bupng8)TXXs/-lT#^Lr&'K\Qer#dXd]Cp9.mP/tTC5VP&D[`VCFf?)?KI(kK#j'?aArSC"kcMIcb*fhrE/IY4>tHlu3H)Ah!H-i1UBF'l\7*5d+pSd1QOXU,!m6;[+S$'LH\EG3'I_C+N!$1+S/Xm_TYp[$6OMM\6Lb6b*.a-p;-K&GIBY.2IRIl@iLl5p?iV9MI)>9,,>qBHsO9J<7OV9E@'%8]A1sm`T">r#7"I2AP!)c`-72/oZir6"9Mht@'bEYs>A0_+@O`e!+[VTQ,*mbQ@MkIV,ab5MJ;Rm1To+GYM@*`88=G8?VHB"STV@=D@OPt6W$J$fBOrV0-n:U?TqWGT)3R<'+G(dC#_jNq)Ib1,>+qU`+UFmB$"/oE,)@E]?m$q1UnJ'U.Z0+@Tr)7cTa@*BMCN#0R2R2uW%(AjLkp^6BkX<1+KC9kU5#VBVIGXKMJ/ENBh9S)#UtS0W!JK8Ob0EsOt%T2AdOWpL*EIOR"upf-A#uq,&+'S80FTSLkLp,)CV;9#(W'V-DcSHBLnA\MPLQHP"K1eAL_-r8j]2$VMZQGLhMrCWD*jo,`%84-5_l%R\YP4L4UiuKRtP68gn/"@=a;&Q6mHJMBWplV&>(7?mI-KAf;jaQ@pBZ,(`[L+fYkPMO&jYR"d$q#a,dfC8-<[TI;3\BHdMWBI6'7!2Z?]W$7BI?t"kI.&qkJ,"R<:+K-2M7Tro_AeJK$JqHOW+IZDhOb-D](mZ;<-<-ZfU4S,bUo&ho7ZjDj8qJI#TSaj!8.L7A5OGNrUM3&urTn]Eg-)cPD@SiIqMNSm/Slm3`R%],3Jk.=W&djAM@L?:RLm4k_,c%/s-n,4lV'ZOA8=EFKWgWKh9Z06^$?/C!";NW7[_\dIUgcrPJ=%OS,a+k"J;Aek8n+6X.OgL7@UUO:!\.rR$;uD+TI(j`A;DM1.12K;Jf./f6>2T-$4;Alj9`\$MOGf"Ad#,I."R2?ROKF/Q)\:")AWV`Q=L>+&V64AJfnSL5&_'@ps7.?K-IZV'a579&5jd\,u[c/!":Q"j'b"&p;H+ea78+=fPg%KR1ntUN6j/aV1a;%"NZ\#;YI8)[;g:(0\g+"[p4);+3hYV0!=_9X?R[7$95[9$sJT&HP3&O`LjtPbL`($qNep!s(e@ZS9oT&4EcH'b`9;!N7IPM5ckEL+%o_,%:ldL/=ONLl-_F&;C?3O['7>&u[4OVML)DU,&Si.L%#gU`lV.AccM9-jl=SR"f1($7$euLe:9K,%a`MMF:np8r8gB$C4SgU0o/fBVd,O&o*L!gnk--N=JCZZ!$m5S-jV+i$5eGP#_7SiU*,;(Weq-s,p=akM5?VL?m1pb&gaD$Th5lr=GR7j>"V8A&qq_>KHQoui<`0P6df7/R(:fIE;s9Rh\PANrmt=orCFh8'mg]"&D+6a)#:/O,i7]."+Kk[%NKSXO=J%mE@,6@Y(6bULL%6.d^;cXHK:qZJ:8KP!pG`23s2hRo84Zi5UdTim3('<_H)XgLVl\#513k/Q#3cl`d7h&Rj3TeY;1*>tbQaFbj#WruKf!VX19?TD=Br:$=O%N29X.*&1$`lL11)H)i?%XV@p[U;VQQ[[c4ZB@DaB4ipr+-jD.-ZO/16>8I.*S&6"o2s/jEoeFIh,FP[e8'qD$Z%eZgi@9Q,Q*'8IP&q-0H/-;4SUf7Ypi`gsZGHd@2-AcEZP_]+.kAe^[m&`i27$HZH@%)@*)OU!_`["OMM86CRjNHCdhIEdRTM(-S/9BL\Be31535IL<.-G$Tt3r>h];r+"U>WB7=tpLQo,6Q-SpD]>m4+f[Y-,`BJ?5dVXkj`A@2`I3^Ai[Dr&_^l5]IS)i(Tdtjts6;E,1G&HRr+4X3eFpm?pS!-J*Q7n.f'J`K]nEIh\_)%^3>8&k\;D1nO@h&3rbD-Xlcb5N\meD5/I>uqMHC2VRcV>oD\p0VCPTTUJ))f,tRL^i2q79mgDt2"2f10:,Y5"=-"Aknk*4;R=O%JHT7l8VEJ]X*k-4W_Q06+0X6E7d-f'/X(2gJlnLN/j:gCPo'R@5/@a==0`c>h&b,Z%ZaC(k*\iC<1-#*@G;1\T-!<"nfL./i2oOWt[p$lGa8q,\W]ZI!bloqU&Q(g]0d)=!X]4RP'nn+[AQER9o`,d2f,DJgI9hi(r>I_5BM@H]`E9ADm@F;O*9nh9!E_cea<66EK;j0YLDt.?#"Q5A.6$4qL0P)K:Hn"0E\V*hgdBoC@&$=^#(M$u]@U5A;L0nQ-'U`qjYlCPa-gborMSi;+MA4a./,B&%-;uZE'_%ib&79A#8oo55h69cr[.o!\/n"O&?W>*-YeOrH05(;R"qalZ2.[*EZK_ab&$WVWqI5AD^2j`\6CP_^Nc/sU$'-X!cbuoB>sn04b7PF0<@Bf+Vp2Pl6*d&!H&N1@Ppeu(:lRCbWI^ubgb^(Ob7YOENEE0#>ruLrrGL[b73^[>WO=8t88-15.=b>N-R^teA:n6%f1XolP4Q:8liPMXq9@"d\QosaAJ6b]*7PaDbOM8,[^:l>:7u:M\7t>k#96+r]aI@j4W+`^I3iOX9bk"S,4hQ,X_*No0jeZo*?=]'1XQddQE!q'\H;P%JHI"SCr[>d?W`^RMWqDeb)I9%pkXgAd)mc@hZda*MKqe?QZ]1tGN9HMuYXV.j%)!YY.85D9d>=H]%"B^=U!s)ZDO=0=WP^&EaiY'6-h:[^:b$qkK4c%B9iK?q+jGU#c!aohaW]HP3aF?;54mK/uX=Q;Hd@/$_E?JG3E[dX6&.:$nHlE"fO^NWXNa2m8BT\:rcR8GE5QP8^s%)u-Cf87lQu%06?+g.eJ/;sgIm,bE_W%jO]jONnI7g!8CUQN/-i"AGX%Jp4UmC7p1cpM=370Zml%qO3_-tUd25k_.@/Y">(HT\&3V7Q]DHZ'WDB$0n6b.ku"XWUVkT.n]BLo'^`*&`D#M)dMBBBLn2DcD!js/-:&@%!2dGrum&\J.HC2D5H:RH__So_Q@A,T'16ZS12\C+a:L0#D`I.l)#mn7W*u'=AE")m4#J(hLY3a3`5pb;*ZO/gb>#DYuS`UiuG&2+q44-=u)[9BLIOn)uC2tQS>rc.S;64;'cpN7XXKQl=Xr#2&faVMODc@=48cJ`rcp4U9VJIkLe-:>at<4LKT1VnC6@^A?F6,-6H3kFaN@gK>TV&&!WKCj[GA&.rn?ZG9&r$r;Wobm_'@P9t_m:8&@8AG2Y_7LTtHDF]'8uS;<1/MNOM>+MP"tcsE&>"t)?J*7oq0OiiA1N)Lo0Z;V=2!tZS+n+IW1OIJDpq$k(FdsdW\!@4.K`&oEuo&iU*ou`a3B#J>QYiEUP9_m!P5=98Wdk&Mup8KY!MH4pA75gU&p>pMYSSs9C?I4i`LRa^;CJ6&bP"?q,`jR\OY6Y=.g6>]aT?YEVYe8gc50l;p\)>P:BQ.&?!E4d;]_%3`eVbt3&Km8tOdP(Rq>T:\RP$T"/d`:-f!kZg[[%[&HiqLN;+VE[oI:W`g(JL>m%`ALdZcW[]BtJ/eaQ"s2-3FL-aSej(52.*W39HOJkrB5\h?%bL$52>k9h^;i1`B(b+:nbd]khhO3m[=AKq8(/MN9M+p'Q.g)*"c7X('tJI1Te(m97@$4`t%d$R@"n+k)G"Q5AP_j9o1Wt,-94*.CNed5-Tf7I0o\b(UBmdJo3l/;OY;2OskdTLRdFb4usk"^U.^3.OmA_kfs3=EP""rMIOnV/R;C#DU"!'Hl#D_s\*bm[/Q>!#Rc+.Ee%NGP1;RQkSl0^*IT$V_Lo\*pF:2F2Ou1[K.S@Uk9(-*T:'7KSm-flXA#jcV^83=$W-H;Ju&I\1tn%Xh(iA_ir>KQ=-`I_[[]@f:*#g4-g@8s`nbl'dZmnU+>=XBl2UZPj%fd)K-,/;J[(I8N?[8HMFR8DbqY4+uKS7:1CU_k$/CO&#\EnXT+a:`l;TLuHbZOtcT=@:sE8*5WJrbRANK6C(LpR"'IikHf*+SG6^JbiPD&oIp'5YJHng#\Krf$K%@EUNUnUadjk!&+]H^pe[P7*%7G;)@p3&0f[@=_J"NhI!,B;Wq"35P=b'9Ytbc"0V2*L7);PSma#k'\&t!`4ql;0,7U\fK.YqP/92EVs`(jT47'3:Mu65H7K#UQi*"QuunXRXo_\AMDHSj2O$-o<5$o+Otu13:d!L$45[@fKo@'6UQ'rlNlH0E`?"[o*PaL-dg*YS[H$7%mFN,RI#3%K"gUPFbp%FfRkc]6@GH$8V3)g&#p_1YH[=?uoGZ"gC6JuN#eNt%;6\JN%_gJb[T>uB]0.U#PK;'U@iTTGrgTNZ*j'%MgreIXKG.n[QX35NMIsU-4+G&E)>-spd9hVI)98([)2L,'_F"bcYEP*e&09!hpU6$cn[I1Q<+si3?C[RTO'@Po7rN1p+T\;dOclDV^PiRT?O&I7u^G,9]lJ3bd,#j<,N!'j-qkle*Uer=K*67dB`/%sD:GG!\8?%"jQMV>KLn(ZK'58J6s!$d_XB^aAd=pSa1c0T@bZlh.$kuSr3t?t02+&Ttk??6LBMpkn5hMa*:enlp13J#OJ?k;'e/`O.-o&7^?4^j?VT$,u;4?nl/HH6pFU;0,5hhjn8_/MPT;Ypi;C?ul[21a'&e)=b3D)J88+LG-N0r33-"$+3'YA54=IR^pMi9CdDK$cC[Xsqc)/2M`Q2PbW,p`e6ST@uWj\*Eg-^;@sD'@0,rN\IQ0giBdQ:QF!cRWbT!`5>a0ZEY4]/s^u&V,Zo7Z%gF766l*PA.)%qI'CmGR2PS^p0:Sg@'XJ^$n=V1.13_W%6Af'j)4FNudHG:=1'RO&oAZcW;.D=/pC=>jL?'H'AZFLTSb"n/k?LI*5="c^FuHVH>78Vlk'Pd6Wbt;OlLB+K6r:NpNZ/OI?t,C^5?<#8g[e6*\OVE0%/VGj3*$t@oLon`g9KH+%%l$53N]:H,Z7r%#nX%o2;t'c$FXo#40Ej>GKNsf(=KeQ8fN%E1;u`)jB"]+Uer[K-[-8s7D8@?U2PfFWY?^32"%pIkDB\u:Y:E$7g]*-/LEfZAESDg7N#,GS^:+ru%@F]/BYe<6SE6QD9:LVK;)^r,'oiR#-Zn[FnX>l>VKqNSH!VhGrc7u))BhSP4"!\dYpJd2ja:,[0noDPUf/[H<;"X#Ccf?K]U:'iHT<*RA6b?d6*B]BP%LG(,)FQ8mT@\Pmn@X0edU?.1.FNc_toqK;eT-PbsccN;/Z:&BHn#308AT+Ca&%u?shS^4#`pA?[KPo*[l.1/=E?rH`4?K51FiA^P1Wp*PH#+m6A\@r7+2>AKo!ZrCV_dp"QT%9m5CA3np`5',<2M%2YB+=7pDlgC/=9.H^rM%mMTfcP6/_\1`ud]3r7&m^p%m'/eNU"d^:)I"i3HJ_[&n8)l.scYks7'[qn;k)4gjWb&P+!%<('b_da,=hcfa*8*VnS3=,+,C]j'-iLYYXRY$#acmU0P])TUG7`YqtmmZFjRHYGfFPSA$jS$hBk::\3*H+`l_P$:UkHLZf#n=/HL?#sfX9!>mCG%bdP[/L7`=b<(R1<"F>n%gkn\^\CeZPV@%YU.fsT`:K)N=p?9$m7+(2IK*gEs,XliWtd\7l9A*agp&ifEjNr95js](pH<.\s]dRa<#@Me4-m*YLUY?g':_%llV5OuE<2eRi+^AC[X-@f-,q^,,Gu3HM=j<>5^PkBp%nQ[4b:$1U-XDnR\6AETaUM55S+MkcPBm$^F>]%H&&i2L8/ONRf?GICGHZ7r45MkL\dYr2nRiF_Fsu]6Too0]E/7^E9bBtU2_?H'N;Ka!HTY]ooA)YUqtEJ67Q_b"t>epq%H2CB*j.bGh&P;:(QPT`qA?$mA"iYURG(bmpeJir3t@rilZ3Ai>ZJ4Ioke]5_#/8.KO!E?o5_KVteR?'a6k9J^a(8"6]>3kXeI%d#,N*Cl*#FT:j5V8T[/hhMWW!_oLrP0g;;BAnFNeTte3ogKR'Tmjpiq2&p3Ro.uH"b)PYd\dk*DDB!f;m942i)=_lXf`;B5X?8J0C>]m],N5r01J;?tN\iGRPD"U8H"N9TK&74Q)aJfk`blt#Z)BK=UD'4FM]nBYZL1D^1eq-=b0D/(L4k*^oFZg"(iIn)5]L3D)6P4ma>)$A9>G&63A<'DgtuD:-eZR&,kL;DVdne[6^EWG#0JZLaNl<_WM>]BYiji\4:fY`hX94@A("9t3FK8b@D#tWgiQA_+Yd*\"HXm+3!qd-b$+lWmec,?5"%b)`>>n=^"D9OLI]Fd)p]7bUf>E`S(._o,jeQXK!`juoI1E\p;?`GK\2YJ2Cb(O\Yf3jef*H`C>.]!N5)m]G5bS'TsK6oL[p#56h6Ma0U!_F0/(NDs6oHV_(>]cqO+(+pbo[4ZO#89A,W2Kr-a:pPZ3$uKegS8"I.D5;[j.2XH!-4OG0X.pL(p6r4+Y[7!Xd\)IgihQ9r6=J5&F$%#]]7&kY>,An'>KT;qAKt,E&/GpFr*1Hb5?gmL.,r/p-moj<&Fi%Vp*_D;V%jg1YgndHlMZ_J"QWFf-CO@T82e@lQ0R/e@Mpl2)+4iN^So;$aNC!mqX65kZqB:s0-57'`XER9955;lFCT.&rfj<>O((0h5h3=k7QX+75WCbK,*a>55MadBJ[IUsa*#]:spcdRk.$W(OlP&+EnpO<$n'"gb9.-In7bN[bjn\RpFEB9O_E!rR[[@VVU1jI05IK)E*fGm93Q*6oa]Tq[@-5I\r4YN*kI`Y_gAAiA?=^B3I#/_u3illV4`lkRNQmu>PJu6m$6if`/-I[ZeLO6qL`n6ojAr9/l-7?tZ;a6,/?jsV))c,:pJf"_iV,TjAJMerD4q12,Bh8L"!pJ:LVqqU\"LlK6"D<-VX4PVenMlW;K/W$?oqn-3D;a+Tol%p$FetrT28M_PSR+NWuLg^VX(d3*d3YgOGoPEn=dq"7.I*5A>@SY3G$IR8;2M&IQu%HHJ;,$OMVlrT>:rH%nhPpA1S#ko[!;E:;8fT:arAQb1-KWVZfC$MHtA:[na<_qaV5-MN!=HWq!#2uO]loeDhaaUQPdSQmQa:\/9rdkB,81-g&JS-,<>#j2U*p?s+q+X*Mqfq;nbDpI5Wo\2YOjWc*#^JBOF2PVkP'cKY_]3&2_=&@:'Zgi!%5J-e"P%>75IMo-#/#A>:Ua#n=AE%]U%`KaO`o_Ga?f!3-+6*QL-h##FuZE:Vl/*o0tuf]GM83H":6D!Cqli*0&]&dqYf8Pq`/C/FZU6BPD>m-I6HG7mIjJ9i3[)c$(.ar:-aKiAB,FfjP!$j8,@KQ\t6&/*W-02_9(3GLYYl/l9!K0=;D.8'u?'@0sY4"+4&$:MSVeFh`iKPb_2ZE%*-TeQ4s-[_c'B'-W(Vq343N833=8-UIHYt`:qoV?l*YP@5]%ZbgrHoDG$>1tc`%=-cgJb@f"0]qf5K$>s]F_51T-a"HI2'%mINn\BcFD9!<1>V*M/[FQf]G',^ElLa)FXVTU40pLFWn=cl^4s4KAX%$nn:G\X*?J+5iJt\ZB_Dq\<%-g=Telt!`&AJj6sf;2?f17JG'@gTN=:Fnk#7"/_AGqXbF:gbDI7l,;jdQ+kfdeMVr#S_..8ZLhC-&GUY5&biX%g"c'0mLr2H>"gd&[eg3kh[/VM;)necEc+LFtFL[Kc\*Wcf/i\?!)0&oV]Y8V9Y"PBJlQEQc\3*aA+[#+Oj@'!k7F.+^f0FT]Xeg=cPLdI%q/"+YM\fPGf]90P`*`Cr@7k)^tV5f"Ni>?8&f,02dF:H4N)JU63j6G(>W,Y3e.g;_g.+!54-QK-`V;]hS/9V"/bANSpE$-N<U)c]!j*DsM9O4cT:OHJ<2\@\iP2BWJ[6YM\BVGh0,d`f`u3R-c.C.O<(#_OjE-_TeGM2'ruWd>,6h0+B!*#1CM:.O]h(ka3`L7%1^1KufY^$LSLIK`iD=`Nc?"/%IjVUFr^6JRg@CpC=,o@9=WpsYtT8&2s@ll?oND@CL%B[n1VZ*ndd#M-h?&'n07gFT++YjldS7]t=NjrU-#o\t?W1IE'A55uB,`CBe5a"bn2JL5%5hFi8i4u-b+*D16>P@))X6Al"u"_D]02^"t8)bl/M[_;7]N*OJ7Fq4O>Z$G.`(m3i=dYMe3N#liiC_bi'"6g=$q2-/5k.k7i%):\UX"RDE(Fq[(`.qH0_"G14C1tXMr)Z:%?60OlM,QU<'c"-ZW"l%X4M0cOT>.!co6amf]/fJA6m-kTL9VT'?$E')`'YT2?ogRmfs>4%=R5U4-KiF]'7gHkTpOa=*'$lNMuDH4O71)g"PmeYqK`GT)@1FNJ>'"h9#@SUc\ef9]6H#p]F89"#'h(66%G42Ik4@''jK9m;Y+Ot'u\XI2RnN,Q_8l\Ull06B`@jMGb,.mO+eJC?@lhZ5X1K+5ghO:g*>Z7q6N=L!R54h,*S4p"fGuB;*="[`1.n:2/tfq#b-K<+\5,H24hCVbE&:b;XlFp$UG]712)Tj2&mnA@23n9gYFpIE5Z_),KgQ)B?lP1aLP0fI-n&n4k.?,%c8mn$`MpQ&Kr*jnBdQP4*Ha>dKIHY_2D;<:Ug^f6^`9+W^rsA2-!+1HXQ(jbH.ecL\]0;JHL>Q&-ghM0fG#&lKVp%_ln[A!huY_h#6("_0hU<sFr_S"H1X_"pJ+_C15=$%*5U\H+f:N1KLF1e':.WD]\Ef3)pkQXa4^(*+tQ]oG4a/=o'On^lkng69Zj,N"N/?!._I$u-JXqogV*t9gP]ctY-AJN[I"T4ff9-gZ8*YR5R/Ok9jkEt2;TM(4,Wbu[kSYCk)."1b?l1U06&R(GW9`TQ"Z"5j.$AfZOLfERP/)7I\!WQZodIZPq>?iISQC+5_qt:Z#4R7I0m6ZM&8<+5^).&2h,K!LB?mEi"U+&,X.p3LnhocQMi0stBCYlk/NnAdj"1+Pnr5HFjW(X$HV0*k]#MJL5Y?b![0rGH)ifKdnYM;4Xc'^\[L]/qBqI&C[6p3r=!VJX-nMPZhR15,`oh&UK05_iRp=XK"KJA*\ORO[@;=P5,mA?>);o'r]A[r:AIi9#QR,XETrsBu[.DM5V9K3<@745.dh@irbg!kO\*(6JDYk(>0\d*GgY'=ZEn+6KN-Ifcg)aDU*9Tc8[-IMB'BFXdU[GCAUG96D75dr<4E+VWh%JGi-2(Q!pB20Zl-FB/d'?,#@GAtUI1T)A6YZWlP_\G$3G-7R:ueDWFLA3U*fiJNZA>c3f6^#H-R/aG*]=7lF;DJ5;G)rOShoi_J_epM]Xg)"D_@$STh4*44*fV]49"]HdKq.QhP4>\r-rdrI^ANS=>r%_Z#=RE%f(>-6N"+Z0s-58pJb#$3D%:Gn&l)!YN`8^[QgP?Q_t;sn]I6i`eNX&jCjKPlbpEO4=EN"*:#e3/?h3mr3F7pKR-Z=01Po+[enP>c[PoAp@i@cQ?Eg^&4U[*T,n._]2cfp[XQdgn@bJS=iOt(J=7@n:riNO'E[k`j!F,Q0o!d/Mn<7UnP9V,^$/T)q.-JlB1jg$i9]c.Ob(>-&k`=FBm4/5:=J^$NH,ee/Q5tm_@Z-FN6.4j.e,Ti9G5F^Xn*./l*X#%WaGWFa]2IX=>F_m-ki?qGF-RB-;l7L^Gop0We*1;=L"==;9tgeB?lFqD46b*/q@n2/RE:(VF3=EI,"7O;5(%Z-K%N[UFIb&jk,Vjm@d#d'.c-9c[dq[]!;U3\kARhn^_nM5f.WmdF(&?rIr8+L9$$hp;3WlWmtDVX8%Tr>/"WA+#ENKQ5C>D2]6%s5;o3X$Ze&%+:(PRNca.,0^Q@;o^9(u5=^i)JeKdEG(j.MX2F;J@s.59f'Q(;.Gg*2,&O4/LA1D>..6%,VoLQFsU+/?++#D3nc0+no64HpLD%"OHjpd(cWA8;62.&m#OkIm[9/1K^WbEg3eo8W-fo+_@g=WIt)pE5*W$1HHDXfU>+j$Pdc2.G6R,(Tdlr:e@l2&k@VGLI>g,>$>h#reffJ.'dgRr80Y0An)I0,?D/=-ChJCcM9Ino1t#eIdWip3jb=BMaecaVpge):,>GM6E!.4!"iAEM/ZCo4?L$U+/bPg)*MLX`A5mB^Mgu9nJ%0.UVnl5t9,#_D7@sAB5+q?;==$b8bcTg)%h#)9)O[Y!fl5:kEkeo6fq9X$js[)Lo_/(q)!I\ADdDG-GE$PY:&%5j+/5>1=tEF3@'tR@t'#Q3K=/pjLf&9J*>;McC[k-:p'UF,HtYIhJMV@q/ia6QCV!QJQ.KWo-N=-S5_`/uXbgX']bs4PDMmu,4I7r'8eL_:R'))AQP0D5bF415_=[UNcV5TjJ(EK,q7u6%I95cU.#L\tO\qNZfB5A3!@u_U`q&LXq+)+%momLlB(QO'tKG)Zlq*+^s.Dg+r9N[Q5c7"]1`6GH#,)&aKR#&!9)9J-ki:875/$h7&H#TrETbp77$!sF!N$1n?JVmg;>,X4(a*OK.q6l2Uo*pm$gQl#YHUF9&iHfW^&m0A#o`n*L:j.5GXDl;TTh=7%W]?28F2LZ7$MW:+4+Ai'rZJ5S,-IbTOY^9!YG.g(^s29C#leHp&\3bV]haatL4[g!9mm>!a(G#nf5XLAF>3,;2MBJkX'+#bkDnq3<4\6UD1p/h"Q4j.ah.oagD,*+4XU*-Q<2CEc%sWGpp4.keAkK%e1-nreX1a?NHH4oV.i=%iJl_>3c1>\=!5W6/Y"2'q^1gYM*GSA)DhY>&MVjj!S%[u34KdG$F[@&%jI"0,:gA]_1XNOJrpD<&pl9)?s0hQ_\L,PP.Y]b&o@]t2H*P]`9tJ@cX*/!C+#oifbKCAtf4.ZT9Q5F/%nPNp^j'`F?(sih7?E'V1jYVa,gIPqi\]u)"mEbJ3/&Js?--iHi:jkF*OQTo51rqeQt95-MXpbrVoPo"UE]@CGsfBepha%YEVR:aY4_fc\J??A?kOlk@6DWfq+4..s)+s*Ba':Z&*oB`ME\$n^%f@_bg=))M7<68ItFApRH%QVkiF)A%b7_Yq_>H7Y?;f3R/aS>;K?$%/,cmcH$IE%^t0\VqM#&rFm''l=EJ3UmmUn`AAkBq<9Z0IkV#2E=Op:RJ/@plnE`+7RUU15e!6%,HWZ\>]PC@'#4'7bPHXo?--pd:k;d'j>&.;\$K"o]==ES$H.Z*=/1cKL6*=C'CD'rGo$N/Bg&s1.TYoG*A[`<*o`lAOaUT&U6kmZf4k;Xr.^^pT5`p<68LeUY]:!FON,SP"?ptBJc`ejZ<,"5F0SA`m"8uLNqOI]5qj1r&9g8&^Z3AEC)pgF:\m]&$RT:uUn1eN_gTk3G.3TbQO@H;O]UL'Y]I8u9dtWLT95Nf3rU]=CTDTYN<[Wj#Eteo*p/X4C2QLNZ&tLI,5k]d9nh3l;;mSeU?4dOu]CpGnQ[nJ?jf6*]I21S^*m[&+e:]keJs)PUugjb5i[E2b/BiPHZ(fV,Qg/pu*53,W9[)4Y%a%6a%BC6Ri&[3b?&@!1da]Z1Ec]>3_p?.5Qp**+B?X"$TRpF2e"``=(G35%>[6kPn9C;1#%`lc$5Cfb.B6j;d<7S5oVmhr2.IbVS]EOFed1gcKn/-CEj,FWB?]Z>$Nj4+g%+`I.E-W=HK\s`.IS.,=KH&nAdLL>-0BtBM,6f353$RAooC%CUgZ(Mb3*9o.`"<76I57audlR+8,/E7%0XT9>41jXUMm`VK8nOhPrOr.Bh3k]1:+Zc8NS@Ar9.@SB1T_>borjQg'Nfe3hWE0?AO./d5ri4*jf=iGo*j4?1<%9Z*#nUqY'&NJ\gPr5uCIs!_';/gA0W@8%$G^j;7Rc1<^\Dr8X*,6%#HYSe!dm[54>%YJHDiRd1fS]NOggCFLlY!mF73jhAlpVH[a[R!H,fi;>iA1lCR&iSNK^=?^5[*"'c_G#!s`_+A`LqcY)`bHdJA/d+[$Br/-a1SNZ)KEnOb'G"0o\XHk[=MFmmR@RR24:+k;g]lC;2jio\kVfEEss!)a*^IC.ZoS[[TXm>SOT+X>`mlm40[$bj8p;<+jCADTL=s`3R)7tZ";Vr@A(-bMCE.3Q%ILj%ZiF!KV+Zu0%=a@DpbpA@uKW^-CY$mKOMsA>c27Kfh9;gSS&i42!(WA3bN%h4WAPi53l/!;3!IC4J*M"%!1/U'qmtm[%.Fbh6:KZXb$0M:VdlKHYM7$f@4WWJuF^tJY#nMULb@5Vi!P._`nY*r&rmnV_o9n5rX3$1n4`L+gsP+26Knt_+p"p!j5r[j$EraCEOV2C#V:Q'ae'EP9`&uponR):4/fsNTPZk1.VckoNML$MVEl#AH%Iu!o,NpG=[eIBk>lF_Lm^ne$.pBe:'M]r9'J]S1[*hEN6LaL=4&XTmcbTLQbH[n,AGPe?p6T$d5B4I#F8)+`$.'flcDmqZ,7uXL2QXDEpQ)`%uF04R.M>*Jd2o-KchWn1?qQlH]'do^+KLaVQ_\oB;n$!EJLWT6rgVmr"pHD?ppc!]T?qtM)rdq8\)Yhi/+=/G2Hpj5a<-L42m%Kk#I_f.chH5At!>?fuOIU2H\(hM)/P,\tuQ59$$D[K'Y1X".'Uf;@s138;Ks=+LNInLaj*%SDG/OCjcX6r'B`W)hC]s9eK/nn)ohFgZbJ+6)fD^<1Ah7O@#fq$G*SP6UMRg_rm1ZZR#'p).48\Mm[orkb/9t_&L9(F@?FC[sj"70Q<'h"(N8%)'cTs[$Y65^Dc^9"5Bgo?rILqANaeV's<3,PV*P>ZX#pVO!2Oo8Oat$[&mCTa];4t\ab:Nmq-aqE6l1KZYTfg1!1#,YQJ5&$ZUt":_e/6l"D-$l9HDP9:(VaIkrG/Cj(A;5;&#@=)0>!oK,Xp%BCoI2?CdndVM]L(lA&T1h,Z)Po6St-g*EcE6$T;cOA6gXV3DS=ca6=TZ)"lud2KDPAYeLbhJs;+<";%?2_:UuGX!n2!SA[r&'\W4+UdFj0?)HW%^i,Z@nY@oRdL`(*KPk,hHaQj.sQGaTe:.Chke/eMPi@;G<4hGqXg*nUDaeQN7OK#I!mlhR-D9PkFMNnqD./nEMASg8q$^1=n.-pkV9:M9s9C#YEm0nBl@@]>2^H"K&G!40d,o;-RdX4;Qr@d"'-1l&ce^;"+42f#>s4d7V>u1Gq)_Z>48BBomIY\b4?]X5A/*6\WX&@oSn;na:]"(pmC0oQpDuI1R=Ji5-6;_h'1BEI'*''5q'g6Rd*%[EJ-UVfj&^:E8K?tMV%Fus>'`t'@BRpK?1dVQT1+h#=/)nV#DdU+je+D&P$ABrolmq!Vpc'i@_>fj]:#rI^$cE7Y3rZ!)n8q!q2O>601WRh`bIa9]S,?7h>QZOd[RYG.GPVOl*F.45NIFt^BfU[7*i\"Cj;SA_/6u+mLf9>^r=!I>07aR(.`L2J>bfb.<3*@[mCKSEpB^YZXIl-C]h=q4GC6k_V%@T?HmQB:s#a4GHD&g*V7Jg'WUpVBnVhVG$e$U7gPsUra0%go'&T\iK6@*Ki54n5t?*qIg4C\f"cl!9qHY#?TXbK?);Pib_$DtU4c$4c1eSJ[++^23VdJ#9iq9.c1YCY9*=f^*GqM\'?-So69GlP#dgLWKdab]m[U$cAjM;K[n7&@dn<1-P$PK$mHJ^G+sYjSrJre.D6c<=!18Tnf]&9EXD$HtmGqaH`0]M>97[`C3P.>?G4N]Q[LZhE;*Ab:2pCiI=W0`rSn+K1\<_E],aZ*^?(9#=$%Xj(V@^QP;a8B:M81N5]Q1C\-YL0L9S>2*)d/iYSY-;nJ!J<3!$:Q[MtCBfN,XRV\D,=q99Lb5+T<6OY`oYDj6EcBFWiuB"A'DWujg2ZgeHPI,cFZk,_4$itfKl8mU".dAo\M7p)_8Bk7'RI'bn>-5\+CP1Z#G^0QWnW:)9SlXsAlb:dYZ.&um'a>!m^U4&ASd;]^4p@g*mTWKed=#]!lP+suP9V?eIe/H^pJ*[jPjP!(!6*/kh'2-3Y:`bOG[Q/)p"&^2J2<:Gu`0lY1YU2/A+!_!R9dnJGIkb)o<+tZ.&af6h0_9g-B\sm/?[L@@88nBE3j$;i=_F"N8/Z]*6+^oZ.cupROPphKl94/qI&f%s_LCiYr1an0<,g!HQ_B_GL6CBMU+u0ut:>iuUMPcd&K7[Y_O?l>ie5N.;\=M5gePo$M@LH$>YY3,a;IpRH.@I(;+@ss$#S\EsY&Pj8;,CB4-6k$<]O6\X35%jR=JH!B!6WJ)jdl;^Ht8@.oAkso;@A_PAkI%n";j5+D6&8Wn"-!S_7^,s2gnC*o)P!t@9R7Zuf+%rn0%dJZNH(7-SS)Vp\fsk`eZ;so)l$f#M+lL2jCQIEP%87f]'\5M-G/GSO'smkZ2W8tW3c5@99/l@"*:[\#_Ql0]sLEc7CsWs)@%__m>GELZ_,^^3ClFld71bX'GgBrt'_M$2-/prUhI"aS[B_<,>oI@T;"a-t4g8RFTmA`PL#o/gTf_(=?;6,*#5pDC'77n>t.CT[A5M"7MQ"V-u'I8I^i.o9\X<%(WMW7\'PLU6earg03tbGB@5a">E!lLqp^Fdp5)N+njYNc-p/F4B/tf$\k#1ga@Fl+Ms6gf$dP1rN!V6:!s'X:^)r1:JiIb7[lYj.PbWA5/T51LDMue3NUJ/2o&!<]$$u)SI`44s<V:q>TX+c,NAEWEsADEgO4cV.j_O\]HTmF^%JfqQDK^L)AuE;MqSV[gJYWHk*QWjU?=f`*M*"m]Z@9^fPWdLS6_\)/!U2pS9!QK^9Hchpi3Jb=^&O$G1ftm]2f_:lO#B?ZFE3)X3)5j(ojuF,uNB*(pPnBgY)@"^#Q"_@u63:i?&6+qF/HXq<]tmp9,o<6Mf5(ZCL>sSLl:i($+r#4VaHE@@GN&fOq$/qn(![mKJKFX'9gTom*!YQ((Z!E^'FKp2s'ogUi-[):@<&WX)7g>fWBNbZgkc*NC^u]2S/%MFmV!VX\sF_U!6hZ'8)A'DKTtGGA&7,Tf@Dol`FPkEiEI,OCIuN-B55GFm)aU/7ti$CYD>f/D`(.F-*\:;iG/ll''J>OC$7tp[[\*YfO+PR6\`%TA:?+`jt=$E&76o?4E6PWOkSXBa3XhYiT,_H.+(ND[cHq?#=*%3N@+scEheaMG,Kh'Jb?3&pib^a*O2KorVlP].(q$55X@/F=d.L9R7]Q8N,t*8$:qh0JLVq%n6OY5ue=(kjFQ76k"I1&pBn@N;IgkNqkB/@^P*!2X*>7HFRK)*8iZUiqN#0L:CpL$afWJ#CcU:@siW2?e:=qg1-*F@a/b3cKF&)Fs._1Af@%o7M:`(.%.2RQ&o/4M"]\&+YlVG4slH`V6q5Ag-M1"3lpq'WG+FHgTe.W6AWia.)4D,&C[M82rMJSCe!\79Tq<=+W3M01Wgg!MG)^@R=Q/Q^W/,%+]Hq7srWO%k]j[lW51Uprmnuf<./AMpB!XcD^C0ODqm*,FXtYk0*%#\!3cV1P.0)Y?U-eSLl^KADE0lDd`"pbb]cs1(G/go2#6E)UNp7K.^9lH"k=aGeD?2-e?8Z9PKWfmQFfFg'"q/YE8.!Ln/_agtQ*1;2Y="G$3o*gQ9[d27t]b$_>O0L.#HP[3[:/VkTS^c??=>)D/'ph=d`[-?&Lpn*j&fW;Jbe-10,3M%>o9]dY)C?*NqfFZ`F`NtnQD3lX0U3Y?M:k@rILa@W1%jRP)E0s\Kuc:-H.E_&`7YpK#$rWM)ihXaC&5pql>k*9p=3L-Eq2^.Q+@-X@J`?W0%ebdS$P/0;h7EOeAI0H)'`'K5.lq[[#"K+tdNd**qK6m=:b8g)q;QP;o4\@S"'U^,\g*Fu50#ef>+e))OGfjV.VZXKD/`r)s2^LU*5XPuh0F_O^n`\$RPPeM%pSiZOaR9q`rpL(:Wki0h=^bA&F"4RjTOqj7BD5(]l;RG\JbjZH%.2JdR8gq!*g674`X6,@>[.LYq*2/gg$sBT(HX6X_GhoZI\m^Ie`uLsI"^Q>PKIf[fi8?at++%=VBp;/1Cb5pgUHTFrFH"Cn$D+1//XHXVX3T-9aXU3#^a(lGGOjHF%F1m8BH3blgXnMqD/MBn@&LVk<6.)"@W't9`Ja%%TD7R)ajah1O\O>Eb%:bir=R`^_N7?m!^mEQl8niK0:OT.G2:_]$$$PM_gQdMSf8E("fF"ZK[*Fi0TS1'Cp%L(WPcHglh7`NP\;2,Nk]?HNB!L)ThrS*)P:.OMJqHiXJEl7WQl^rsa2XbC0fDe0g?i&dr7oCft`Q],52qdeL+nF"X/10n@r-:QnNmb[O>A%\"X#PU4>cHi83>ajfHe\a>V&uc+!/96^-[1*gNPjn2kuTDXKpk/uY&.k?f17C1#<3(SBTVe[L1(]8hXJV+R7eCoE:($$*#q>UX/A9*nFVIrrq3io1Q+<7N9(bPQ0hkdG&['.2L7I_cen%#[/uZr8qJ9i+6fgSo!cFT8eGKQ`kPSFDgZ8*SfX?9!N:".7k8[nRdDH9@KfM_i6D?nJe5(q.no;7a'%((,<2Co@qc@)$r)p2MPb%QNO(%Z[d=49cXFLFo"$r.*piJ?pjtL"A$f\Ia.53`CNH"eaJk^Mm^^0F#k"R5&ZT>AS-Wt`G--fR@%]-N7.02P#0V^dq^P(/\444"\V9n80bLd#f\>>O@6ol-$c6QiC*8U!Kg@0Vg)W.?*Pb,Mo^GI5Yo$2bmmD\8!YJ(oXj`WE,iG3HLm,'_1%+U=8#FNWl84gN6G[9A=RGWF0mDR()&h.WPA[Y6?1*d8dj'8!GA@d;ujcr7>+etSihB$SF^FG;Gd)5*/#+CC*%jh"$3h9'mdRnSR*"M@3:TlIa@+^:TnV,#B=]hS5^`-1E6);o>oeVS9\[j-n6NY.4>0+hQSRIOtc''GM(l]\-ZGt]CHr[2+klM+`-h)ckcadIfHOT`.V#_9N6tAii*2E?18m;GZtlq@YI>6M[Y0o6j:$`AQ8PLOOGlp7l+'++Y$QJfH"J0icmcq1_ta42`R1+?POh!7_QqJaWMP2Z?'qq,E%M+DWmIGHp`uR"khMo9:QnU\)G)H-XWk.3YupiL.a_9Ra5lps.n#,luqk>n$DQ#695eKD=*Xgi5-@.$,^+kKeMCaJ&!/Ga_%M6H+5Ba.aWn!7XGr!mN1cTb%U[;b85pB+tq#-ZTT(o>/k(4a%.gPC+S20-BQco7fs%i%T@Wjo&BrJO#TAO>>e+a&oA\Q:aT(ObQm/6nF`6dT&@.F1;bl5r%VoBJC%g_%M_.J_W4JhX)3jR,Z14#\o7Lb8^A^@/2Kj5/@8_SW,$GVATV70N;M?SKPbNbq-t%Y)qt\4%KV;"f(o(%uHkHAUgc8R=Bd'%%N"hGs+DB3>N'DPE'2YM='6ssOT[opaEG'b2hn/[ErBCA`8a!8UEE`?(1&b;$&'Oh(a3j#/8U,W`rS2&/n*0gW\GV9O>*^*\SprC]<4bA-[iR9a$c%[MBB=SK#G'cuIJH[[cau76ISH7_Ln(^>#2A+"H"F2&ERA(,-^!.$p&*Jn7"\jY)aY,#RTXq5Vtqc>n/:!,5'";Pa8/WiS_ZB3dddM,h&Y'9T?EkEZ!aecW$gp%c#_EVOe-`ggQDAYEgqIIr/LU=oBu!am/Ga/V1)*#&AA+krP'56cd?(un%[VKK_]tD[?b\%=6nS"bo]E`q'>uC=S7l'rcq'*aK95:G0l,J/+n@rFhRQsN3`!F1\\/VDf"/^.o>qr]J0'Sko3hro/ZC)h4B(%bR]-PrB\o!g$n$)g)kS-M)I)5hd61](Yn'*U5pB:^J5hV_f&ECrYM%AGAhE=n>uLg^JrnTcVLIVlht1nhaS3Uao9?VINPIQ_tS$2QgXA?-09&>'rO"`rh#D3M<@NZgoB"<4079_o=)S;ZfG\WZL&i:r'"(uK6iCP:ZB+u-i*ca?7aPer#]bXBk`KsJhQbD`W"?5+jf3p0_u?.&7U\5IG-XZ^CD93^D,k7Vi?c!2"([]p@H>]\*om^gd.T'a4C@!_4GQB$=7edW1fW&W1=]!^g.Z1MqG($!_h]Dk^e=%YiL7CbhS4SkYL*q:2XAI>fXOqBq36"h/@u2oA1JSoiL1!e)t@+Ge*S7fBg9/qgDc-93aQC*OYVfRqO40_08nNASdidW=p.'VUeG[,-pN6A]lcA[io;AM_oDmjrclNYQa`;jeIPlCrM@0)JdppuN*Z@;03Tt57Il;K(oDQ]!A6^sCQOd=UH65*>r2mi"%=2XB&!,@lD7#k7r;28?*tP]316gnmH2$JdO*"u,4tgiqhZI5^V>+:_Jn=:2#r$d<*/chbas>kse%u@I3niIm@nuR\5/,aq)rb?'LB]*FR4%28:t'*?i?CaMVQh;*lJ.#CJCr*`,l`a7S1s$C+f_:?":uEgN->T&iW_5\"s=FI?/^A?rZ@Qqdq%NjSnO$:Y;WD^Z;g[0X'-3LRkD[CfiHX'gao\d>V>7^M#>P_mOj5Pk8c\J.*u[X+5-I]=NJ*Hf4P1s9<#U(/Yqi<-.'^X0dKJI\6(3pO%H]8k5qMh>:"&nWmkQ[ti`3IrEC)IQ6bCJDMg$0F+R5*lKf)H2YIZ]U)3:FeYZ1g%fX\`:DrYYL>^jO[u#jSe38AF\6]S0%3mds36%@^7R:KO/$uJ3./AUpqA_-q6%J6eSjKW\$r,NYK-"%gSOqfmXP$3O5c1)rE\9`9>mIG?`a)e=ej(0)4]@NHgo(R:Ysba1uWl/]8l>ujpN98I#V]e")J6E$ZE=L9qjp]L<:K:T)l`oOj]slXX"=[I##=T*Pmr`$""Z)3@q7ge_XZhT#gbY8W&0[%;Q*_p.OqHkIHOA(A%>n$@-6QN;,tZiMn%_[oPi"4cCKil34.pj&QJqd.OJP$PrTaXAs'4!p@B;i/6+BX`Ke2@ob!E9(0/1'KpbS*"9AWKP#0+G+Yd?"WM]nV;(@\HH!iM(Sqc%h%L4Ep$1Oa?"eFZNXK=hM[LBS.".La<>F.?lM8SmWssHon%mIR\?F\[bVr,VXnFMZnn6c`-k]Z+mkWUV$,uHbX=q0BHPHl0!Gu5Gi7dLqku.Lr;[i3Z82N#S"u$XI.@&fnW"/j2M0%4,sqI)t*(E/mLoP\XOeaULFe3$%oU;5t1p8EtKH?;ZZ>_!@K'\K>2cnNb8nQRA\E$,9dY<0![TPU(-l6';_4(-I%Qj%5Gt@7EP^M-8)E5"4?P902>!Z9q61=RV36l4#WbY4PIn/5^BXpKSRj!asWek]dVYl^2-m3b^rR\1Xs-bEm"3%;!)\^6>YDg$Z]N4=N#9YTs,pe4+-rWC&Ibee(;*cpbe(mq>KWGY9Gr$*Ot$ngl%PVBBJ'o+>piR6h3&0-^ZLS4bCD-XG^l,_AU32N1]G@(HL33"nc)P%hEE0^sVNFu=6Hei?5IYu.C#84@#,lT!K=kYGdN^[(KAnI1b8_nC@-;c+7#NP)Ye`#cJ,f1cMl8V/;!AH">Dn9o<8J'Er$:LM2DBS.nASqf-BosdjU=16WS%O'nAI$Xoa0_FLP&`ia.&:,1ORo"/CC#m+KiIc]t6:7#?%B:c%j,e4-:BBu16/`[P#>Ca0m'"8!12rH82NNI*qc8h-"XV*SOR5M;GZIn1\CE^ofu^#aL(5ID1_G#*Sf>[h<>!*caMo]$%F`n(ld1=O*3O14[1ZI/j2Z4'k+W&Y6GI%:8gVEWL'Le."hDXLAApH^h79a?ZD?Yl2QTOGEI.'OdnJ$9r@*LBm9(+?sL51h'A-&laq&7=fAKN02TrsFA]c1:hENOoM6Q:I\-/n;2pGFmXA32jDa!V8:K>tk6]p>C'e5BCbG6ed?AjVALP7%ZM_]BAINGHWP[Mk!E&5e+-7V6>$tW%-3Bj84"J)UOjK8)Z_WK0[CT5icknO_\ocj"3IOOQu.mFa4)=e'5r]mr8/no.E*3/s*L;hL[kk0s(!MPR&3ClI2<;I8Y\PE=((\'ho0LM[X*TY+C71>Il*+iuJiWmGf6NG)%si^j3TZr8[`Ip"R28P:om+XT,Di/43p,j.3D*b&;I95-aIWiFFCDJSJdNC'MCnqB3'kY"R@ZM1O@R4;,=V(V>SX:M$>VhZBCO@3AC2Q&dMq?U1gFdqNFsTd;/\A/QRkTX;IG=<@r'tb_@;F(iRH(m!MB\s'T(I@4=LZ',kXS_nCE-n?X8c'0E4b[m/]t7G(2'kT$]D3kC>Kp="Xo*,fs-j3LH.SR07aDGLdj<-1W(dHB*8kE2VoqF^>-9@eqpJLm+N__S%s.saL@X-JWQVE@%;lckZr^VZkheaKooU;P%m_g)t(G/fLkNjn#=n/27s*KG<*CL-]_[L1+c594OFj%oQ#+2b")\kIOC5<]FWSo[;Pd@6m.Z!"]N6:WgWV\K\1TsYk][5C=NJ]Xob3Yr.]`j:"EY',h&m\95-R@*MI^g9uQ&GYst0J?Wf*G*<'AV@$&#<\OG[(B#tM7JHVEDs_E,o*44(;U0dLFYlG7G4q1]Rj4k:-Q7DW^`#,;\/JeG^K\`4M#UeN*.\ADu.im4I__L9\c!HRRoT)m7GpT#>#VRZfUF>K8:ra]_:*Z2OQ!H]aRJgX-;p:Ui'.,Wm47jIsDoA\]7#3/gLQG3#K]5g@-o3sN7+4F]H@K?[Qb_iif%)E0d3Y&+m]iJ5'<(;!$X#hichaEU%[/)JJ`RkAr,`2NjBN`L.RuolFgFhYs]!ZYrc!jj@>=kLKMj2Tru&KG>didpQY'(193s?:.hb;/pK^aN^7F_7=l(]chC5Y39A16$!mWa^']8f4uFhKS/atfIn"1e.!m7Je!CqI'5dst`*s(9Q$!@5aG==u<"(QXG&6go=tt=I`#h%R6"_2Q4]_$oLVLp`f]SaI(Bf^tR:aN]ArULk'M][e`2">i(?qO&kZA3c(s\q6Sh#c0*=I*n&E=785Bc^=ihY['"hhJ4RRlt\S5*1[frI=9r0af.lciUjgWU8q4lmQ4#nEL^Z\'^:fi%2"i$[pHBP:8N\Q5,:otE!%AjJdnk&dmF%4AY!$)=)&9\m%q#%cJID7U@Y5uB[JVB[OEEK]pReJk5-<\^Km`?2\80(&2paf)\?6NTTNq%S+1W7HlA,\LceB);B"RR_5#MTKZ$o6>I%l]*kPA0BFAS9`LOYY+1673.IY_H''A.6F>'B56"oU'7(b\lQ^.Odcrgo;#:j?t>XgMpU.a"`?SL$E+JM(b$ET=ra:R)o=&fQNFrQT$L<9U3cQo]_W=J:9:SRI(Q9r)@=iJ5o7u?R%FkX,L=GuRB=,9ZANE4Je*NoNL5>(Z%[MAc)_JFZdsQ[C]cdFVab;I>dZ^*Nu/;D\?-/Ws\YV@>/P(U5P'*[=4RLl)+$3dm99D%8$Ju\.UjS&.gb3mKbM^HLC#GPM\W?okM$371:&c6FY8DH#cq?4\!(OE\(B)B_nR6;m-3^YVW5>0+#f\cl4%E99M4!u\gj'j3^/XCL>Yj\Pq\.?=WgjsO%IAmE$,ka4'C@U)j+_d0#e"-#)+m[Xk7:\!8[D$u$VZ0om+#b/RBHC7(#/L`4,bm]BTZ2srX>(=\4$D&MApgV"E5n:Z[*I\>BZkBt;3nqf4-OmF(O(pf?.DG(jo:E1eW)Ud;WUl:W(D'NH3n!B&Msb^o67`k;XCng8YgNq5X`YXmhlaoh4t7up!aM60VD(S@DTa,/VR2M<>;JcIR8r10?SdW#BKO9+.-luhmU!dXg#_qISDbiK4-fVSn"`S$-M]gn*E2co?q2ChJs,F/nS1Ze=O6`^=gPRd[[<-?arq?DJnAp^6i+<&'HJ7]V,Btua-utj.t4`,Vd-n(+gtE?I(#m8Q6NS4!U2.!N2C#mL/-/t_p>-2\bmV_^RbR:;9ECuN45j3bE'Z**^!`W#p03+bfQ"PTq]TLlcrpNkAMs:"P('SE`\f-<=EVZR(Z^`FbkBNN']TdY:V,H0-W'Vl#pnPa&m#6j!N``rZ)^+0d[CNoW*l#EH:itF!Q<,:=BMtm2N,kU?_)@!P7s7":\HNabpOeUXN3.pmM-;eF9,R,E+h%WI\-A>tkJO0_cQe&N,+bh"$u7-/!PLFPT-)b@(%-qg^jMMSq4Im6&a:q#6Wj+!)%8:*@_UDJt04;<%\25kHF*(dl(fF`9t9*A":ahho%e&k\ERaX@^moYL7#D>XVh4,PtbMB!l*nWUsQ11:3LUH;k1"##`9]8=_g%@O0IK&ARl[tmhTUWiOXm3os5iL:62iS6WqU`7?3eW&9%s.9?RT7Q6IlStpPL`h"C@:_c%c#Yil,@r>il54J!N1$c%6kIM&`?J1t4*PkqsV$b_pJ7!ogb4rgMfg*7V[5o6s$(T,olMSS5Isq-0qFr*8[=ZE=I,1i;oci6M:l!&=K37Pk(Bd+nQgKLh05iP7+^AiO$#5#0W_nJ.%+FjiV[IoM36almP8p\X/*7&I'H8k.'01u7-%DmT1mer\?iAhc:YH_M(0uIPtUjQNd#VlldsF28BVt.2Aj/GSu)`ApVqmNBYq@ZeaBt-\t!7OMnM,7$6lgpR7_jtp#eI)4>3e4c\*-JX/T9C_BVe;r2UaL5)lg],6I"KN/LS99[%\g,<[[m752]U1ehc:\QrW0;rfU$@UVuBQ4DX.pU#p#Po8$s5u1&>`Ur]nq=`p:*6Xitk?&c47k.5rgI@S6fr"FnG]DghF@?=9an#3@ou`T;bhH*g$X79(j]3cHMp75)UZ3(j-[ZWH.@iI3;?Sn91mWLJLIb3PlBX$%]9bXJth0S03_oGdD2LM+IGD!nV9?X_,N+2WP\EmC;QF,UA;A(8(PJXg):<96cD>UDCZDY,*UX:P\!5HUpJBhSO\_QuhT4gGq0;h]SZ6-`s8gVB7H""/g4JrCZS%g>e/@`83N*4K)aVcqt3\MWs:-\3.tODN`(GB+$hM1n@u@F3KVbj$J$3=k2IKhgOSo.GiiG?f!_+3*IKQ=,+3XpBo:N8oiVfc>^PtJFsY]K?G12]e.ZhAriB$bV+aBDIHDefigbDFLDDHEj(,9iitZU>sG;GZq#KQ\8F([a``m;0&(q1l$DCT`7-a@->&F;<[$^JSqaE>gCOTN)JR3la77:K:f+t]R$\R'UY*MgK`T0W(icVU;?&Tc@a*kC@S-m4TEmC]&eqF@iooK4EL3DpA*_hH6,t*B)6chLA0)kGjXJ!q>#*lV=:\;muqE`eS.S71B'ilmcR3,lP1[diUk,*iSEGeEb2@n1"'UI$?H_KiM;FYbD?mLUAef#L&8?)(;HDP)G#E-n^!)13^5V@Xo[>fpuSo3r_M=>Q<6jp;p>(ILAcibauPp[I\U!2^RUP!N7:MSpZTWCHI^NsO-S8QHL#^VH9FRh[DKW\N,f6K+ipk!f&KilK"GMojO\pI2enBpmQ,HhU[:[PTj]1&=u5.Mnlj`(-4ThP*:]k,T)_#7tdq%UDKXfB_O-6XhWK>iCs-ab.L6Th)@[>%S;kkG=]-d=*b@DIbae@-Hld-KR8h(^dg4m.66d^iD[_XWifLB3*AO9^F(%HVUl36d./u=ZseTG3iS5m,ZQKMlfg&?^4'>tO+Dkae/;*/;-YCep3^n?c3c[kVR5SP%($uO<;q2*.ef.TU\1OMeugDh1k(Z`W(1JAN,iWm2Oi3#YL._j1uIGIC1TG4=ecC412\8#3V'-A,;d`Ob':Mkf+2n1]))_-noP2'[qp`\+uL6cj)GRq9I[*oaW(-0!KM@e%(>t>nkQC`D19q@Cop7l_S^L9$)dAFbs-t0Ti5#N\!r$l$RVM.h%Q!'p1rgH'hnudpb\I)=!N4W5p@di<7bJ:1cWZ&-d&:X_=hNcolJPhRmdJNu^RDkXDAn2Me>O%&q)be_W'1UqH]IR`/dV8cWT..BNd:*r)W'O,rseEn'Z5%Zk[l3^,tuW0Xn"(_+URga/CGFIi$i/r9\nse)B?\k"eiO3nMN%IG15Te7c'SMcPqp6Nkb2d*5DglXk%+5>V!U0eo'd@ieKGNZKTY`A9Tmp>U0ZOP4IZT>1>ST;8UQ];3932)U>V`Li.UgMtXNp4Id^)<>JG2QY<-C!#:]+N0eDTrd9:*j3G/St>N9rSLon(utfQR%3Uqm`1]hOc:0Ou&aMH8.;7#QrpPIp)SjN7b*S-Qt6O08@qc02D.H2)$t#m)GnFfH4+o52'C;7d'@[=NIsC%EbLP&pqRM>oe%!*0$S]4aD6H2q;FHWojMcC)/oH6=bkpk2g;YIoir/Cs:G0j.FsnQ13+PFKnfhd/`>C/T/q,8Q_S*AEFWF7`U)$h6cYapZP-4Wm^Jr&#W3Tj_&rOVn[N?'[.j^@.oq=kSCK6\\sDEOE'V'C@8K@5X<:8G@oY&nu3o982`[bd#*c9E\YF]XkHr;,Ti*2'2ViH>[+'1#s6pQUp)aN#uX8D2(,dXp:!mr?H-LrXHqG=Y(6@\\-hdA9-i,f)*YqW1@t>i37trQ9-eeN5JZmB5DM-.RABWuPg&9O!@IjBWpR)%b0@YnSaJpdueqc]<_.[u8C4"n)nB(DrP<$Nl.ZY-Yd*]Y7`siKk1;-H+(q\T"^#;n7A<*MK-eLT@pHffp>AC-%Al7Y_)(hoD'paTDP]g.\iSaNM86[XAPkTqHdf^5`Bh2(<.,#p^A6C84kCeC:5?8*e7Z^Q/I4BOM"MJf)%#aL3&MofK2,8E[<>-Z.'[%jRMuU:l=O3ngj&NuLH*Dl*`K>nd%>Z,^T+.pUi)\s0Ho3!WN'9KPcVRpFZCnJ_`Z%i7T60.3FP'bVLaA1Lq!s:sMV/DQM?4"(V3]A#Qupt#0]L[<2`f72929"1.6,hMO`P"'k>m0b$Q!MJT#-t,.^=NJg`pBd\D46'Y$Iu\-TXe`c?X)k,`Cj%Hg(H`_M\^1EddGA`^_c@T8"lCOm\5RT(u&9"0?1R4iD\mrS/?-."^Sb$jjP-]Y1N:cKi)c9ZJ.[NANP\q.=hKL"QpnV0S8ghqWUWGFZ%ijVBNu@J`FO1/7^\([s,PWaL77#Lq.U"2mYM.-[BY_3O->o,TN,6@aRA6Y("C$48ZB"^Im6+q5!:,dA;*<*>'H0CFO_A#TL@MiFS!(&e!8o2Qq3-diuP$G0TJlFl=+T)jGuJ4kt/?`Ru.[SF9l%%f/d+1("2:be^7TkRX8jQu@o>O"NT@bI[&&tp"oL'NVp63WRjaLWaT?5gGifV!fN+Ne/uZ9Or@`q/6QL,QJqM=8^(T#Y.4gW^KV%epV-HSMf)JcL?.ZZOOR7RAo\Arsm\A5,@/DL9d'5p&4j0?]KUH>9V+s\#t!F@-5hVkdQkkRln3kP["t3oFasOX4$=_^:S^&WErH/&V?:"f#pV$]f.IJ\?c+'pF0M`CjP-O3_.p\58B$DlJ93H5SYq`-0#@'V3$pT4E1'Kn%8l^BgU[l7&DWhn@(WIILuoUQZNejT@W()G*:XG,Z0584&N;F[]Q78C+[g<=B:[W(pGX>F)up@Yfru9>fr.a>Kpd)."i`Rn_hD#i'\$o7kpmVgk-(cJ&.oE@.oHjD9RC5Q@O]@`\AG8%MM@AgWt0(pj@/*8.;jjV`?So5s[[FE`09<8G#+XE]F8:r]V8=`R+L@;lPEGY;b6bH#WB6mV"V;@hAPa'Ue7(=@jgE8jYn=+?a'pY/[\i6OemTdtZlt>E.9]"&epP#_P$G0M%9i3+:Ku$p/*=lD^e*^p.Lu5biNNHSb3WX(LGED&,k*74&s.K$*Np&A+-]-s9PK,mHNDR_/R9OR97c8]4dW/'"Isje"0g_dj63a.&P.P`4ZkG:o>Q8^*d#\-L[^3=?NUP6iI!:<=Ai#'@GfOoQQbNT[qD=d2iO+FNGqnaAWI/R6Uoj;?lK+>ZMA':@:/ZXXLY8i,PkX#*9(ihDecX3jZ.J)*gf=5BB%1'bGfsLJC=i$lTJ8UjT4hasm`(Y`=I;WenM;;*a2>"H>AP@1[]nE-;iEgmr_RrLoIQ7ini5d-%k\p?H2b1GCbe>Ei(sBe1u,Kh7aH6U2ooMi3_3>@kSS>kkgY9B68U$<;5ob3U1T'l"U6*cK2!X*#@KP3M+dGm[giD38N^*LMuk\,?aY*I04<]r*>*bjASCp6c=BPVoW];\1T,+;R=BY)\l%'WH!&KT6`2^uskLe&tI`/ofhUqDM-2_[#()alDZZ"Qq#IV+R#U4G@kobm-!g8lfCV-YO>LeRuFe2G7,a2?ODLKS^4"L"6b^.H/[HR(IZ3GHu[S?($nT%Y%3QpM%8+%A7?6>fBkiB7R1%f[1H+Ds^PP8q*-,QZmO"'JKWD@V47RVM0*'I;B$Z!gd:lanc-rb"ZK`lqeH(*:#-ZP5(h2nrOL@gU.s@@,0AG,C3ni%=iHbmY=WV;[+5odDJ/:(#Ri=T8,#WlW\USX_0HBq065n9P\!R)I_Z\Qu)5b8=JR!n#g\s3b\GkN/R7]8KeJX)3Y1GnFt&>_gLk?S<'g/G!;@"oftOk0[?nV;qK!EMPk,0eK2--O[HsNG_E>7$!!p7W/n-N,#)JYcoW$(]flF.&2jI]#3:;b2GE1JeFYOi=NB*,?!PhGlH4#DC6FC92EO87gGWPpJWW0?/j7"@]:@0X3tmGX&1A!u<]Yb6("0JsqMomInbn[E<5,+BE)0ei&Xo$imK"rK]/aIO=0jg,F`>[YKDA^?4clKVX;ODhbd/;*>F(fQYs3h20eR'eVsjNV`3Rs1SF!Srb6k3t64RAf>UZSd`@14@5dklssl4t5gE.$T:6i"B]IMFeC94Jc/1p8Q'.6NTNb%.q@:dT`mZC8TAf#&%M'bW22:"Ik151RR-"a?/rT(e-Y*)Z49r%#nJea/2**?@MbA0'(%Rp*o.`,D&Xc$Zs!'0pIMUHMn`L:0\$tl+HXa/lGMA'i]lT'"u<.-cpsJOPrfD1'=OIK<)XD,pB&hh4m?Om?do*Nq#,T_,hTN5hhfthr)pJ(h?R_FB2[E=HJ5CqiU4"G[15:a3m[X?ZX\J]>&H%`Ut1#a?%q90gCX9ha$$l:@IdNp7aK3_UInmKPXcN_IW-:V_98pdjI1W%%88-lhK6Ze7!2#KefcuUViKOquim6Z#DjgJak,n@6ko5Q8OcnKU23P-8gj=4i&;tU#:n^8o-^opI+D@LYmC'/bY.BoH,[9%Z5.-!/Hp@usgq&&-!AAB]Is1SUJ"Za)ZQEi+p-6N^HJ9dVBf+@M?C-WC_a^^)=8OjelP0?#'t<6,OoFh_@Lf7X97-am*\PYDr4ZD9\a3%1_!["VLEHd"lJ$CFg%18H%Kc)'2_5d=dcl+WCoKF2!@c>UJl8p#rll&#)kljjI-ndf`7E3XmF+>FIF0a4KuC6f;$_C-!(CQq)LkUjBH-Y%4NnXt0)WrOEc06Y)rSWZ2E+(s_/7%^H[Q%.qtI:PK'hF#l&/Ib(VGJ1]?R)BG.Mm-5p24e$I!r'sSm%H6("(Csu$;\IfM5/bS.9:Q*dn0G=rA[`:eOgkFHdSne[C$;6Ba:d=On*kp5a,GVq?,4b2`,r^]F+N5#3RR^C9nA$Af15hmI$_CNk-\qS>U)P?R/N5MaXPHLXFoCI.OE%I$q(BiFrt&;o_fth!ma!9V:,K>;5;5EfnO&BZ-dgY>#QBe'pW#s[r*UX4P<`!=6(VFLY6Dt]FlQ-JO.W3O6\P:,R5E]\P"0@8Ff_s?[?H"OO/=7)[.]%-aAuoU*>([!mH>)QD=b6ijcuah'Ghddo9X?1Gr:7,Oa&i^hPq(N5GS%(H4Zf9Y2F[\cjRV)K@#uJR`n?e%F"mnQ4@i".7VbG4sH>kiHi9`*pp`f*`ZX_g/%..U/8VIs3gm,rVDSDL7"u1[h*$gDmub!_m=?BjloR1KOa3jPUkE9@I*=q.^`p_>*#d$E>8Y`H`79`O0!'-F^ZheEeD&KbDNLJDCgGa>+3"A/CluR(o8\K:Wft]lb$!n'.!PNjsVuZ8n>+\PW$A'5D,k'TbER#G9QM7[SfYh@Uk_`8,ssilVOqV@o3LlUtGch]/4&_ae7[_[WP^Q.Dc\Lj7:1R]?^k=KN&HeC.@+1K[&/5S4Y;1/i3WD9&UeVBe>:W`NG^7Xk.^rRnen(Xg/gEO55aS;Dmp^N\jL41TBr3=DeP?&IbKSVaLpi..N\&Rq^j$ZTbQUKn4WCOA4bMjBF+o.TR3fJHrS8@mVq3E4VMZPl\&)gTVJ$Y)%"%6ODqUi.&+lmpuaEiNrg62;=.8<)\g0-VoS*FL6s"BZ4p\T%])L2fc:cPn#:-j_qp]!GP#G3/>pq)DG0(T6s,Jkj\:p99Z_^XaSaUn0r%KZG'\ACCfM5LRUuJLI;+OBkAlb-@$1)"+P-nQP+/:^F!^3.:%COiST53g_j>R;@nKqm^H?Z=_HVJ\Alu>+d,bD5[=/7)".`NE]IAsq\mP?kqZF6f8q:>D@Z4TWf27(5(6N%gGC0%X'NWc&OnU'?Ca):6n'=3g94:d[&*M)mb\KB/Bnr&acB&9*1!]YjNQo$:>)FR,`B'-M70S(uEP#oAG09"V'POQ9Ne.dM\"k8B$L>UMiPa&JGfRmU?1>+*3Bl7Bb_rT.fdRjQ+'K."W>Cr.)`3u'#uZpV1";:DKO*0Vekfn;kD2=@_hR>+.:+Eiq4l93qeU"t@M>>BiuoZ)G5oU/:N"B2?DCch0hc4HGEQQF8*iIgb7T;#:k]>HN4"?D,>N.u0"*SV-0m3F`3+&ej+S*Q33RZo,>V*lDR(6?KG,VsI@6n7:FK"7s@oCJ^j_=+urJmrEKWdn(f%[a+[@?\Oqo5Je8(U!dVc^&+W1-HSe:6-_M*q$8+kCW\nbhL^N@.$psj3(QnN:.t#2TM93*bHgkh1I!&7)>3aSbnHRRLHJDBfNqb:2gV!d(u.P-DO-JOfr"V<6R50.?RaISIZWiLRNE^Li063pEA(N<6HHa0:bI-P>/afG0)d&F<1l;fO>?6,8K6V[qM2Ohgf6QKGkTo&GL$uc?>HHm>CE=U,OQ'<@8EQ&HUQTO"@AUU,F2C-Bj7SbV,l0(]HQJG4LfP5fr>/?N7/%m2fB]Z`cd5a$XYdTZChNk4e5Bh*DRd[E1esQ9CjB<%\AY'!5D9pn7KaZcu,jU\@":GYB$T_oI_5`6@+TrU@Oc2GbK!/h78@rDB/ukC8\#/R["tYKHNrKq3]h].&L&H)O0!dZ*4LodX^pIGI&7)tcG9d-D?lpd1$NJgbJ_8W2^ZJ1K:8$!GB`A\M\b\<%S\XE-$^'j!u+3,RH*;Wc)R^(AVqM&O.I.r"!r@dt`qWD7<6dh)=*f5%L0o`Ob2-Z@3ec='Qb?@?p9qOd$JlH$DLM^(,6i'6mlqH"AN3lNBSa(Ee`um\/Pb$g*a;CI`>kl<--bjr7[`9")rXLpGL\WN(br`hA"Ts[REnNhe/FreHNW6@"WfoHJRNe9E*XS6PmQLAmJ3"C#YrP//X8,L'Rpq$F]+)g0)pACO1FRK)L@J\9rDA4nI4/2-%Za"a@Z-UnNIj.D+U\O_TE-Id[aO&f:mr#ms_4JsZNR&J%r.3bW2MZ:1]#E^t=aeEu0P+^NIOIPLOqWG6=)Z_CLTfggNPj'Orm&>oou`2L^Pdn&seU1mIu#N1j#D#]O7[*\V$`3PW?"B>6(,Cs=!E(\:CiM>dKuR[2>0:13&QrZm:%(ZpQ4D.--ljFdNnqA]r*8=:UUJ21dF<_'CQ"lY=Ht6=A#o1)R%";DD33_YDq]Z6Q%5,K_2u)sPbE:6#_Gki,8s.'h*`1U0;0+7EXZl:m]/N[4K(#%3M-kMlDBgV8cpjl,Q]/oeK@(JnQK:h\eLEU/U_\/U6YP)+a,BdM*/Sd0q^#$i)!0KqLPHuakQEA%aYJ>[A,a4Gt,T^_+u)\]*KCXtkBL>YRoQTB,8T,t+n(l,>DoCh/")rSPK1G_/<_h"s6n]XmNe(f?+m(aX3="OY,H-F,(HnN=;&NCq/aVIi#8.R"6jLSXF5WYSj+hlBT7WWTXTF;:cds[.U"bmEs7>sYFfT?gYbRm?s,>ORMa,Hd64XoN4"3?KjMO[Nk2IY:UUkYfF>6[e/3LURq_)SDR6Z#UT;ZI`4"lSL!blJ@b"G@8;/4$2>;cOlp8(&$_j0Ad0!+'UL.7sa0S'@Mn*[I]FdK`l\P+:eRZ#nMd\In1`IQbfkR1SKSrIO9k5^#EZ0-VPiq:PjBViVGC7.u"="2c!Ug^Ji,Z4KPk17n=>Hj*it5/J0)(571"nke_,FU4mmVXb7.!qM9mY@mLcmi8L8OL]A4GtMKnoT&_^jV'/WX1UO?-ii*5o/@s4KV\3.;5kH;d4L@YEHa^OquesFU^Br?\g[s0nuR'WL"Yc^0\f8KSPB/^8h`pCL]F,_,V@.D(4Ecjt%4;6:F$rE)NLR;,bQ\JZ<[p^+(YSE3Qc&g[pc]sOTBkBED)qWkr!luHJ![4IfO4Z=6m:>Jd16"(Hs#`(S%[q+8(-\c^S+t,=PN`56uPiVU^Br,0[IA/^5driZ)o_6CB47K5_B0C;L't[;5B]6bqEG\eei>*W'U7_!R>VDVS,`mnnhUlpU&u'MP72"1kmKZ(fKkk%:#aKYNsM@&Y=u'M[Lpt8c"HR]sT>;\!Ea3\B9p:2QA^dg(H:k$p]@`4l6!9MeQ%Coo\KpfCV1:H,(U=mJ24<.]5:p!fF_f7jEP1bsq-C$,Uh"g_XZg.X%lYVG'F/Qnf2(hJP^ZGn;f'8@5o1jP]e7IsT'o%%d)Vh]rV(&WuD;TOrO3ika]QI1pCTOhS38Ud^;BR'=m-m/",ZnBQ[mZupMbj5gY/d!n85kLYOqqcki:!VqOSg(lTj6l7U%mlX.n9u"JiJ@W(8a&=p]%iH?*#ir8Nj$rjWspp"(^obU2].3Cb!Z_/P-GiHM\"QHh6W>$*M@hFm/SF@CV2Z\'k_V*W61n`X0.V__(>u@2bp,?26`0da<(*38D@d[LdWCT1LWl-/%3Y#%K`X+&,*F@T/'(!Pb(U@%KKn,_S"53RO^aF?O>(17UOeW4NS"nQSq_Ko"IM!L2^?l#ZV:ZC@baK5$/Q.^J[kBFiS^;ofg-Z,nj13Hj;Ef-&I@Ue4BlbgVk2_a*hI!I/>SEPnO]'.Ek:m(Gd(&/h:+r\Ue*JUsnN)[=5(NBHlrMl&6okc9lT9EP%K0nKBEn:dplXc&o\XV-0NHpaI=L"qa5?"?(jX'nBg"imHs.Zj:U%Q4*h`-BG&%a7+/5I3McDsSp9$Oqo6Akd3#G3!g!N4/l4GTu'u->^?4pK&./Lk"5^GNA+>%)7r$#_:5GEl[dad.QRQp\CN7\;o`Lf%_Q;qlV:BnVaEKGKW7_Qn;$CHg4%Qs'S!Y02"]%frij&&/9F^Z"Z(f(kii4_\7jWE_fGpjmnF:S%bAQ2&4nl'T?!+@:(d",hPmd/K;e,`iPW^\&GH%(fKKNeTKqoa=U%.3":iXHbe]:D01Ok/Tn(SWV%N4`^pA!M4_ID+Pq3P[OFaFVEA0Cpe?q5JFOr,\0K!8E]&2Ui64^^'r?7rT(EE&t_AQF:SPIWa\?WKdQ%C^3G:9c6jInef:W`J4+1b_SracF4MH:tb3:rKp4@rq?OWP5;fo[`6'^=tNQ8),e=A[FOd+M/begR?0_'qTKbcAd@M3B?]6&l\>AKE`=0_"PgUhIHcrdEFsn&q^(2qF%6\mD(b813P;8CO,]Sprb2]REYML'+q\ffD?BS[oEM([mfL@O.Zk?m2eoXU?8[b<m"m4O?N2`=T9);#r0T^31nPe_=^S'j6r9dn[Br4p_A&ZpsuR&r%Bo(#Fh>^0*a:5e(M>E7Q);"UoV'=,n&isR@5gQ6bTVrV2'297!(JFS%4Tdn0R8AniopTd"1=Fo.m$r.%QGBrG!M"fFL/!i&kKpLM*bQbW_/lo3_:c=7*@a[sR-&'shP;hFBiN+g>@O7JSV2bT.58p3WEH*O6^H\9cG)]%:V7DJO2"j+sV+-H$/dKSo,f?Z9Unn-bj[!dMe@1bpGM`Vp([r]K7%_dDdqW93Y82tEsu.Y=m!LTJke?EOH9YN:%B<]',VQH@)jDI&NPrt**_;I?mUR)Ulne,h^:J`*B::Zj#?*\N!ZZ&_-tTVNd-^=#7LT8)O`rar,hPEo0g`nTennG&Dh>QafM6AF7^PPN_)d?Rd+O^\2-,uekXs@>3_163RM)\GhD!tN$fM\M(iu<+Vu2]`s/K>h*!gm&PP!H.McQhA7>jB@PUUcjCn_O8pT?>=Z7c,^%FgjlON6S-90?j,"Xn\Z9,tL)gTjM*naXn9n^MA\\E;TP#u[mptXK#cOH'X"*S9:P)tXnA-c]O`8OSbT022>@Q?4um+&@p9rLuE-uii>Qq`ApX>:aub-Td+&Z4_$?DHdM6>oE6(YHQ2*hBY18"-b?;#?,)V#1TSIE+5MZ'/:%U#k#4oUm3GImCJ=lI:LZ3`[9WXb$%&cpN'L;l@u[kFfe5J0ntj#9o$/>,4]0jD?$'E"MS\*P;Eg2@EC&LZ"<'MY-uMrKLZNhtN1oRru)U<#uM1X%nVh.;/u=9;L*EeC_lnc[WK4mJF;QK:k$W(M;*7"d0(dOJ.W?E@Q_)HCEcC"6pFk6XLHF>Qm>&-O#)Z%#:!!`T_R=IZ9\E2oi=jfqQQd&["V^^fV)\P'PP#r.3XCdqiQ%2p>kFrBcGCJ`UZP6N']?/5dZ4HJ!`Y=7KYs\-(&KEB5oaZTHE(hi;-a(ji?+Ho!%^BQ_U0E5$W2*#Fd;$0K(6t+Mc.s=3^B*q>IR,)$eeXiBJID`%[")8d6Mm^3i-FgtX6.`X5MA@-Iq32;/J?@Df"oCs6o,AMe,p0d-Z#X!#K70WLTt**ilKX,2\/UV,OO9RJfp7RcMf@Y#"eQqD1Db;14g9nH=S+iY!6dNbJoBs^#jLq)[)gd2Id*#rVLbedkH[UqNY]GFZHblnB$$rceK=9/Peh2%K2H#/q84d5UepG4.3e^(d\r/\a$LM,I*cpP!@ID6iTB2=qJhA`)+Z?e<65h=/H]9U&8@&-5'Nn[^2X^]p;+V@QmhgaW+:NZ%Gm;%S(\Al?uh@3MmTNgY&0HD#VV`$e$t>[c*^pV@S'B*V4`n"TK1I*)>o-tb_'<>Gl23"ErS-k3R4Yl^;m77HtGn:ZFXYGe(+g/2E=JL&5n?m58q"#D4f:$a&21i+)X;Xfc)GD9^TA:X\b,m-J%s0:#f/?i6J0FXlGbU@ZY5)TV5NMV<%DC_b)=M#[;c^h/-Iu26Kq-tNWNh$@EdjbaH41O$f$O)"/"QI*Z_V_62e_hnb*59*QhWZcUUc<;n(8=0Sda4q4c"5&b8a)Pn4oD3?J8@o%a@*f9Yg)PUU-cG.tG?1G'bMCmSnD-/)4ZX%4fFDWrD%&qBLLL9^At`'?i7Q$^rl@sGDkI.cl84J33+cNj_#j]*0hdUVH$d3ap5YO48g`/>X@%J/om@_EBm.MoQsND0pQ,Y)XnF^HBFXkAF*djlcbn*oL$C4UouO_%.YI!3J*$Bj*.AnOLHJ^,<]&opL#MsYaSZ]K"]0a#pMf3tk6ScQ(^XOo\VH0n1^"D?]X1A*T@mpP',1p1IAfIqN&SXkl\:kk>CIclBFDWmG,X-hiK$'UE8"NHC>cjZTZ+T&WkF^CL5BW*FPi.7OR9TIs?a!%U%-Ip3XP_!td]49nhmXLk8*I3?Z[^;@!IPb:7&t+B:Ak$;jm4;\CtYJ!B$;sqb^Xg&F9\Nc]=;FD.p!5G98G/QiVJ#\Zg@/STp_P8BPk"LUN"*G5Nas`=3(%pU%pGO66YuMO6t1!E,nm,?QVZZnK[dj=cr67P)!Fl#^put+!h@"+cV2K6_Oc_0We.peWi09_7qOVqJu.5^iH"P6/l1+2_i.)8$DXGR@1f/SY!n"kM/A5G49!05k>(sf-c1Un:llCH&2:?bKrNCPWDDS4.u_-@RtbK0A1_0#pe:t,gb&tjVo%f?p6R8EB)43%;9N.rcGjF1ibBM*illS0ZBkA:"#nC<6!NHX"YcUg^L0=INW'8Vr2"@KL#m,9H.MY>#?#,(iBrb4dub/!mL,qK%SO8Z'd;mc#K&W![0PaeshcDUFr2dp,/(lZA*BF"`CG/uh,(s?Js6`+!("uIT-ZreFAMlYRLaQ'pH3#NKH)8t*a\5H2*32<8gWZ<81kpPD+;jH$(5'(]Gl59\!Q0UL1_F6Rl._i_I^>t0*HXeuP46Z^V[^uM7"=%pLRS5ggA9\#FD;kGV[*e>h'D1W]@]'Y\"NY==>\XqM,flPs,WNAhkks<9H,:raWj!BUXn*h*OlpAl%-R/dI69?L;.l>.?1(OR[5i08'2nmT-kVVPK^lAEm;fgPo-Juk4*"%Q2(8-G11IVaIN\R"9t3?Rq%I$l8/45C".S*\;<'0TcoZdt0[OH/+X:heDS@'m^W4f;nUK>4QCo0*o1>6sVAl>Pac.i&nae=4.Rg(,^dRaFVHgr.-T#$G_7Rt[_f57cZK+LBKQhHYkW9e=Y5DQk=a*]f+CH>-8BD89FXm`Y"5>J1J2Ds&hXK(jR=!uD1B,lkD3:\:hV[]k4+7&dS&.a[&%)`Ke'HgT[@>]gT@uUeYEb@CV)&Gj$V6dZL?+`6p]9pK#*7nNm-Wb#RU)rd1TKD52pP8t5;c"!!6a:JX^L1R*I3'hl[L7),CKP&j[]!FkeCHOH]b"7K`#0#tFN+B#RaW)=NA.ABj;%X.a(pl;=NILWgu`n=RBHi_dNZgpr!kELCE@ZnMlWDO2f]8P/=)tUqj`Qb(L0Ru;Q_IGdmnQAH#!!&U^OeZCsQn(csbq-OrEf:kG"B8`DaBmN)?DKs*r4b`KkF;2-"aZNXJL3L@cD7uemISu57s2gdHW[-dM"s2VJ83,&WBBl4bf.MKDQiJN87DX;:srk!LBoU\puN.cZ9;\b$HCK_a#ml,o=TCB'0iAUngYItW7=3SRR"T`&K#Y>g7RtHRI_t54r,(\1([j])&^&6Z(X9-R=QP-;g9AXVXn(CI>[fn/V'WU?lpZ!2;6V<`\ouE1((SP_Z/cjf?U:P^a('.L[FoW4AZNI>ElCToGIahM<6WpV=okJ73A(oVX?;%OkU-9(hns9+P35/7t91mCs:N_N7[(l=2bd(/GM%DO6cXukJU@2pm8)7)]+l1%A^jq+f1ar#PlUm+>G@bJk^CtLh7g+CPf"T"q<"#M(Y]a0G/S057sZ_l!)aEG?/[M3"!6Hk2Vm=<(%9c6t\Cum%'0mAk=/ZRt%%SdJG@3BbA5`\e5K99`'d\1&`>IB'&g%KG4NrFG^.g7d7KOM*A'HROKh"LM\W!k#*ED%\c3Z`"-kY3-t0+^c7"?p253ZT7Xn/bY[*Y('e]gk$Yh@AkDUV^4GKF1%41H!G?NE&.f[S?KZ)R^RMn(V)7sZ1qD*agm%3urf_MgPi5N,QIKUD8'I>=';[D1h38tBJ!]L#k666tkMi@DrfI`cA.R,u%4N%g0ChAB7[B-,#Us=1,md\*!Wipi,c2=`J$d!b#sU<](d693;#j0Y#Nlk1]s!iN<$.'$5Ko\R^R+cZ+G3YS67[It>1U(oeqBEH09cNgL3"1/7`-5L6'F1L?WKjg`Kha)^d&C\!P>T,b(.;^*_!u/cso>9]=nj$R;3ftG)PO7e"+M/=?*r!/eN&72jaFA9F:fnLAcdC%>Q!cO^0+[&lhcmk=T=gLce(N1Lsqb$O@2,<*%9NJ[@a/`V_R`npH):Cj5b("4e;A-W&qYD+Y`P;pH$Od.7R@&3G[D`P\God1-/`FAFl0_/1tF*jaWn6VD)=4aq8%GLY7a&r_PL0U\Y1co.h77X4h1WiV]$:MJq?'Q.f-(Z]iMHYuER0d)R:"Gm7I&<$]q.t^2$*ns%d(2g3IL.GVr9a<`p/Fr"DItTIh`74":PK2E"f//Ed1^PC[c:jZ6G)$I17i9<2Pm-VhNG'd-+3SF@#(P5Wck+G+OD)P^"`Q]`Doo>#*[SfE2,NHIMLo,5(ulZ9IU%&-h,YTbT*0/j(A\q&e_JpiuZ!_^_A:5?lJ%)L:S,a2$/X%%Jpd^"iq\D235%!-&8juM:ID-B)Wb_Zqc1p"9W!7cmZ#Il3#`Iaq"C]OA0-U%N^Wk4QgoSmS;^NnklD2)c'kkqdJ":^t*QRdL7Lq.#/qhU!u"]#$"7thMk0fKOP*N2&7i4ZfHNe'lDJWW?fUK%k6Qca"``V1hkE48G38NUVK##+m2GHnE*_)6s,'V7>`S$BP.#6h^g?#<#u(sR'\/.Sp7G_YI@fsll6MJiI59UcS7YFS#%tuHI\d(luqb>Jq6FNE%+T(K*ZlGk7:.Ea?sB0$fQZC/ksM%I1ff$\'m\cTcMr]]088u9addc,R*a"u,i.[kTLgZajRjW;&[7YVk2K,$;`h_6^HEkf]p7&5g+[%Ue?GnmAULJ=4KWlmt>duc7,H)*FT70_\QlN"V<60k4H%TFW#;@>Q2%dYEHM;:pIfU3"D:RjKUqNN#AR",gBcVSQmqB&ST@Lt2R[B/iZ\t<1%E`V-?as4bh9t!"u`sDiA(G\u*9U+\7CRq>>bEXW)=!Lb:CGC(NV9e,g6MNBjE7U?mM[efFgi%F:*M=d%ju&72U$n0k%%&E(ACM'^+f*K?@lQS%C53#maIqJOD93IKXS7#kK+e6HkhcHdSr"c]rS$N%[F)HmZ79.Rp/L$OV_sGA4Cgtj_#'=\E4EM[>3#cR`80IVPK4*)*1;"uQcc:&Mg#j^E1aL,8HNSfFE"g$3#Z!aq=Qe`1%SD$W7KX7aPD0pEbsms.^eL1%*e+jk_')76<5trFJWh8B+:Fj+FCaZ?NaQ7((2=;h;6F>&"W<'5*2t2:Q6[E*&-j:D]_LVCR]A(:iZ4YUHa)q+#(STGCkfMD3g%)>GKT9o0BaFJ[]hhO<;TFKY?UUqM@eI0+D4A2CH3_s(sjS09bToe;u79iLjSY0[B2aA`7Wk"HKj6S+ZqI5rD^rp/k&fnE[5K5ZPdV*)kA3SDn`-[c]6#.)ipe=_A\)fQs!rbSQ']RCGNV6TCbHa$7%H<@Mb[3I]H/5>I?*c"g7/bIMJ02,M?KX*Q@@tIOirTF@Kg/H5cf,J7cqHWYCZN\,Uc?8*"sT3p>?$5+*>BJV#[3@RiOBi@)_N_d$H-&p):>3Z#k3_e8f&(=@k:Lg"8mFT'g^J8\dm6gN3*6"8LJeN!D,NZ'i9c\1(^`uIetN!J;fouJ9rj`.marjF<:4(i&1p>VC!^K5'VG!bSP]dM4h[[EbI,uGRmd=TYAJh6FWKh0X6H;3r?^?i5P"IIO:4Dm2GJsa%8pcFJQ'j$r)ES.N&a:$rh2"4K9O[(=@SX[*B+!;FrO,,SQ"f;I5m!ee?39Orr3sCsVX#)Z9Tmb_K[tTda7Z,Y=c"!.'kmN%`\,M"iHl>_17K+Zci<__5^VV0*8#Yc#/4QQ$laf^FHPng:%f@22Z,Ya!WV8:+)6GkmkGQq3D'<)WA3U418kN1L9AXqgH'Di&G5=Agp9p!ZJCPDG#>PlM_!0h#W76)Nn#B6Yt#!7G7_(#m*8#f552e)Zgs.c>J4&KpfSckm60e0CdCId@s*5g!VBK!f@@jle$C.")`pi#,/8@YN.l`%GT&;Ac$"7cZ0EP;F>ehNng@P=T9Mo;&0J&eqQE:\oqG!-SuXKOdHPOQ&VJ`''0&D)W-ak;/q4asQEGc2mF%BWt26a5%F!BnDUp+0k_#^IbK5p4*2C!=;d7p?gq=e?Kh?Kt3a#6jaLA6qdfN6P+?_(^[#*qET8r+p3b`ajkQidt$.hP'A!MKj#.7>RPTgYO\-;]5UPUN5W5bM/267*s,7Y%Ff#bY^a&L]iB!',iH"s>#;ZfXM:-U3GOj8qB(RP^Z<.`laKmdcC]m#VRnd?5GF!uQdP51B[jPRRuV^@Hmg]jo#4Ybb7]Ut5dHKrj"P6k\u#.d.nuE%*h7mU51t!Y2`^R!;CKY>BCmm0CDb(X'78VD#EF5c-Dl7'qDf9IW:_$d<1Y4];X\nlPaNQ&&.LKE#"KiE#2"Hj+*5E,%$2bp)1O9fN]I592VDch$6nH_m"-,4J.YLV%iKFLM7H+r;A=l4.KcoUTOT>L(q*bl%jm@ph_t9SKK*R?#53n(p1OoT&L^mY$W;Ioi#%G+[Ae%-40g64%2*s\a$;\@4JT-1WQl#RLs)pW!k$qd.3hRUT>9l_@X^EI.@"lF)*qRSZO6Mk5XH5,XjeM]T0QK]XIbg+HP%6CE#U:"&22oJFBikae*/*Q^jqH^++XIg^M?)RT,#H]C5iMe+b3OWPP,@fMDhj2JZV$IV1^Hn_aXa&/;5$O4L'U*lOqe7QM(+m.8f7Vn+:2!b.$QuM#sf")i-H)#O:_PY.ah/C.[7&8#k?PS5^]B\9gLIRJ*'khnc+B%#RH=F%O!P#St-c5Z%T=-1[ZO\8^99Bei!ftJH*/&q:-:7%Jud\^*^(5m>LLSWD:5C[A+Lr9"6"[H+e3@QW?Af"P9I>+HaS]=gbmUkAP488(&Z^Z2KYcW&$ZL\1M,+`h,c!^s8/;VP%K-JBV0aO?XrA#opTTK3X!C27TWBa;.!rj>aae]aDoa29X7"^N@>]s+)\eGJa'q$jTs*eEVA20MlA[E:6&\J2_LU(^K82*Vb&,?8&^8$=NGtOr#T6-f@4A^CM]n]("k3=>=FLuKTKiF\N?a!S(9GF'!k)icBB^Gj$erXi%NrmZ>3!B-(L[k/X9o^-;iYKV9%`W..:^4)H$V8+>I>$dcO\;?s'hl8fM(;j6OBA%FQ=Y]jEfOEha/69[8`1f6BQN=f0QBTA^^oX,^hrn?AHTPP[hr;W[ktI0*[&5?V1Jb"YC5)>rqV.42O3HiT`B;+0Dt**CCX"QtB[,#LdE5[eRF;$e8ia5f+6h)!#-OEYnF;f!CBIH'MsBHdOF@+hiebh:j+#IH.k-aans7Ih&,W7a[i6b.PRBkpB[Bf)bV.B[Td;>-oa'8-/**>>tm"EE_AqE]iYQ4,a?Aae3sAl.hJD)c@7eVrF=I1mK2;bI&8q[\T3GO_K8!s$%EclS=jnY>/4V<>Y-&Op_V5*#>e^o]L(/S>uN>Gj);\ZccA9N5?'k#L=R@tNALil&ZlPA'2^J:VKAbd_>`?fs$<1"d!XW%s"o7n$#";AiZMWhj6JdMY,qcGdT8MAau$?8boFio.5[mq[au;W)5#mbEB7HGPbC>L;XfN9OUt&)f\T&R%ZkLC#J*D8L=cLSEQ_Mc%u^V%RKn-]0_H9TofiR%NLT,G!&]_3Qiua)'jSI&q3q%C'#Eir=`0Ahn>G2//W.j#:o'\',DIl?7$RCkZ[=ei7(Hb>f<\4=enW=dHG/^0b9!0(GYfVPm)n_-p_1SNg1aP]-;j"pQ88\`Ol+p461G_V[NWSZ[iDE1(<.c+hX+?8dej[l)gt6\SgMQH4^#B*GH!?,V4-d_XJ7'tL*'ZJ?eJYpqg3I2d`YQR.2PPM_Nm7>"M+r*C2.mCG[n;d75"]RtaiZc:iQb@.V%ufTGUCCatM*4cp@.254n"HLg>5nCugM]Rl4dI7#0GW)@$c4CG[LV&M-3q6\R6)BK6:4:;OT/80+Mgb"u(o0Pjq4ZRu&/O4[mmL@5SEc/8U,V.'lO$],U6&J#B>otdOTgn8:5=q7)%qn^2JBEJ2&+_.q7RgjD5.cXC"1%!s5J7q@;6'i^IPR\Bejl?=s-&'AlC/KSA5uVpg/hT7XQS4K18L8nn7LNAD",p.p;^-B4E!jFu/LbRJR:BZ'OE%EA"mf(J2+o)\Ke&o@U]nhPh<>>SESs+Nf5cu2Q/@MbW',%4.MhSCkA8!D/q0S=8]2AumHHAc(H3]1$@j+6/S1)L)Q^nTN@pDcBUD=FK,,g<'TRqV&j_=`b%r:XbC-@P"[%J-/2K^]tU;"/8p;dKEF'PFdCm_>ONR:_%UYm=k%_g8C-&?td>a70;Qo@s$bFQBHUW:jhR-W+RX1&H2U60soTE1!\D0UtWQ#4U;a_=ecF[?HjB18r(P'$;r#QObk9UhbQ&%R@GU@CW@Im\6P&j"][mS29b#610/3iq[I6'Z/ZePCHk,D,ak-XaB=f:L_F_5/2??+V1U,NN$4.:"U(dF?o^_8(ME1fZHWR^-aCb!@n#/@'F`OXQR;eMZlm:aP78'?+BG-QV^*Ud(3AP^,T?Q@\d!s7B;6*0';Y*CVI^e!!,YFUAnJsnW*(g9s0;!N;sf^74tA0kp8mgpQpA2&CO%q.*7p@mN!P-?(!a>@Q`[,*SW9e.7?9RP^"5Kcg-"3:^`$m>4uV>:kGE-qD;g#"q)#uW:oT+&2):p8jhO*jS+0r1lL)plFXAXM8g]:Jf_M7T)\KYdC\MJ-nOj,R"OY3jU5%pRu)^"i`DJd@ubr+X9eIq"AR^*pg+t$&i?X]#DT=bh<)UFI^-nicZJt-:$Nt-5m/QL?,F-9i=B="US.*W5(Et5j!nhf$[+l0?EOt94FU](T]S*,/%li!,+;c#?3TmH+]K1I6D]q60(&ifV(+FG'<@`NerXL&e)EULc:u:29a$E&Wn>/+Z'CrV$X$Y*"gUW-Xo>IcW+?44.;9H?qfQD*BWa1X&$h-9mci0qTS&5"I_-["Es/$knRc64*[.M4(a$TrLi(1dU:N+!E5bIYlMZE4S#AHq3;I*phc1Osub*@-!&R(Vo&O?/@:;'FlN&Td,4".Y?h3V(L/K$8NQZaV8bE;-9Ic1Y2]'NKPI@meF!'H8>l7P<@OG;2rMN^lX;,m#HeT#7c'DZ;"DI\ki)B!NDp+Mujk>.])O2KgQd0`9N*Z6b=I!tU>eb-&#[)'C"LX$o^G3Qo"4u%jTss\,@R-.k*-T45l7iu=7q3>^.s*`a&lEp8%T,.@ET\g%l+=aL=OE%`?BR&nX>(FA1i'(%V$PhsM:%dAh(0!=hi5o&VjD$_G'*NWEasbuZJF0PKAOX&A^5+&7Kp*P2G+SN9O0MZ.j9-.cbgoaqu--#gA'gmc>c;ZdM6[lrB\Ce0'C.'35=AMgt4PNaW`e`!YQ1r$o-3YN8^'?#l0!.C\Vjnp>NZ(3l_h.E5*$$Q>kgA#(r`!Qsp)&+;(?9M_;l?F>nq&1OVopglP]@(rA:)ofbor,IW5oO0838mp^\16Ptj,\C8c,K>1!]^5\KC=B?O3WZ1acJVnpD5am4J^(b!9T[\dl*&\N]rbY`?b,k/&Igq+]-O_j348]Z*PL3/m<:J#"XD'%BV5@MkE"mYQ8=4(eS]]"&pOgDfBFB.F^;=B7%]a[9X&o@jk;^agR-\3ue",GtU;#]-YgC_M(+lH?'OX,?bJX6pQA8XHGd,l6VVc*>pr$Eu9bY4?LM'P'81)LJM$/CW2:")t75]5pL%1j03G*W]EL+l7t1*&^XXB&k^M)8TBLBGMG"4H]'_#jlDHk2ld5W9P6B'g/`*LEtT4au:ag.lC#G]4!$;?mW5E1'+Tu:Z,Ae'nTBfnJ$-24`V0N1Apcfsa%41sUI7KdBD@kR]jnU62E=>MJbE!3$\MfnsqpVA5\R*#];M"A/q2MSP*DZEjiPHVjmN6at?bhlFFWd,LU`;`hVgh1&A^aU[/kXQV,=ioJ0M"meZu]t7@oX(7&<[8@$r][_LCs`50G@:%9!Jdt7&1Gl<)<]l1ITZu'grd]7\TsAC1;^M6&t;mEM/#'Rb"Gd$_a.KZ(c9&\jm;cY'K(e9;au_@TV$mh6fAk)`;6p_Yl48>ThH0\-]0N47ZqJ0]CpQ^u!=HeF&OuM4=+e74"HLT^s7W,a<@%6Vp16MK0%fs22n=fg?6E]A9mJ3j)Cf?[T3-r:kZG;N]R;NbLrhbrHM?AJIA;fL0\538Ui.(umlLQ+aN0WKM>Xc?F7@-tK6`o-R$$'QQ=.Q5HU^A#in;)N[7b']@CZefERH?D\F)X"/]\7u2ei\nUj@-mBps&hg7T8p@g")hER$";jG_$0);a*R.$m_8db3K;@fXSg4-`QP:aoJ&kidr17NoBZ;'BhT?O$r+L]iWHKrHuogZc?&0e2qXO:3(;=g`bA+AFimp+bZG.b*qN-?b[nJN:dQ(QaLhJ__fKITqnk-gbY2C&JlXj)F8>3k7g?.K+78N3%]Ao\4YARNahb`%>]a&)3V&FJEAO%1(Qq(+gkupMIZ+t5sd*LYR26;^ST?b&<[;'!',"tb@&hg801qP'4)9(,X_aFR5\Nu2'q)_5D>WE"P8/>,)cO2ae8X[W8<0u2oo_RT/831nRqY.;Mh2h??^#PIW_j[ac7)aKRlM4+=RJ.),?eT0gntbZ,MTScJ8gZ8VSEsC\\Z?oc6"%?VBc:K7WVmGA?oG2"%I>3>1l`NkB';q5#rTsVYDF"bMP_j9^8JHlH"@,?g?LZ=daj,D`uB^0OLmmbAb>.'Hj4W8X5H=)QlILMj(I"O-4_DA3-nXPoCEI+q%4'>g.5bda'L'ekuf"L;d]=Q5\c4UGW0$+cjc/C^("3oqRKZIKs,(c9?9-/cu=]N88[GaauQ7ZW:9:B;HJc2Ecl*b0h]!5TuE+&8cTBXqr%j3l&o.;(AS4a^OpibaBG<3B/[L0gMOJ\JcbD$.MSc$$PE^$3A6FslfE\@!XtFe0kYe.obB:LNVBN)raCU,R9p"-HSPp5SM[d+s7Kp+L;&KkOG>_17WQ,aN3Gr\VSAhblfOUp1Om-*A=dK]-X[JEkK5U@'T^8SrDq#hD]GO45e(cF<_sg0gdD@MSGRNCh2'(+`[j#nWi6[JWW-mrN28Mff+Y5O(M)6u2fPbR_.`c-%&JJ(gW$9W2qA4]gZ?&2-B#=cWZfM=?Eh[rfJfsU3)]?cUpgH9hPJBaDGGB_KeOD0oF?,FYCIp2bQ;IZ/o?+L5jS&u_DM[S7_d%$NEs`Fptr:*9&t8q"]h^7+A$adKJs?+ZjPS,k\n*-ZSNuXJF/J(F8YuAobt_K5?/3[@A*nYbD)2%8,b^*pXTSEWP+Sh/'bK)&@o[`T*^c=F7rIj^bZU2O*N#&GUg!##4&S]h4j7q[eXGS(eg./[0shjO\sWbt#3!0l,=O$HQ`rNVQiLLe$36bM<=(:OV,,90KDT"s,%J/R9G[%HUP"M'F/T]f1%-mR2&;2Uf*TlsOeuiKjM$bLX.J,fA%2X"4mVKe:qki7]c*A`0+JM@/2$u=EnVapP3M(+'N^TG-\RIc0hK.9[X#ZQq-uLRJhM[M`ZRSj%Y136JWlUi3WK("`<#'bOFdS,ZHuXj"l,4=0d^dOM[eQ.U7]<:+,(rq$-r;s1k"<1R@#>Ys=/kYJ@c]GkU1$VL+B35aR[J0Q*!s#^A5"j)pDK]"cp7i)5l6\"4e&Hai7bCO"8.(j>Sd'mbiiq%kF*om8Au3tE?ru,*"\8XM+1I=DQ6Q1aM&7dL0JgUM7k]EWL(QIY8aS1K$ol+L6NuPAV0t[RM608NBK9XL_MX3",^kUl=a;[18dk-%gb]Fj]TeGB'=3,fI.5@W)+J8"UTg;\?l[O*`QuEdiY9h5ZQ$&a?qp7;jLH?f.`)-\+d?Kk>W2&XiDm""1)E-Jbd1J7;8Or6S&PJ)hUGmF+ZLc%>&BKL=.7M=0_?=ls$%ZN47)]mG;:W[00Xr]T7];bKDkn>p(Rg:C3">Q,QWX'CGmT=Y+l(`k)2q\J5`[q(Ri6.o`WT3hb!TVcNqku\MgF]l$\a1])/,C6iZ91&Ta$OJTh9FJE0Sn=VE'QiEYo#I6)L'kK**4%dJ(n6t<,LguMt=S.3E.oPc+/U,p61IihNo<=H3R.6C8u)%EECXuPW-"I/24"I72MD=U&DYEal!`]k\L0Z(.%1G2'4@qopme$4%J9n7=hc"%IC]I5G,Mq`7"n)4Z:A>S?RZhZ!Z_X?89b(7go72p<9u:m6SkpRerUL3Ps&L,:QkJP3sm4C_=1^&W5o.k*CjZ9+*$[6oH&I=*[m,&:g+LX5TaAqed&of1hi)K<<,mL9RLXHS/m;6m"XH#E)RROE<;S/c(O!^l.^_/oRBts!si'S*#f/-bnA8[*.>/#0,[),c1P)#qX]PEhakM0o8Z8F#g@l/AHE8]0kWnn2iL-mS4Md>ggOJQW+bsFj*C@mPLfU9@\#p"2]ki'imDJK!^#i4glbL.riNnM\%Bq0+jZO!rB6PsRR4gKZWnC*H,LTdoM"c`!@g"A:TEc^g>'pbagGMj&icUcoWKi;kX:6]=,nm2MGF44g0M7TsO*O(csC,UguUC#^M"h-XEo;L`hJb&+7GFoJ1`"_-T?\"nRB!Rjir@!lh+.fBks$5_JaHAk%p#.nb[lD1Io"T@eFZ+l24&qXY9op\CXBU3EQXrb@lrOjpg'/Z[a8JSkc9G_e[HMEX3,O/MKTO;Kc#5Z7<;dua1F4@e)eaHC)2+JB)1A!,j0#MM6lrjDHIIGoi1E_XqG-76MtYXYJJAh-LU'Qs/9%YMIIS^O%_:pC=q,='@*%-:%bCt6(l9XIW"/nu'Ai2.]X&:ie!h&#FYL#K_:*FGReLS3?XR5Jd`Tm@utM:">big3m#YeMi:MLkc)t3L9Z`C[;(^&:Bc",b5ZO<%ZqTs7hSLbj!G,/!OAAd)JV&@0^m'u&u\b`.5,F29V-ZiSQW\7rV#&+"#A!?]*HKp9i;3']l^UtTgHYndR*uKG-KAN*EORtVl'C0/%06gt>)JMd-rE!Bn5t#0^*_qdY`aNS=6"1,<8l[CLQpATs0\s8!'(&O2nqdS]]r)"+p*?\9J62(F#6KQ+!T-]TfMO:06.Zp$gQK6f[37q:aF>,"E=s9P)p]0U82/=:o-NFTjPi-N9j,mI7'5mWdI-g+6Xk6TEp&T!#eoogL^Tu-=QmXBa06H4I&mO*@h#-,&0i>IYTDr-UYmnZWKNs3T);#7fPr(p)PrYk4(ksH(Cp9odUhB$8Wnkt,+kJM`jK<9KLqlSt?e)uC)0(6f'm-.jbd=p7+pC_f%8=Y)3\`W65=!Ld,,E^gP&V9&kgQIC`aXKtPm)P/ijhM/bEg<-1Q0&dX.GU3X:>fc"q2G+=cF]8$4)4j/se/I2OO)V)]F;"OJ:,BDcfA@6Kpq7,r*_,$F:MiI9ErR;'sYgZ(-q`Y!u6?]GCUj]p<]%3s)6i_CiaD<_9J*;D?J^\OZ2oE])HSTatdMdF'DM+S%PhCY`C^PKEpU1kC;j`97\aiD6+?>W?a3fa3H#c#:^Ie'/onYGXCCU-[1[BH8p<_`l.Sd5VA>U$d+RC/[UL9?k869$qk&r6r2#/eAkYMAMN__+K4BjrJ857+U<+DIOBd9*#E='sA]+O9N;oP;,5ce5%epq*&0HUA,KVG-3?/f[QjK`rb+/Zf>&G"[5b10BrL=]V=g1HO:@aa>WM4.,QY/%&VP:8V:il'6'VTmnDn]=;I;8kRuT^\'WH]9s6ZSI2&#T8M/u_qLJ'dYMn=;Mg/e8An>[7%lSLkglWB0lT:aXhHo>GG?(fEc4J5JH>8V6"I/?02_8Rc.XNXSH-R!)S3G!sf:7.f0Zat-VqW4'3TGcb,mOs4d<:Jao3O\?P;8M$gYe-pGn61-"HYJJpT(_PLm."%/emVE(M#D3>G*1,#[rgSP;-X\_ZOG:`;C&iuT.USDPP[,b[(#9]P5FMW>OMHdp.M;u".B"Or:uj2<#1`dM#s:ca!"N[S#i-^:Jlq.g6'FR&]J'GX!bccl:?@8:4P>LCR4%cm'YCmh1%VBfY$5D?kVtm4Yps3-"i_=XZ_WIe6;W;IVF7s1n7\16HVpf'EIa3ERkk(1D2Vfbh!DLWc='J_'Ko+[C=jOf\bU&toT*Rui/<+7T1,#^8A%a`/U5$da<(*l32ghH$(8D:dCZ+5stNIZV((`K/m]lYSH#E=T]I38>OnP3@+Y"+hffPMnAaSku$""H[$G^cnAAcZEn2=sHtFLo?i-0+bqqT^N0>GClef+T>a$kVuYPoP=-ndBSo4rLb70;[FZ@:-sFZ!DOgQeHit15lgLU6FDO4Ulh*$+WA1VXFr/eoJd)^K;!g&1U'Zq6F;FJjIaL9=G@Ka;@Gc,I]tL&2!/e]2"56&C.:VS.oqF&/?1CNF#21bKSKX=JVMd`QNdJESYZ0+*o^p^a"p]o2'm>8oh,CqF4Pi)N^3&e0nT<"nSeocge+?86DGAO9Oe?sS-o?IR7)^.MC:>MTX'#gCG^_\ZqS;dHQ(nm',c6dTGZ&`+3q_i1GU-FqSV%dK_ZH,I!N'oZj'.EWeld)kGaV/#>`WS@]0>!+gF_\+9h@H06nWZmF`XBLe#TIMe(W!O0&J:FT]J]rSuO@r%)q(Esb=/6P"EW:/Eo!0^Zch:N!m(hr,*/pdR>gu8VGT@$kf05B^;S3TjQp'4JjcG)$6j16)@hr$(+F\QU"Hk5(#R5ut)GmqS_\,g5JaNP45`(D\cijM:.Gr?Hf;ENbn,QCP$rKiSO3"E%k`_1@(4gE,5g[pjaHGCOLkC@L:fOFqp(@AS+TsP+bUEZ\.5VUR.9+\KN"A[EZOKPqOJEL@!?dP`d[=0^*C@OQ$:KqH(IU)(n;nAs6ldR%%U_`qKhTjHW#j%K>_&B0Ti!!87?Ak%IP/.]E-!YP?-D>i0t[=q?u6"rL<8nJZnEg"Vf/>A(Dl'Q0:@QU[R1CZ"5;Xf(=%p+=GCG#d@.#Qp5g*nllp=$$,D9.CHM5eBuXFH6A\\J5"UB]%>4B@EC1UV;s?DK6e786)W-Zqk)J!7(h[e\:sHfNs+p5Jn@ZV]3+UmSuJZ^Gkn]\F\d8n)rVH/an6!<,/F_<<&EM8Eq"N$*eIO!D4^EBUW*0J[1,SkX"]M`gF;*o<>EAsGaSmXJ3G#DU5EVaQcNU:%g"mS_$&gQ:ZaUFT%c0Bmnn\PMM($r^)Bi&(lFoH93hF?VhuSsgVorLZSJIFH&37tgn<*G\l#JV.+LiQ![Nq.HnQJjt>KeHjZ&)kj-3&"(WCQ>en;8.0J$fk`i+d(;m`m[?/9CD&^D0n)lEnn4jm`hLe+^j70npEG$qR"c*4bQ\FT+"n-2bl+<1&kCG#OO9OH8Q7''9,a4Rn"bV:\8r24dY5B.E-=oshP+d/)KgC!se3gIkj,F,-(NW3UtYgOH*GEefM"AD*)C^,TXY9fqdQ,4E>F!u'>[iuM/0/0/o"%#/`$Y:UpObS94!KMG6oR5sc+Y*&ot-om+`.)Ru2+"^JHCll_u0oGXcAZ6]%+!.riR#&P%VG,'BA5$*eVV#?]n;#+G)F8W,"7#!sZ"4%Z6IVRS$,2p:C!)lqnf9O.Wr)I\5$\mIXmmgh;lU5"gE"2gXm>2[O(#e1Zpm_MfPM,>^*4faPh'H3oIN3CuT)S2_dh)]+TnNJhMbA:&8Q/E1%](atdC,KmAE5R9k*49THAqnE*6SClE'=H-Q?Cl>+igG\4H$Rld35':UJAGWl>@=T7fK$c-4a[IQ]aW,CO@9/mn/r%#n%)t$,$hsHMUW)oKn0m_[i[u#4cKZ@&J.AK3i7S);G"6M//t%Y6;q>[b"<^D*eO7195#0BQBt4CX:$RKeq7*8i@aWBW(Kgm-Sd^6)5F2$ce?55`&V9/VEU\7VibcJ"K/SJ%7oOa^'C%j+jL`-K%@.P,7^1hbWI?u+t7,sH$OH%LiXWqp'20H+<8ZiV1feS)AcKs4o%[o!^.P9q=#LRg&G8e%[pP%4rskD3d6dX86=[+l7p5G#GChR),e87f4VWl'PDSX]cA_W.pNF('F3oVTFMi#c+8*#!b*8YZNs2-@een.c>t>d_fAW'q/^>Tokd0!.ZOG/q\)+L3AQ,r:_6QjZF*l.]Kur5A-!=\X]9[*FS\C8H!-3h`rMX"Dqrt:b6prfi#Qij&/nWG&BDfLp+a/oL@'7s3XuORCg[CW/>-X&i>jUkdWO3W+\)7ia=SckiULIn9Vd8:C).8;"T.)^^PO\,VR6n(NU$3Gc-:^iUE#:*kMJbhAK7H,'0WF6%p]E5sI6DJ14AY?7WL)`!8Y%n!0MPLTQ!G!>pW=6j6"%^V;dCX6=c]X?@d0_XpHobqtM4_%P!-RTr+&'5,+uXP*I@d6Biai2!FC-6U9Q?SUQ`.SmNNMG3jV>@G7Yq^^^N5NSPo5&l^h[i=?qRBOn^caV#E4d\+iW-b%9,HOeM1*cFr4L]BW+JTo:I28N\d$e74!?PB)C4X.ZdKL"O5b7`$AH&'SBucJ8"3+K-9V)kWm$c1soj5d1#p;M@Ep7$*kQT)F]])/3PNne!7P^tqN(r:Rs5B>d]negQ5+0hL:_.!,0T-XBgDWLmhq$"a`JMqb!&j0bS1/@ZmKaO,eo]iaaqlNX?'-p@dl0lW1GkAGpob*]tGQGa!EcgeOKr"@LN"_P3`$/)/Im)A\ps+pagRlFT46F2+sqXD+72n:@gZs1]cq0NhO,hrN(I,'N.FPam\.BT8E]&=A1l#!>KmV+OJ_QnEk_+A$QB(Le_B?=GKR)jj/o8_@#8;,Ruh(Pq#@@G`n8U"f>:.5Xh]A;[TO^2oWuAUfn62#8=J/^$nT8)Q9=QAKniLB=WK?h\KPWTRF[!bkU+T<1'Bp3o7=!P`tdR"XhM%*b8&clH>nG/%Jql&%e5lW??]o^U.XYO)A)DLHGeD@Ui0?V(Qt<`Z9eW>F$eTJ8gV.!hOG496:!Aq5uii4)c[.Za=%E!UD`"60JX;HkZC`:%1>bGL?-/pD]Kt`JV>)be!CNL;plga6_^"u)c/gf#Ir_?6O0q:Oc>!KXu-dToc?e*g]uPT#?;*KkX:cXE`1]/"JlLC47(:Yjfbat?>j*JluT`21Gfe4`FoA4IArq7c@u^WGle4p0@)rRm7kdf&'B)Ac0MbRjaD!T:]5G;XR;Lk4&OMOmK5#G(a2bU!c]o*9e5`b@]6+FmW\M&(YE+8,/#TZ*N@f8ZY2DAZI'QiC?fo:q9$7UPA/09#Jqq3C&S\Mji/\W]%>3Qe0>1UGYY0:%b^+!%/XesOLpHDs`h3K.C=DXDZpi`lg>PfduI6;W@O;Ab/M\trq+QpcXpaNDt>i0b?OtR;NK^.Ejn*!<7@r/Ukfr2%dF?X0-\(m[.b9KEkX8_FdY;B-=+@)<9\\`R]\#D'ojLjO0$PM&DWC1(QuqJ5_manHfm$J`A;h#%8>qs?G;WCp$"t-hNBBNaJEb&\<5OTF;3.omU?tE;be]%Q"CQ6F$*QZe<^Z!&Zu-;%Q$^MPVbuZ#?3Q5"KcJK2*i'MTV,Wd]:0L*9VP')"10I0E;bsjE^ssk:k`inB7O7OF/:;F>_=du5[\0N#AtgSk#=^1ibnWH\FkWbdJKRG_Gg-\G5L3H"IUU1=(i"dc/d@[HW7V#lBhcYg/KYIWr_ei-IT*;W.+YsA@`sQ6rk.P>Hil#A#qt8RXq7_"JF,rBP27UPI1p4mJu,Hnq5RZ#gjhI:BVSdBVS`HP)PbCR1M8#+b5"/c%SSX-a4`[--Pj271:--jl&<_7<_./_R!Ce"7VKWL*shIY@NP`&2bp?Ih&UF!Df'$3N$e(CamtGgY++K^n)g(]E`)T)A83fJuD:TAn6XHWaqM(8eQ`5No5]EBXTr_p\4r?$4ERoaH7.^f[K`W"6c/*#f$5UlYgsG+$rDb<(oTe@&24JK7\2]dh;-RGQo>uj;[#=k?pfE'ApX[a$U`d>N!LHBJFq\>AcnDZ,Dfj/1oDLnM2=+m+9js]P8T%BF]59r(ePW4TNmp'Stj_1peBp"Cf"girb,"Zj0CS`?c)Rcn`Mmd)L2r!!W=R)65R,XOR^9j\^f^#];!qF&[4n*n#AD;0.7eA5_GH^qh4jC8g'3XANooi2/5Ai/JErVpqWTu0>7)g8+6:2oR-uQaa+Omd8H3o9,1,7.("kSk$+@!mBVBf?pY?3+2=fqD3#f&rTO7GYd'ND&LouRG6o]0VCh3Jdd<"aI0:C"s?cn99ra-M%&=]ifEVZ-8QO]=Z&Pq#rPtZ)3Xd`cZ8mKSjOKPWRIq>AVV2@5(.P?:qq+71<=,oU'u]%p<^*IMC_.DPfTeiMmF0sNRBEtL=tHY/DqmFBqIMMb$<]]IfuWU"]]2mR.ua(]`Xq+a?1OXWP[O-cctJU4alVettoINc<"5UGOn5kJtkp&h,D4W[m(!@71B.6TuW#MhV):=,2>(Qf2UR&V6MOG0C+LsiB;'3*]01\0K@ikmWt=?D^Y%?95S0esc=I(8W@P^=oL+&U/-UtZ;_K92TE35[4[.hWPb!QTeq&L4fJRRQsa7='mR%F;W\A3(_e;hI1a;b[Fi/RfsslR"%"^3/OGDV6*R^+4GAJ!2?&:*2D5fgOc(ni95J"V'FP7aVPe%T"*H4OXBV`%6qMtnTXR1R2[Dqg%LJB#Ot+[%.?%8mm)sC1/@_+@eW]['$__;`@dbq$k)g)FUPhH8Ig.ki:gp1COZ9R7#gC(W.ci%!@k0Mk/a2!aNg]Gn@6VUg5VuRS6qInT1)*'I>d:e)70-g[S2\8LOQ$X:c:KY2'b+Vp@m,oAbG[g5(Ja=N;E"fhUObb>j;k^]4G%4M8Tu%6J>r+khUVs+&)"si!uc/--,BYs/+]hC,7Yj;n4hR1KEE6V9Sd(R)%h)&JTIs3<,,&Q!anEE+J_+>F1m+:+,U&I;C!t&/qFoFDMssjm8F%m]1):n;!n`&)\cGik)s`^2\P$P=OKP8,nc'JdbJOV9j5?uduS!QA;gEm#O+l5&`U5`(6G^X4V^1;.9nE2KkLsd;%lS5Vr&B)2A.U,Ll?@L^=(TmK?Bb*tR!G^K_CE$]fEF!W%PF.%n\'lkmpq(IF_=?b$L4Rb0KLg5uWLlN.!6cpW^,@H=he?7)U"4?&#n:[Ulc2<[$j1q3NkI7+KZ(UHM$*L-C-DWC>L1#n)JshFR_[#](Vn8k>^9.J&5L`JAmU)*u+42UcMl$br)i&G8)UMM8m*WcENi9RAH%JV@Jm!X2JrfAr1D(<8Yra1n?m#_#KTMPiZRHZA,,fd#$?RAnL1o_m&4N6L1Hpn.fkWOS/F-#E1=I!R#/0b$o9lb)is,b6\KfShlJafd%Bpq:qbP^V29fH,/V[o+\HV4HOP=aCd\NeXWP3?%Ns9A)8\Zk#Wqm&1jq`G[P/16hor;CEHAAl0+4A)9-mGZYNCkM7!)ZR(V7;$=A>&(9UM+kAkG4/I=i[R4`]uc.,tNY9V`1,;6^3DrO:/r3nrs5M!MHoQ[g[*uaO953@(IJK0Ck]ee9*,_C32Rf;<+I=jEQ;g$7I,3:h'FO^&TkA"i`#+9j_bXB,FC!k229n`^NZqcp&$X#+r^(abNRSeLG-0#J#Vph2L"L"Y$H4e,CTRVKU@7lADoMJ7'W9W_.Q$ikl2YReDelTJ<:+9=]qI"M542Q)!t>r.uJqI.Yr`a6s'oo9GF_)$2TkO6:]@3o;`"g6Li1hD#t.iKk'>m)DQ.dB.8m-1G;3`^+:4N:Quobt*.5pBIn`.D8N6FmrO+Y=%>To>4+E^u3An&_T5jiUGeT>5'@T!Ja=,p&n!68]Q7#U"i.U7Fp)gYm2WX2p#GUGu8$qUQ'LS7^Sj3>V2m:E:\Ye3l`IZ4:dRTl5hUAsW%9VQ%S2'gh;&$Sr[+^"!j6*_.P>mp.<.Gkr;b'OEN,nTn)^+"04AYRjIG).?q(9g^"H--KLagL*l8K4YNH7^q`#T'L?[i"_)4q?cC5_n]^2$1PST=-*[:*mjkIp0A.k?n3T^,V]G2Sj.+4IrZXRS#?rkZC!jbj.>._8[s&+j3jl@Bep?6A&("mBQ,T.\QL1jo4orsoK@;9Wt!S'88)P3me@i2*oY&18uF`;Yj^90IJW^gId!G\,mq"OJTn!3a/pRu$U(RJMRVQQsSl1:Vrr1#u/O\Z7Wl1r7)?GB8UOMGf[j&K1X:a\^?`&g\rr`Za$W70JFn]T=ilO%uh\S=,#4#+=S73mG'dHb+V[kSgaG_dS_;,n+b=,fDh'Enn]5"@$^hQg_0piO=k^kfuol5UuFCGb(ncAn\%KY+K9JOm_:"dA0l8fZjgjJnXq57EeJgLgsL/+0Q9LoTXTk4O1U31UDQnC\$/rGB<<$p;fhC4K'V6N@)RUDk*G*c,V:5k:%Br!PsJ1S^u0PlLMG3+n8&kku^!f>&rE1<4O-9:AYe,H^dT\r=JWjJ@OOB?.@&,S1P6:))/b,O,f5V7OQLt'UigB:AB!@U%>UoK8qdiCsNN3H27Vq1!h[c3;Rr"a@6,=E7V0f*O>?a7mt,o$j)8S"/c,%2(6eqKPK(rTY%7W-/1P,<4eAcnu:=k$9g!2m-0;nF#a)P!gr&2GQbMksi_^cTVf%hT=o/3+=icMG.;=o=`8gWfoLSSE!a-C*V#WP`$%4=Y=9R'NMu#0eeKa.nu/2NB]O^$9l/V0]/a<6qN!CB>6Cm_2E/=M\NE@UA+fI=^\`o4E]R$o1LVAPtnTa7Yb@"MOE8kN9C@R:+t8H[7nGaCd=)E)c.D-=YkV/^DZaib=d\L1)lnV'rD7&`GR$l(djQjL5MjUlOsQ[Jg@mjI"Q3Au(8QOf-i=0,%<:@O1D9M0%4/5`iL]M5hk6%bDK6o:J&HuE'dk,b0g],;LKo7::1]ZBXQ"6f!Y>W`F&?BK:ub=BruaK;2h.OtWT&.D[g-[X-VS6j%o0/cQne7(*G7.;mHC]o&=P'Ua]11;Rnah)VOiiYY3C4^+#X_/6W$SE]]Jt_*LFC-QlC7cQ^lRE,Vn#W,YSg5kg>S-ke^4b.&(*HkORYn0Q"VQUdrOc-sP`n7n(D]`2"RaC]Qj,\qqO#*2ZG).,].)A5$8\Z_IhQcqG6*)'NG<-lX&Of/&4<4ggZ;a$Mq)Tf@USo)^WW=>1-(4i/hX_&ZqfsgbIX9$:Sa_6tlp'#a'aC?+)b&+#bM]&5&8i:lWHF^_hT#^q6R6J\YlZ5/%iOG6n?Q9I.s*UOAFgr1mt[7-c3%;A8Er+d>*Y)Ru$o7cuQ((_o=]u\Nlupf!2P7-<5YE\!-76RR3`i/jZrABmgG9EQ@a^Msgou6d+k_;15B?X'q`+RW1`%s&4e)sm#q8X,TWe"]W*:TXZ?'`3mggHnE@"AbBF>(8+5uj9IJu_sek6k!Cke501>U%LgFX2fT<*lAM,5IEn]s(.'/"d,NcHTb@tsjW7L;>_XhnO)LG6i+7(BKeMhHhC^-L>ES)i;#/VaRTIOJd8!j&-lbUr$.^8m*=?mRG8EU/EO;GprWd.-_(QA>6@T:kUPX1aI2SfMaKf>?fcYN#G6Y;II8<*bk8%dk*u861?8]Ft.S1H7,LR3@^PLk[JW9ld:_0cH\F8*3GYticRV=4Q$8_FUf$T/kCLfVBc_73`/>)<*[_g@F$0PL^\-\@DGl!+,S8_mK8[g7&IJJa\&5]a;H1cP[r"B@Sk_%$:,NhOlRf2;C%baVif%[<*MIjFS'W8M(8-?&aWI?es2+9BS`=U+;uXW+IXJf)-U>a\%`]eOf\uc:22>1ha)eH1lBCgb)a^2m+Uj%d!i^&nd3DVXf\5;;,HimXGco\Vp]?!(XXQp5?qqkUhKtmLqtQ/JInbXdcf%u;j0L>#9esIXAF*n+JDt:J=m^@U`?HQOFRQKA0ql-j.#%-hQ+l:%3*%*jA>UVaO,cN!\o_"!/?H:Olt$0g*0p&'tnL@R5^4,[b!dQjQ6BX;N@nb`InHrs-pN"IZ6*)`4riW>$Uu4^pEKOip<=b4sST\!%Gd)n-*"FNr/!abFGpMdrC/lSg<$FC0;NESjL.oT8,1S'i8M2jfUf.WMb&/BT?+:38XL92#NEcQ&,6]#:A?1e^KNTocp`Jh'jtGFiD9/qXe81^QlDVM-?sN`(T_f9K2oDA>+N4g?UZP'!;UC_Z8rjm+rR/ku5f)l]c[J=t66#IhadNSoB94uOY\AAk`P`sS7RPTtaQ*bJn"NDrL2;i`"0=Q@5]hA<6,IQ!A13J4\[("[t<)6sb'[K^0p#cXINaO%][XApmD+Y]-'kZ8HT8-c+1O9*Ei5d]&c1kK6DjM;NQOX#6+jO$)t$MXgVd'?%4,-X4[>JSPQ?b02I_,73u-ijh+>S"gV&c7R3mm\O7XR?r#Q;1YRgMO1/`cWo,?6H"3%/Md:!X0i]pZGWk3!105pk/^5$3>qeN'S%!e9ajib=7jEorq?C$DkV^P&pAggmu?EE&'8_&WeF%Aim*t_.[p-,bkoaLuGk))$1ulkqSig-j$q=k1lrP)EMrb%u1f$JICJ'jIAVhLj7pX_#Z"&_j9SWVE)O6H=5]Q]%uCKDKO_&%a8RUGnlkS&`F"0liG0;LSl9iph\u%!:YPYREGnq&Gd3"LSo>0U'&@7a;AO:'N[P-$:B]$8BaIlP*0iNpDf_-K31#`s%MS-T9[f(s#/%m_)`dJ%?*mYHIFcS=)TSL&YN61Vj'PILYIYbs.]:6QPCfQd1TGp*.lH=?Fk.3Y>teP_V7">J0*R>1(/aE4SphDrp;D-Hcn)YkoB-I@2S&??q*aFZps.JZMpS8u!'TR>jVXla^j+NWo:p2*rI-6nk9#Yqgkl;grX-oc(K*cG?b=a"p#77+;+g"1#7+%+>G>e]$gs(6A5Fp7d%_@CHGt%aH``-9!nf:_qIkX's&A^s+qL@&I)*Ad%RIE`JH$G1;GCPlr$(k@_lhMaI/[KMb6iKH\llISFuXE4ZW^r.b:hcN-(Lm?#$BuQ=t0R6F3@98gKgddkE3A28i*`JM?`.0RWM:JoE&[(:^L@JTZ\]m+CrDe0Zj`uZD'9T&'$54a_ba'Nh+9:Jap7*WtD(n%oFf=1@-1a5MLqR"Igb#JB4E@(h6Na7`Bh_bJJjpiV^L\kL`'bXVN^p'Ts'0'VnLLU`r.&%C%3QkS27ViuciJ8;C$&NX$aH$%k_J]'C^i($::dJUWstnU1p52urf[IbfJs$lDPY=bHu7:n=eX%s.rr1'B<_1e^HH6kW0,.RP>@4>o#WBV@b[-J6B40Pcd3T-Lg?N]Dn(T]Vu:@0hUd7^tfW&936Z,-b`K^qcm^5g0BC;d(khH,h*,k@"UKJUf!gJ7*q'Es]rSj>cuGX+4Q`OnK%@L&q6Oj/Hl[K#QrF%C,]L"kMA013fSjpgB(Wo!)]miE=nBa\BF5?`dc=k"U*+^s\gDGLH78=bg;,La(fuP>1([am\OqgD8:sf4QoC@-thpaZ?Sb8F"r6RRs-.*B=AnI#c6`>3Ba"IG]E&o5F4X[:P!UW2Z!;_6./f\`nP6"H@$po\VOuG<0/;HF3LD-SaO+Q_4kO7Cn"-\JK'@k9f+&!jkOsj%$N$:Oj&qE@n'!+_;LjKD$JFF&C5n>InkJ1M$g;#T".+n+PYL5qi1p:#T8G-me".2-7&#)RUn1)mZ`\^j0IGMJj7'g$-TnWUY[4#.6BpR6m*J:+Ljt]FL/sm.5gcN&&@]tGV,np*U*Q>HaQs0P3j)jS_Rk[>8eAeVFGC9ZLS?npU@j%#T\:2q&!WeOnWjC"j`5t$J"_YQab7TE;nUjt8/)"/_?#c%jWF\=6T=V1Ut?r>5o"^q:^\jA1s-OVpB*&;qGJ57:UN;dQlgu7^)jNEliYZZckPh3l2Z,:EYTK*?L+tg+T:fB5j=S+'Q*e`IHSO4_,#6+nm%+T8BdMrJjZr:>'4KSA/!Cc+65[P"D(pBlj(J.8rl^EV@37*bOqDu'UL6BTTQMXF]_8ZFa%5EPN_/=*@a9=aFsH/XAtJqSA5_uMnlJ<\PsDc$c."#Xt23]A]$FPY>T\1Tg4g1BC:7`cX.rBgg(OZAf:L[D")o/:S.+$$0hkEf(c&^2ngKa^B]r`m?(]SH^<5&Ae#eB8f"+rECF20X!X-6eli';f*-\!;`$PSm::g>96$?,F\iYWm<@/KqP+t_B1lo]Od-aO,3$5d8M2oP=$$`GPk][35DHh;SAEp^H(n""STj"cTFp@4T4G%F=>BX;2q;J%kR;S@uO@Sk=sU73.X4YA55B.$:p9bKOBAsA-9CN>A2W/J?GFmfq.$QoZ3&AHH[50mZa.M.X`&3WD]PcUZ4%i.Y[?ooN8!?qWuGP=XIF?7-^;dcFBi;:4`_S*^]7]VR=r?&/aFWrL@j_6Vo1f7(8n6[(3]5dLhD7!1*Gsm1&XbnN!EZ-pOc'JJUWN&@^+qmZY2"P/EL&c!?h4CD.cA`W=Z"5uL"h"+95M>?5O?Y2fL]ekEq&9pW(d1WK/+G)qIqW<&SdjSp%uBj[HR);+^dK@I6Bn;J[L=@@pp(3kj?T3\\+ZUe'Dp6J5KH]sb[K;fFOuGS[(mBEWo*l4C==ql1:SOP2DA>NkC!8I1':\j#EeaKHHoDqNWr-$5iI_6j\qo%)$f.F]Cp8);qs.*aGJUlA)A9'efG\lQ1mQGIRMX(#%*RB:3Zq!F"q]oiYdp^JEWpu;F`eqE(V#\4DYJGE(\C=cFa#J$"+SX!kR*d1Y<@/=eLL#tQmd]Ui<\oZ!/jCoiSqTiXi>hq^0RT\+Ber6Sc"dE)9f3qpo8&kQ&P>*^+41;^R`VBE5HRF:W9Co4/dmPJ#ndIaU7.9RPd'Cl1tN3b2^9`=i5m2"@+-U%`+"P0')Tm@=ofq.pI30[T\S5mGDk34]S4QOF;-Vn6'7jbIa>S&p-*#cml*0VM5eDbijp4Z/G`LM85Z&4:`":('pT5hIt!E4lSYPJ0'.X3.[I"T[?^0tM[GuQg<)4!ShpUmUYIh\5DNIQc)Nj+$:JCN*,/c#?Fs>b/&ADo,?^p8a[Jdc&&c-IJ[HpoL[h"Y.fe=d$u"!,bA_"F9UeR4F)Kmsj9<^!2FP72ab_kE*9Mu0@0maR0gP<37-@DG2*1VI#9KK^e3)`t59.\F7DUbf"?h[k3&LnVD#st]*M=;3iUS03k?_VkFYD6t:'Q>FY0(s!$5bJ/EBs@@h`9h\\KZ&GW3F560^21XpqYADb0kVN)@.N,8]"Mtr\WV(jpbMkkdD?<_V@V<]l:l2@EgJ:>ocr5&&S8RZDP)$3#9=b%*!\)E(jKG%3'(JAJ.:-78Z_n#OT6uN@3qN#3$PB&]`o$7m=q<6]951'O>uE+kh$[ae2S13dPkC#9oiW..-*fB5@u>FU&Jd`.9`#2J-Y\o9/*[7O=V(BZ6^:r9SCiN29-)nbh0H]oq'2^fMs(n?Y%-i"^[1#V]G/INMd*25;b6fq%.?AB1_GE[%$K2<+g+sJ6u`'b8NqP_9q@k\QoHQ`>O^),=_X"*jZ%U283*dm%i#WG)bUo$XqE3:3@f\O.d%IVJI-dWp(`DYIKRt@n1VC]\pnh3nikj0'"4Q$%Td,Wl!mQo>>C[bl_Wj7f")'"'e%m,(R**nh[bmj!`TtZoqm]"I_tcXO.T85Tlg9H@c?24@]qj4lbXY9iFWN@Ook?)o1gprX;!IIlUMXbF@1pK+6TG"U4?M%+>UhiYWu3Lg^Ci=FIXaB873f]p1T_3DK&KIaG#^OdGVJC`]ap_AEmB0L][\:`+k>VGd.,:tBUiF6$K67(EAYijPPH`WkQdO(W)t4HMano!&b(p5fJI,V(+o[NBG`:")cILEI*>pkHqC*l*@r[i%.O'ZD'm&r1cM%_G:K'b9h4gSe75D2&k6T63JPN`3e3R9m%dl2[._^9b=*/O89]T'7HRJ![biA:oa;BkWot!Xh%8D;8^t*TfS=X&fSHkXZ&X.BF3gRtkK`m3\U$rKbCA?iG$4dJ*H@pc6aE[IN_X[`l+A.!3V54a]n@jNBl*2@QIe!5UI4TE4+G"37itXe!OsMHN_Ehm6OZrb:-4"S4\N!0`#Ii-/nF3+DT-=>mW2?G\Lh,Ye+j39X1DENJKIGdia=T'+HN5j%8BZ^J#W`5<9^BM3#B.8DfhVM_(C'Kmo:HA%#(#\'^[);;YY#oKfp$C:;ne[Dl(WlqH6$B*%6DFVb-,BT+X=m6^BC7Q1pLa&eC+CXtc2su%M@tYC5hRg&OUK<0mTg=B0SW85>cNk&6Prd5XY.P\%#6"8=dpKenFXuW&]Jg&cDD;=ftsbDd/loABKP)E_5;Vn(a^D^XH3XX]2;Vra1^XL6$!5XYSohX=sdhgDOGGPM$YN".al[@TQ(Xo!QZ<,bUk9=\MR6:l-("9S2k,UTSamjNF<-Y1G?Wd0aP3k'GEa$"GF,I+mJEBDga<[lCP-lb([jV:_>!7&B(*l?:giN&/Ct/LGG*I'*K/*dX/ui$7_/(N=23-bd7s-P5um@_&#canA&Y(=-f%e;,EU!\Hn\[Lk2C^LXu!CP\Ib*_bW,o:?!BBW>q973,,$W7]MhL9gk:D9u+u8oo1@J206;n2\@M`&)*m7#=+DbC.MqkEd>PJ9\bP>gD!?r;]Q-$B-F!7lt`!3<>a_7Fc@[J_7@H!U3'7O1)P9ONb=[b1BYG49a3V;Z%>o;73(c@,s8b[N:GZ9mkNJR)BpH8<[c.X+u'0`=1.'oZZm\3=IfQtTbHihKM\n]Pp04?ohc!a;AP,DhOkdt-!N8Z.2'+I6rJe-(pOMoE06lp#teG2`et^Y(5O54M$S_=$^N#q_@/_;O#I'p7q7=1=_p`>-u?ki%18DQ-4#tObU5:_64"Vmee/e###I$R77<@i"7PYiMCug-*odI\5HUjn"387OE?abtPVnHm@h,YOegWH]^$N?o,e^sip`lm:Ic)k]8)ak\Q^Yt09?ZH>Lc;)UCVp/b74HK:p%&kDbBJ#sALP!lRYcJ[M<*H#mE8tYic_lN%d/%j3UfDmp\3J1rCQ"/VAC-K]pHEE'bJ1*C#j3!,&c1IE-O(`"eXGkT/DP:S`4P26SAF:Glc1*b+Q?sppr-\9(S5=.hEMj6?A7fk'3"rQpB8fV:o^OD<:-Q;#O=@$_3-f$0'F\qc.4fg1f%?R:5GPUJab>,irKL?DD2!OSQ)BKgPLE&I$Tf3JNag=X:QA9+9HtTc],GiY[R,$Z:gs6&>[lD$F@bB_VdpV>`R'DZ5LiBWKj_`)c6)kj'H)]HA%0>?UFF&E+c=LNsrlbR190:l*FHqFar0^R?YfoHg@"JFlXD&b6bH;I\9>iUmN'([.E?PEr)'OSok'*S@Ml1lD%Tb\<;k'F^X.Q*^MDTnY*9ob=er*__[0?e*]jd<27OHV,D%tEAY^A[=6F;u8%'$\8UOmZE;Vq$drQ$Z8:j;O)AfC<7oRL.>$t@1YV!B9+r:4n1kNr0?E0>*Zr&\Q(4,@bsL(9.rMu?#N&4fAni;Q5LYgS^SPeC&UE7Ri6."K`6H!#t;Z4IjWI_T6pNtog#KSlXoJL1q[G1m9D"@4UH5n$%%5qV7q\<,^!I0=Y_P&-j^Ucj9UC:oVZmIA=:PVA>Nl8GHWqCdQV>>kafT>@5cjA^l:L'5Ut+Y4&??EbD;F'*luM4:)inkdf9h(LVSWQptd>sDck1&CO'R$_!9=<2r/gu9R2HfZ'C"%lUHZsO4sG`7Ad#S"99i9Gt5MO04KDd0jd[iasTB&H*[YZdfA[/Z;g>!KmXVXNXG3Q(E?UiLidSe>/IV%3m^OW5)-c#2KkaG0hMP"KJN.-_@S7,HhZ,kBO(8//&0ZYHb&Wea(mT0"I4.V(0T[TMYp[_\-bp*Go4&qK>SC1&SZ6,NSal_\BhI7WXdecM&cV=[P2QQaAim@?@paQQ.QGf`4tSpp%q^;9'q_\.,%,OiigaM<:E3JH/M'S)uV+ejcpFZbas@drT#@3YC.+4^a>$gm6s7i.OGXKBHRtNpBE,;%4=>D+"lSDk414/8(A-A[9n5YBHS$Q5c-f`6ChW?Sp3Bd<'Up(8*iG6r:6(K0a^a\,W3QrVeYq?Rl!DPEV[ITD8Jt3E15`=0o(n8dEL$Z%TG2e"%L+BCA2@q%9jb1RQ#KVmPZY5jr.OA3)YkN\]IBK*(POparq+q"0eJhc//g.3++Xp-s5.0F@8r;&9/g-(7(8RF(c5C7VJ4M'9"1PT])FT7!h:<>)=)]_jVXb=G@#%'g0[s#J2'A^?@bZ6A4r;ZG7@MArL=oBQ&(3?o\?XD5EORU+s9b<6$t;WTOqI1_0kn'U'7FOWmY98juk(FO(bZpFfd(M5VBl9sZ:4;!$Ib\,DMD-!rSSOH,N]VCsdce(CL\9ZZLhn+9lcch8j!B0jG;/uCSo9;=gt=f+jS:nta$An\06)^Ree^'g;jY'm_k5!dotB;V?(3aHoV@+Rst9"k0DaKQ:Cl;R@GZB)oVoBk@uUSFJJKP*1UN_uY5`Q>P=]=o5:@P,m]66@e^M_=t=J#>H'!&#JfNP:$ntQ,eHk"q,1Hh-p9,4ii=iqNaWIL7?8RXPT;bMdqpG&e?^Iq`O,n/coSbY?#HgMD8Z4N?8J>6K/laBuMNPb%n?Vdgp"`9?h!V=)__VR!i$+J93BnG9(LjS4\br8WIG?Fj[YRHt4_7N'/!"G8V[')6GGoVH_LHKqorW7_:6*tf5UE@?^Og*g/GWR*Pe5cg^hd]+kq3,mHU,Yj*heK1V,H&'(fXa28eLcpn#1uX6loZ?7d'CqDceBSk\![`i?\1I@^"N]1tl4EB7hPX\5#)gM=LQRT_5Ko9JLafi34E!I8UMXHH8g;&2Y/OH"$5kW#:sj1h2@`+0\*aVQJ@IL&!:=1TX.%NO&PC]jK'3J.gUP:&@!DHP-](G:Xp0_gj]^RBg**Il7%bG+W@"RHH8*EeBVUW6pM6Rs#")7>RDmsET4JR%EeoO6$fj!qhS+<>0s9hbX"NOI3AmeJfFbbg;KiJe"j'U8eGktak&-)1_GD36Y17d]drbJp^aSZuGa("#pT?12tcS^gJSnb9GYL?Qqg#6K3j$M:G*W6GF@^S\i!!(i/Mn2bnK0;,\;=%Dl@4lX_AoHilgFi6N5dSRXA/3FV.TNg9)a?C7/[bECZTWc"G#$GU&>:@7W*`eHCb,k2bf[T^b8#?1=:l02)TpYN5!2YiOTOLr?mVY[)4=/SL0?$\NA?kk#O)SFlrp_\+>R.X?9+6S#k$;D']AW5S_Cbh`[%%I3@m=WcV_eR:JPp!,Wr+mO-c9m/YB.77Q.GO3H="KZ3Vl/B8UT__I4r67o8(Y2F03F#5E(^0aM)7-S0e'M$/chnl#l>"'OHu'bugJ,;BLN=;6!:FW;cV_]f6grnM;@9Om/!m1HR!%.6/mjJZGjUdUnNjM2G(J@hIl4a-U9DHISi`W>q/@UNO^Y30G"=b\W7buS@?(mWbCmDFb*Ll."UoGI'UJ$a_e62"U,gP\QQ#@oCpE?''p'LE:DF6>;mF.B;EV9H"h8i6qB#bdMg:9G8Pp7D:7mFB$Vm65iO$VWTcm4ga$B]Pbc2\h(\#%*7H.@r3Flg48g#i@)/1Z.O;qQX+Ufg5.YIACH4f6)7`f7M;s/oZ0$eLW)1+iM>kme6B;d[p_e>b2RV,,'<2AK@P)mj2mP!X`Z>:uL3`36tSslT'X\Elmm?Rl1rHc0[M#co[Rn5XX\e$tj_oE(#IHn1"Z=C`=%&`M3c94\Suc6BH_"i%AEUjf&$Igh!F9q2fX5_K.q`-N*FFhccDB5r1>,pGlA[9Vf*O7PTH:pOJ5M.";los&sce07nUc@th/'qSYL*7#,aB6D^'r5@O$^%#:A!=Bo:Ka#V4:@"lDaFQb2dOb,(%N'8(GFMSUBJn;m/OOVGTj+ojS!K\;5]ak4X?0O[0Pb>r;ML]/Wbl$u63NF5-o/Y!!TYsZ7"kY5TE(!j+AS(C#R2I+jM?.&*-sVIJXZc0D%Tbl6kL#j8\F3l.'&`]D,h/`0ObDO0N)D1M/o8SLP%T2$tK0&(*TLi=\&+6'#19YZ/NlB%.#(^Xs'&G&h#q;C>,_&a5gCtN0N2\ers**&6/m7Yn;kujRE1.Vau!pE5\-"Os#:Mf%86LnH`UD2'7+Z-_`Ce68@oH8qA74)/s)/%Lb(D2gk%2$-LsB#T+CI:s.3LD.R<-Oqf`&*mUA$&S4(2I)V;91Gh/L\+bI'q.!@k=]D(_)CW+sFD_`Q3*/QT/tD#8@b4:OD8X+aI,9PtrL)l&;Q2U-u@W*CKem'_]&Po5!CU_=1aBDAY)B<7.5q0P&!9pbB;#n"6oaO`W:*Uqn-`)TJFf$8VN,D-'@L`cu!79Ld/'>r#;]cu%a!JMqrVW`M`1;dCTeo&kncT8A,Q*-G7a`3fDa`*B!_8K,2;[sZda81$:_u"5^$6_f8*69;&GZROo>E[]dPsA@k9!m"E-Ghc!YHeF5AX)e1\>!Mn+YZA_M1$6nGDK9YJ3:FZFA9MM100!*99L.5a*"7uTY+-==4FX2qL$:/&l5bng?=V38rMY@,ILh3dRVL;g2e#Q6D+QLRBIJ#K7!m6/nf;XN*p:2m2FU>Sih8j0;&g#P;,cBrEC?ERd)]@&+/qDu&>L4@FW8ZhG(FM8A(`+ldl`o?TY229fS6%Yh>4b@=omfLPThMU-D63h&nD?*!Z1t_J0AI'.Yqb1C*o5N!Jj\\?]ebJ-bWia@CF#5<(&^gOD02^lkkfC,26e\7O7&MpS;qn6Tfn`OTuiL#Y300BEFDfq,7>8OcG4;0g#ercHbn>E'$qH/uBbK%Sc#Lg`f=(>YM(Ck#!7U&G_TVD]2Q;#t=n8.(<2a0NUd_DX_:bZM"1)knrRCcUeLPG^GRt9Yd`?-6ZauiKEO:))]DY@Q]aATkXmI"[n1*J2C/m;27\KEX9OQKV]bp*)]6.5FM<&;#9As.'s_.fo8:M"@;.ZkZrlhXMGraQ):ILe)2#0FNFn3B<^7`nVmAs'u:V&!3ldK`I5Z>C`8QRY?5C\b17c-Fu]%_SsSS2CAX@@O=9M>3laR1euCb^2u^N$p;G"ba]B/;;(jiIO+6*#UQEJo\QJ#o,;_bAItKi]D@s]f]D.DAUnGtEXmmg$7qYe;Lmsd'5/:!$Nud5Os3KD'/4D.Sn]q)9hg;N9D*$Z$P/*bO@Y1Qr;bSL3`&d'q+qPBN*]n?a;?Oa"rIFd9Nu?kYJG:eoAK0oB_^A"Q;8e\iom/!4i_s_he2[e125DEr<1H+as^3q6iAe)s*a[fQ@93$W;S/bf6>D]@ZG%4_ZY-&1k]-Mp0SMWhJRARKSbii<6S3oGYtsEX*j5JE62RqRo,Q<6IF*t@)E_bVh(Pm^r(E[bC,^kGV%<].$Jg'27ql%0Oda%fO.:^&oY4/9:5UW5m&<-Le*:hajK?,[i<**X8o]Sh]+SK1C[n1QAh%ilEqRb1*I>`")4SH3V0R].L?`H)&F,J)29(;M65jhad23<8/`fu'6XSRaTG-:nVM;A'<3^:'!OP\,!G`G)E[$R5T7q-G(W.,Z+f&%>d7-VPnF6KNJ`I)7-#bP$>G(*25hFaaNC$p#q5!#)q7XB,)/l4Q?cR_9lE)FT@=5Mh&C6?2>/rFpQOOL65`Nm'6VoB0p.aqY+[If(W8JCo&/t/@'gB3.R^hGN_.O=RPPuO)S!E_7P6EdmVD,jc>M`E)e%Rq'4X7)=\nbub;QO0u;(upd,f@oX.@8J[k,OY4R3[%$P]UkU%$a-$+aZr,ONSap"Lp'C-nn-pfRi=A7Ir;m`/,'K.&('HiC(E8E=iH7LKqfh<4UErl@G^n;/mn@3(0l#/#Pon@aJgf3Y&N:^'S$`bI_daiaP\b;+X^)%6SV;"\h/H`2)qlRcfsiODu)g,kZNLX1=K./VjY@ZH\37$6Kics&NE\fIf0'_@eSJj1+k.\]YC-'/IdW@u2U9,mk:PFXIghcOlkrj?-RO8(OjE%-Lj8WR4\6])l\OqeQLN6rQ%(7us,O=ikH4PiQk&h!sY<>D2OY"Gpsi0g98[NU5+!XoW/Sk=Ym`C(l)6H0F3Ygf+pOG5c#f7q_@T)&j@kc)\@3ie;G&(U\oe`c;0u:DAL5/U/(nl8Map=g3E>60lG8R`\?.UPn#9\R,t)",q,SGmitgqp/)DS3[DBgZqII-=S(TUZ\!_?b`^"*iMj=pb\bl\SK$KBaMNbZ1OMDMMH/^sN4:d%_P-Hu_/n"F'=)42<3nk^9l$XRo^s4gaQJOkdtk77iF$e('BEa(>^YNcd!@:`?DQ@!R0?HTcqMdk2EngDJ5]o3X,[PQ]hd'0YnV,_*&*-3NkR9=#+d(k@)T\M;\]*._q^nQpg*U%l?n]/9$iPnYd-I_\kAo7VO2Y:$$nfn;GKu=ka,o@Obj4j1*BcZ&O>T3+]PTS;AK+hjNh+^^Pi%$3bJQ(F!Z=46IPFa(7R!Wh#j,K`L%N-)Pof>tfLH4EFj"H!c-Sg"=#a]U#pIK\V=cgkp>QjqegbTW/\>CQ"'P&?@4j#.#"97#hE>V#h*#/iNsX'+V25,"t_@Jf'$D;^"usNn"]_D=;O#5)gRorJ(/.q`^%,=/'d'G3F)lqT\=b-Y3u/Q*UT>Cl[OOM.:L=>1R42oZL8Q/IEV*U8G5!BKH\t&A`fBkA""%jC^:YO:Fs;U_MnSm1eBuk*F(?su)2Q@qZ8jir87DcGq\CO_)B5`-DGNPn^sHd/A51k"Tb`Yo"l,=PBc2f[Hkn\XR8$aAI)IYpH4T/M/@^B_`QK6d^I)")B?@'jjga_On&P%JZ;>cl?`QP9I*8`<+Hr!Qqc'jI^5;o(('H$D@iC_So-q;'s_?Gb`+7X31NB.]k&86JTale"bAr$b$Z[LaPh#)T=be@AV[jh#Z_TGep2UC6;,#D*q_YoYmObnZ5GHa=at.Mhi:5`]05sF_UL14cYaYKS^og0d>'ZNf`h>9q4u\3n9u=Su'^'@:[+be.qWhiD[dM3X0'H<)m!QO71g`N[fk(nWZ3LUN;bRq4-jYSL.aB(F*Q%RE`#.YIYDl!>EOaEFJA!I;$ZX*]Z13n]#)UulG-K2k)!ZR$Ui3;%8[H'>31?'`j/Kab_48gYZ66e7?7I-,e&#P'Pg,UOU?TKKA4].?m%2Yg@Fi0Lr6WSAB$)S;o%`YVlN`u(9F`\>&VX`.L5cSs%rG:>ed!gjC(U)^K?XXgW#gS4ZocS5N*u"cVeLe8[8;._&i0WFN2Qp,j)"=b=-4n\1'EDsnhgRj=(Se4Gu;fp5=\)m#%(;#SMTit`QHaMZ$!RO&,Un4WknHn5W$O7$.VsaO'+m%k`3Vsi-31.Z'L`h)pF.B4tquCsfM(==='b*?cG--(Q]Ec*C'kpCA/:kt;'Rb0&EW>t]gmW$;3/Nrrsurbqr#7Z_he6'bpP62qZh^Dq@Ie)J-J0fLYj;oJO2W>&JD)2O'JC"=UpsH"26QfcY,-VLef]G@/TXFS\mtg5K<\,4JDSl)@.9/&dD7$Tu?'?IK'%j>b;,_<-e:1_25a$MLI:]aA!7$@W-KgPaXVJp(J(pk_B[Ya&9`Kt8mh.4C#J$hdPF$":u9Z]/78J>#TC2"*$X/,-]b#(Qh`$c1blmWDQJsS3J'8>*K4e=t-3>#=(`\*AU5qqrdU>0KuUmn8NNC42<<:HVG-G%0_,)mcn=DKB)P(Z``:pe%>&AcHt1u^ipUm@%0d=cS9KSR]4A-[Z,D^7DAoQ]usqrRE6-r,gnC6ema"."X)4I%T&F3OEQii%&A2cMUP=3Ps,4T-=BjU,N#5gUM$;+Weh%4\S9F%5U]-E#H:U('MZ^u.LhSJ"OVNC*CBpO1d$FnK-_\WGuf_7&8i0b>n\\mZt:@[&7@N>aa3Z>ms\o?D3fAL*]uESk-)1L/le$(#9j+QoV/*FKk`*PC:,ZZF1856KeujkOL^?I5;$&E-@?i`DQ4Z/gA;:?O:ZAP4S0m)XQp8YQRs5l;K$IUGc//V/!KV*D6>]aYr>5D]n[Lisi\2#t]h5a2tjXI6JuESQf>SGO9[h4F3TYf$Z?@P&iNP"q;c40fhOVI^f&;PBqHjBPL7:$rT(f$A@^E3>-#8%!UB"u!@Vs(BRN'-:HVDIN#,%,B;4;SI"ckpZ@#%M;-4:rh\%)?]30Qb)r9W3"U5L!1ZHuLt[Y@RjpB`N`UoS<:OiZFlg-CSC.lrMZ@=aEVZ8!Ra^#(Y&G>$;!-R$]ZY_AJO?RI`N6>a=7k#s??I#lhcY+,YK=,f3N$E@=BiE=!%sauN8"iWLXT"b4c(KZO*f:59[s(`0Vg4s%>S?XKiIDm7,nE`Z>?j6[j3m%.$qQ/g[11mhIC5ID$G=!=c;HMKT@Qmi;M)>4XW!=m(J[8]AR*_@,j0Y.cLl5'uQ'g$gA5*:P,mY\o5[k!@9$eZDO-!5u<5-#mhgZ16BXQ$r%$664STt8-sAELIN$\7i2Yn"KTreKHgL6%gN)T3(uXQ4ZSlmUAfM39_sU%k?$=;7MoR3N,Q\NIE:QriIpn'Q;adOgeTAr8Arlkr#S,%Z[*.siJAp=ZroBfCZJq4I><(`OL5h1OS'5?BpTI;PhcqU+l!kIbn1!X0pi5q,!/5$H+Up>VMO\cF2s@TQ`m;!^arm3qV33j&&Y5;\P39q!MJiTc8gP+Atod=2Qg6`7@D@%(.re0m/.&^eH,3=)G;JTp)al%6^e(T'Eu#i$)F4EEp1F`@HC#\q/YGkS7ouuom2FBm\M5u*BG"k#2]Lr,`@7tNsfDH8#1I9G5\>4J'-Zl7=Pfg'q@XPj2SV?2W6P/%m5`Terkhc[Ig_pNVpnf0`P$!rX,_VhGr8WS(qCm2)\a6_=MZak-*ooe1oCq#K%%EIGan=qUg3+X\-G5B\.WR]FPL0-i5i@"F!%tTh:,B(QkINB_fD)0SL:3cGJ\C@8lC&q8dHuaB$42WFb89$g'3NI,T/RJbWrnj@I?d8W&n,5KKs-KV^YQ$eInFZ_+nD<:,j8;+8*l$P1?f1lJ\,APdINSFde,GuOqu8>Js5X-Wec5)6q1"J'5L7m[5Onb*4X0Opg45R1&)i19K0E\"$f5?VTA0B,(N>_Ue/SA'%7*hgZ&)KV&Q@[%qAa3_C7*"A&J@]HcaI?uZ>sH:mY*3A^Y]n.5oj>!"i(V0SRE"B#N7uBKe;7[2A%@)Qd!6T1L[H?Lj:pS0JL^iNZU5HP%:\'.=Y[2+]Y1b_?*!:8cD=84Q@>?NkcYl#80b6jE$`brt`AahY)""JJe^/s(7&8gZ!e%."@Qo"=Nl;PJ:6AE&IG\8ese24p*s.]E@HJ725s!Y.&Tg.71#"!&0m:gN(/784#jA1ebF_n\N+&T@Nm=L$I%EhaeXq;jAA\+ubWJYL(u#1-Koqs/`TBHJ>:E>)gaAG@\U&Nb=3#ht-"E!T_Kn2PeXRpamY[&Rfstkt8$X)'W*r;SVM91Q[cA6N.h5h\XlC"Mhu&lnsp,0S=?nO46I-RaUfR1=jX`QPa=NUQLT18,9oQ=AHok7)]lpclrs9+s@miL96l3TGT51fjb5g,tiCee%r^4!VkZ='p])XW&dt0,"(REmQ3qaFus$/`T7.W32]Mjq`jrRK22jrN)BV.)ma#BF8>h+cNr5Z$@#ol!D!n:+qt%m,q,`lNAM=U$Re2Sl44_-ob*WY*BCn/4AW0bf1G#cA9YJ>jGAjh^o3s-eM3;S7$V3%_>!Cas%^D/]`#/11.3s.]W#A#CIH#(;`R6<[T2JM!@>8ur<%\`)*W\,nYg/F(A.t#,MEl4gLTG2s8A4QdTe=EY7Fu##7,SLjE;J"Q9[4+ERXN,9a<9'972gBp2F8?"_tOlBp5q7>7!_RB&f=fIY+rD?7=k,]OA2?kBlKEd^'*rM5!0J4,>/!?%O`,6Dt6#TjgtX17AVkm.P]%9KB#gpHl(L;@fikYkR.*an>,)4%#(]1"Hm/L4fYo'<*A[M'b$n_u*$p+:H=kh@<<6Nl7QqH:'s90bbj?%CV`n1B$huir5Op&V=Fj#HjcmLN.nEm"+mr8*Id6,l:`dnd5p&nB'd_1k3UlqKTc4_nao%#"e])NnOEcIp]4n1gn9pnO]Nh_+).+TD#H`YPaR'ENRJ1?hu8i]8klGU9N10KT.Aoa\8*1HP`6[e"`CAf7'"B*,^8=Fi>9`d-/LIPeLE"EsDXb0PZ\Y;k1t+.Qi,V&X11'AI-;r+JX(D*aWIFbj@TA3.K&B^](J*1jj6AG(0/!=,6P&@@8qGa;Qnt>gnV4BZ%^:bi@RSMcImU*g4Cm42S)'N%]P&me;rH0LcC0N-s,.3!'Wj`S?SN'I4Y*cYl& +# ===>END WOOF<=== From 371b1b01cbf3ab0fbca85c461e56a95e99145a29 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Wed, 8 Aug 2007 14:19:56 -0700 Subject: [PATCH 236/278] fix race in csma-cd channel --- src/devices/csma-cd/csma-cd-channel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/csma-cd/csma-cd-channel.cc b/src/devices/csma-cd/csma-cd-channel.cc index 7b6d211f7..30c84deda 100644 --- a/src/devices/csma-cd/csma-cd-channel.cc +++ b/src/devices/csma-cd/csma-cd-channel.cc @@ -267,7 +267,6 @@ CsmaCdChannel::PropagationCompleteEvent() m_currentPkt.GetUid () << ")"); NS_ASSERT(m_state == PROPAGATING); - m_state = IDLE; NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): Receive"); @@ -279,6 +278,7 @@ CsmaCdChannel::PropagationCompleteEvent() it->devicePtr->Receive (m_currentPkt); } } + m_state = IDLE; } From a7de7bcf31be8c5b210c790221a637755859535f Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 8 Aug 2007 20:56:59 -0700 Subject: [PATCH 237/278] Removing (again?) src/devices/p2p --- src/devices/p2p/p2p-channel.cc | 186 ---------------- src/devices/p2p/p2p-channel.h | 128 ----------- src/devices/p2p/p2p-net-device.cc | 354 ------------------------------ src/devices/p2p/p2p-net-device.h | 313 -------------------------- src/devices/p2p/p2p-topology.cc | 172 --------------- src/devices/p2p/p2p-topology.h | 87 -------- src/devices/p2p/wscript | 24 -- 7 files changed, 1264 deletions(-) delete mode 100644 src/devices/p2p/p2p-channel.cc delete mode 100644 src/devices/p2p/p2p-channel.h delete mode 100644 src/devices/p2p/p2p-net-device.cc delete mode 100644 src/devices/p2p/p2p-net-device.h delete mode 100644 src/devices/p2p/p2p-topology.cc delete mode 100644 src/devices/p2p/p2p-topology.h delete mode 100644 src/devices/p2p/wscript diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc deleted file mode 100644 index cbc3eb805..000000000 --- a/src/devices/p2p/p2p-channel.cc +++ /dev/null @@ -1,186 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "p2p-channel.h" -#include "p2p-net-device.h" -#include "ns3/packet.h" -#include "ns3/simulator.h" -#include "ns3/debug.h" - -NS_DEBUG_COMPONENT_DEFINE ("PointToPointChannel"); - -namespace ns3 { - -// -// By default, you get a channel with the name "PointToPoint Channel" that -// has an "infitely" fast transmission speed and zero delay. -// -PointToPointChannel::PointToPointChannel() -: - Channel ("PointToPoint Channel"), - m_bps (DataRate(0xffffffff)), - m_delay (Seconds(0)), - m_nDevices(0) -{ - NS_DEBUG("PointToPointChannel::PointToPointChannel ()"); -} - -PointToPointChannel::PointToPointChannel( - const DataRate& bps, - const Time& delay) -: - Channel ("PointToPoint Channel"), - m_bps (bps), - m_delay (delay), - m_nDevices(0) -{ - NS_DEBUG("PointToPointChannel::PointToPointChannel (" << Channel::GetName() - << ", " << bps.GetBitRate() << ", " << delay << ")"); -} - -PointToPointChannel::PointToPointChannel( - const std::string& name, - const DataRate& bps, - const Time& delay) -: - Channel (name), - m_bps (bps), - m_delay (delay), - m_nDevices(0) -{ - NS_DEBUG("PointToPointChannel::PointToPointChannel (" << name << ", " << - bps.GetBitRate() << ", " << delay << ")"); -} - - void -PointToPointChannel::Attach(Ptr device) -{ - NS_DEBUG("PointToPointChannel::Attach (" << device << ")"); - NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted"); - NS_ASSERT(device != 0); - - m_link[m_nDevices].m_src = device; - ++m_nDevices; -// -// If we have both devices connected to the channel, then finish introducing -// the two halves and set the links to IDLE. -// - if (m_nDevices == N_DEVICES) - { - m_link[0].m_dst = m_link[1].m_src; - m_link[1].m_dst = m_link[0].m_src; - m_link[0].m_state = IDLE; - m_link[1].m_state = IDLE; - } -} - - bool -PointToPointChannel::TransmitStart(Packet& p, Ptr src) -{ - NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << - ")"); - NS_DEBUG ("PointToPointChannel::TransmitStart (): UID is " << - p.GetUid () << ")"); - - NS_ASSERT(m_link[0].m_state != INITIALIZING); - NS_ASSERT(m_link[1].m_state != INITIALIZING); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - - if (m_link[wire].m_state == TRANSMITTING) - { - NS_DEBUG("PointToPointChannel::TransmitStart (): **** ERROR ****"); - NS_DEBUG("PointToPointChannel::TransmitStart (): state TRANSMITTING"); - return false; - } - - NS_DEBUG("PointToPointChannel::TransmitStart (): switch to TRANSMITTING"); - m_link[wire].m_state = TRANSMITTING; - return true; -} - - bool -PointToPointChannel::TransmitEnd(Packet& p, Ptr src) -{ - NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")"); - NS_DEBUG ("PointToPointChannel::TransmitEnd (): UID is " << - p.GetUid () << ")"); - - NS_ASSERT(m_link[0].m_state != INITIALIZING); - NS_ASSERT(m_link[1].m_state != INITIALIZING); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - - NS_ASSERT(m_link[wire].m_state == TRANSMITTING); - - m_link[wire].m_state = PROPAGATING; -// -// The sender is going to free the packet as soon as it has been transmitted. -// We need to copy it to get a reference so it won't e deleted. -// - Packet packet = p; - NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << - m_delay.GetSeconds () << "sec"); - Simulator::Schedule (m_delay, - &PointToPointChannel::PropagationCompleteEvent, - this, packet, src); - return true; -} - - void -PointToPointChannel::PropagationCompleteEvent( - Packet p, - Ptr src) -{ - NS_DEBUG("PointToPointChannel::PropagationCompleteEvent (" << &p << ", " << - src << ")"); - NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): UID is " << - p.GetUid () << ")"); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - NS_ASSERT(m_link[wire].m_state == PROPAGATING); - m_link[wire].m_state = IDLE; - - NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): Receive"); - m_link[wire].m_dst->Receive (p); -} - - uint32_t -PointToPointChannel::GetNDevices (void) const -{ - return m_nDevices; -} - - Ptr -PointToPointChannel::GetDevice (uint32_t i) const -{ - NS_ASSERT(i < 2); - return m_link[i].m_src; -} - - DataRate -PointToPointChannel::GetDataRate (void) -{ - return m_bps; -} - - Time -PointToPointChannel::GetDelay (void) -{ - return m_delay; -} - -} // namespace ns3 diff --git a/src/devices/p2p/p2p-channel.h b/src/devices/p2p/p2p-channel.h deleted file mode 100644 index b534df915..000000000 --- a/src/devices/p2p/p2p-channel.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef POINT_TO_POINT_CHANNEL_H -#define POINT_TO_POINT_CHANNEL_H - -#include -#include "ns3/channel.h" -#include "ns3/ptr.h" -#include "ns3/packet.h" -#include "ns3/nstime.h" -#include "ns3/data-rate.h" - -namespace ns3 { - -class PointToPointNetDevice; - -/** - * \brief Simple Point To Point Channel. - * - * This class represents a very simple point to point channel. Think full - * duplex RS-232 or RS-422 with null modem and no handshaking. There is no - * multi-drop capability on this channel -- there can be a maximum of two - * point-to-point net devices connected. Once we start talking about multi- - * drop, or CSMA, or some other sharing mechanism, things begin getting - * complicated quickly. Rather than invent some ad-hoc mechanism, we just - * Keep It Simple everywhere. - * - * When the channel is instaniated, the constructor takes parameters for - * a single speed, in bits per second, and a speed-of-light delay time as a - * Time object. Both directions use the same speed and delay time. - * - * There are two "wires" in the channel. The first device connected gets the - * [0] wire to transmit on. The second device gets the [1] wire. There is a - * state (IDLE, TRANSMITTING) associated with each wire. - */ -class PointToPointChannel : public Channel { -public: -// -// This is really kidding myself, since just setting N_DEVICES to 3 isn't -// going to come close to magically creating a multi-drop link, but I can't -// bring myself to just type 2 in the code (even though I type 0 and 1 :-). -// - static const int N_DEVICES = 2; - /** - * \brief Create a PointToPointChannel - * - * By default, you get a channel with the name "PointToPoint Channel" that - * has an "infitely" fast transmission speed and zero delay. - */ - PointToPointChannel (); - - /** - * \brief Create a PointToPointChannel - * - * \param bps The bitrate of the channel - * \param delay Transmission delay through the channel - */ - PointToPointChannel (const DataRate& bps, const Time& delay); - - /** - * \brief Create a PointToPointChannel - * - * \param name the name of the channel for identification purposes - * \param bps The bitrate of the channel - * \param delay Transmission delay through the channel - */ - PointToPointChannel (const std::string& name, - const DataRate& bps, const Time& delay); - - /** - * \brief Attach a given netdevice to this channel - * \param device pointer to the netdevice to attach to the channel - */ - void Attach (Ptr device); - bool TransmitStart (Packet& p, Ptr src); - bool TransmitEnd (Packet &p, Ptr src); - void PropagationCompleteEvent(Packet p, Ptr src); - - - virtual uint32_t GetNDevices (void) const; - virtual Ptr GetDevice (uint32_t i) const; - - virtual DataRate GetDataRate (void); - virtual Time GetDelay (void); - -private: - DataRate m_bps; - Time m_delay; - - int32_t m_nDevices; - - enum WireState - { - INITIALIZING, - IDLE, - TRANSMITTING, - PROPAGATING - }; - - class Link - { - public: - Link() : m_state (INITIALIZING), m_src (0), m_dst (0) {} - WireState m_state; - Ptr m_src; - Ptr m_dst; - }; - - Link m_link[N_DEVICES]; -}; - -} // namespace ns3 - -#endif /* POINT_TO_POINT_CHANNEL_H */ diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc deleted file mode 100644 index 9542d951b..000000000 --- a/src/devices/p2p/p2p-net-device.cc +++ /dev/null @@ -1,354 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2005,2006 INRIA - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Mathieu Lacage - */ - -#include -#include -#include "ns3/debug.h" -#include "ns3/queue.h" -#include "ns3/simulator.h" -#include "ns3/composite-trace-resolver.h" -#include "p2p-net-device.h" -#include "p2p-channel.h" - -NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice"); - -namespace ns3 { - -PointToPointNetDevice::PointToPointNetDevice (Ptr node) -: - NetDevice(node, MacAddress ("00:00:00:00:00:00")), - m_txMachineState (READY), - m_bps (DataRate (0xffffffff)), - m_tInterframeGap (Seconds(0)), - m_channel (0), - m_queue (0), - m_rxTrace () -{ - NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << node << ")"); - - // BUGBUG FIXME - // - // You _must_ support broadcast to get any sort of packet from the ARP layer. - EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff")); - EnableMulticast(); - EnablePointToPoint(); -} - -PointToPointNetDevice::~PointToPointNetDevice() -{ - NS_DEBUG ("PointToPointNetDevice::~PointToPointNetDevice ()"); - m_queue = 0; -} - -// -// Copy constructor for PointToPointNetDevice. -// -// We use the underlying NetDevice copy constructor to get the base class -// copied. These just remain as is (e.g. you get the same name, the same -// MAC address). If you need to fix them up, YOU, the copier need to do -// that. -// -// The things we need to be careful of are the channel, the queue and the -// trace callback. If the channel pointer is non-zero, we copy the pointer -// and add a reference. If the queue is non-zero, we copy it using the queue -// assignment operator. We don't mess with the trace -- we just reset it. -// We're assuming that the tracing will be set up after the topology creation -// phase and this won't actually matter. -// -PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd) -: - NetDevice(nd), - m_txMachineState(READY), - m_bps (nd.m_bps), - m_tInterframeGap (nd.m_tInterframeGap), - m_channel(nd.m_channel), - m_queue(0), - m_rxTrace () -{ - NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << &nd << ")"); - - if (nd.m_queue) - { - m_queue = nd.m_queue; - } - -} - -void PointToPointNetDevice::DoDispose() -{ - m_channel = 0; - NetDevice::DoDispose (); -} - -// -// Assignment operator for PointToPointNetDevice. -// -// This uses the non-obvious trick of taking the source net device passed by -// value instead of by reference. This causes the copy constructor to be -// invoked (where the real work is done -- see above). All we have to do -// here is to return the newly constructed net device. -// - PointToPointNetDevice& -PointToPointNetDevice::operator= (const PointToPointNetDevice nd) -{ - NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")"); - return *this; -} - - void -PointToPointNetDevice::SetDataRate(DataRate bps) -{ - m_bps = bps; -} - - void -PointToPointNetDevice::SetInterframeGap(Time t) -{ - m_tInterframeGap = t; -} - - bool -PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) -{ - NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); - NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); - - NS_ASSERT (IsLinkUp ()); - -#ifdef NOTYET - struct NetDevicePacketDestAddress tag; - tag.address = address; - p.AddTag (tag); -#endif - -// -// This class simulates a point to point device. In the case of a serial -// link, this means that we're simulating something like a UART. This is -// not a requirement for a point-to-point link, but it's a typical model for -// the device. -// -// Generally, a real device will have a list of pending packets to transmit. -// An on-device CPU frees the main CPU(s) of the details of what is happening -// in the device and feeds the USART. The main CPU basically just sees the -// list of packets -- it puts packets into the list, and the device frees the -// packets when they are transmitted. -// -// In the case of our virtual device here, the queue pointed to by m_queue -// corresponds to this list. The main CPU adds packets to the list by -// calling this method and when the device completes a send, the packets are -// freed in an "interrupt" service routine. -// -// We're going to do the same thing here. So first of all, the incoming packet -// goes onto our queue if possible. If the queue can't handle it, there's -// nothing to be done. -// - if (m_queue->Enqueue(p) == false ) - { - return false; - } -// -// If there's a transmission in progress, the "interrupt" will keep the -// transmission process going. If the device is idle, we need to start a -// transmission. -// -// In the real world, the USART runs until it finishes sending bits, and then -// pulls on the device's transmit complete interrupt wire. At the same time, -// the electrons from the last wiggle of the wire are busy propagating down -// the wire. In the case of a long speed-of-light delay in the wire, we could -// conceivably start transmitting the next packet before the end of the -// previously sent data has even reached the end of the wire. This situation -// is usually avoided (like the plague) and an "interframe gap" is introduced. -// This is usually the round-trip delay on the channel plus some hard-to- -// quantify receiver turn-around time (the time required for the receiver -// to process the last frame and prepare for reception of the next). -// -// So, if the transmit machine is ready, we need to schedule a transmit -// complete event (at which time we tell the channel we're no longer sending -// bits). A separate transmit ready event (at which time the transmitter -// becomes ready to start sending bits again is scheduled there). Finally, -// we tell the channel (via TransmitStart ()) that we've started wiggling the -// wire and bits are coming out. -// -// If the transmit machine is not ready, we just leave and the transmit ready -// event we know is coming will kick-start the transmit process. -// - if (m_txMachineState == READY) - { - return TransmitStart (p); - } - return true; -} - - bool -PointToPointNetDevice::TransmitStart (Packet &p) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitStart (" << &p << ")"); - NS_DEBUG ( - "PointToPointNetDevice::TransmitStart (): UID is " << p.GetUid () << ")"); -// -// This function is called to start the process of transmitting a packet. -// We need to tell the channel that we've started wiggling the wire and -// schedule an event that will be executed when it's time to tell the -// channel that we're done wiggling the wire. -// - NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); - m_txMachineState = BUSY; - Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize())); - - NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " << - "Schedule TransmitCompleteEvent in " << - tEvent.GetSeconds () << "sec"); - - Simulator::Schedule (tEvent, - &PointToPointNetDevice::TransmitCompleteEvent, - this); - return m_channel->TransmitStart (p, this); -} - - void -PointToPointNetDevice::TransmitCompleteEvent (void) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); -// -// This function is called to finish the process of transmitting a packet. -// We need to tell the channel that we've stopped wiggling the wire and -// schedule an event that will be executed when it's time to re-enable -// the transmitter after the interframe gap. -// - NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = GAP; - Packet p; - bool found; - found = m_queue->Dequeue (p); - NS_ASSERT_MSG(found, "Packet must be on queue if transmitted"); - NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << - p.GetUid () << ")"); - m_channel->TransmitEnd (p, this); - - NS_DEBUG ( - "PointToPointNetDevice::TransmitCompleteEvent (): " << - "Schedule TransmitReadyEvent in " - << m_tInterframeGap.GetSeconds () << "sec"); - - Simulator::Schedule (m_tInterframeGap, - &PointToPointNetDevice::TransmitReadyEvent, - this); -} - - void -PointToPointNetDevice::TransmitReadyEvent (void) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()"); -// -// This function is called to enable the transmitter after the interframe -// gap has passed. If there are pending transmissions, we use this opportunity -// to start the next transmit. -// - NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); - m_txMachineState = READY; - - if (m_queue->IsEmpty()) - { - return; - } - else - { - Packet p; - bool found; - found = m_queue->Peek (p); - NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); - TransmitStart (p); - } -} - -TraceResolver * -PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context) -{ - CompositeTraceResolver *resolver = new CompositeTraceResolver (context); - resolver->Add ("queue", - MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)), - PointToPointNetDevice::QUEUE); - resolver->Add ("rx", - m_rxTrace, - PointToPointNetDevice::RX); - return resolver; -} - -bool -PointToPointNetDevice::Attach (Ptr ch) -{ - NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")"); - - m_channel = ch; - - m_channel->Attach(this); - m_bps = m_channel->GetDataRate (); - m_tInterframeGap = m_channel->GetDelay (); - - /* - * For now, this device is up whenever a channel is attached to it. - * In fact, it should become up only when the second device - * is attached to the channel. So, there should be a way for - * a PointToPointChannel to notify both of its attached devices - * that the channel is 'complete', hence that the devices are - * up, hence that they can call NotifyLinkUp. - */ - NotifyLinkUp (); - return true; -} - -void -PointToPointNetDevice::AddQueue (Ptr q) -{ - NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")"); - - m_queue = q; -} - -void -PointToPointNetDevice::Receive (Packet& p) -{ - // ignore return value for now. - NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); - - m_rxTrace (p); - ForwardUp (p); -} - -Ptr -PointToPointNetDevice::GetQueue(void) const -{ - return m_queue; -} - -Ptr -PointToPointNetDevice::DoGetChannel(void) const -{ - return m_channel; -} - -bool -PointToPointNetDevice::DoNeedsArp (void) const -{ - return false; -} - -} // namespace ns3 diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h deleted file mode 100644 index e1eb8a666..000000000 --- a/src/devices/p2p/p2p-net-device.h +++ /dev/null @@ -1,313 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (c) 2007 University of Washington - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Author: Craig Dowell - */ - -#ifndef POINT_TO_POINT_NET_DEVICE_H -#define POINT_TO_POINT_NET_DEVICE_H - -#include -#include "ns3/mac-address.h" -#include "ns3/node.h" -#include "ns3/net-device.h" -#include "ns3/callback.h" -#include "ns3/packet.h" -#include "ns3/callback-trace-source.h" -#include "ns3/nstime.h" -#include "ns3/data-rate.h" -#include "ns3/ptr.h" - -namespace ns3 { - -class Queue; -class PointToPointChannel; - -/** - * \class PointToPointNetDevice - * \brief A Device for a Point to Point Network Link. - * - * Ns-3 takes a four-layer view of a protocol stack. This is the same model - * that TCP uses. In this view, layers 5-7 of the OSI reference model are - * grouped together into an application layer; layer four (transport / TCP) is - * broken out; layer three (network / IP) is broken out; and layers 1-2 are - * grouped together. We call this grouping of layers one and two a NetDevice - * and represent it as a class in the system. - * - * The NetDevice class is specialized according to the needs of the specific - * kind of network link. In this case, the link is a PointToPoint link. The - * PointToPoint link is a family of classes that includes this class, the - * PointToPointNetDevice, a PointToPointChannel class that represents the - * actual medium across which bits are sent, a PointToPointIpv4Interface class - * that provides the hook to tie a general purpose node to this specific - * link, and finally, a PointToPointTopology object that is responsible for - * putting all of the pieces together. - * - * This is the PointToPointNetDevice class that represents, essentially, the - * PC card that is used to connect to the PointToPoint network. - */ -class PointToPointNetDevice : public NetDevice { -public: - /** - * Enumeration of the types of traces supported in the class. - * - */ - enum TraceType { - QUEUE, /**< Trace queue events on the attached queue */ - RX, /**< Trace packet reception events (from the channel) */ - }; - /** - * Construct a PointToPointNetDevice - * - * This is the constructor for the PointToPointNetDevice. It takes as a - * parameter the Node to which this device is connected. Ownership of the - * Node pointer is not implied and the node must not be deleded. - * - * @see PointToPointTopology::AddPointToPointLink () - * @param node the Node to which this device is connected. - */ - PointToPointNetDevice (Ptr node); - /** - * Copy Construct a PointToPointNetDevice - * - * This is the copy constructor for the PointToPointNetDevice. This is - * primarily used in topology creation. - * - * @see PointToPointTopology::AddPointToPointLink () - * @param nd the object to be copied - */ - PointToPointNetDevice (const PointToPointNetDevice& nd); - /** - * Destroy a PointToPointNetDevice - * - * This is the destructor for the PointToPointNetDevice. - */ - virtual ~PointToPointNetDevice(); - /** - * Assignment Operator for a PointToPointNetDevice - * - * This is the assignment operator for the PointToPointNetDevice. This is - * to allow - * - * @param nd the object to be copied - */ - PointToPointNetDevice& operator= (PointToPointNetDevice nd); - /** - * Set the Data Rate used for transmission of packets. The data rate is - * set in the Attach () method from the corresponding field in the channel - * to which the device is attached. It can be overridden using this method. - * - * @see Attach () - * @param bps the data rate at which this object operates - */ - void SetDataRate(DataRate bps); - /** - * Set the inteframe gap used to separate packets. The interframe gap - * defines the minimum space required between packets sent by this device. - * It is usually set in the Attach () method based on the speed of light - * delay of the channel to which the device is attached. It can be - * overridden using this method if desired. - * - * @see Attach () - * @param t the interframe gap time - */ - void SetInterframeGap(Time t); - /** - * Attach the device to a channel. - * - * The PointToPointTopology object creates a PointToPointChannel and two - * PointtoPointNetDevices. In order to introduce these components to each - * other, the topology object calls Attach () on each PointToPointNetDevice. - * Inside this method, the Net Device calls out to the PointToPointChannel - * to introduce itself. - * - * @see PointToPointTopology::AddPointToPointLink () - * @see SetDataRate () - * @see SetInterframeGap () - * @param ch a pointer to the channel to which this object is being attached. - */ - bool Attach(Ptr ch); - /** - * Attach a queue to the PointToPointNetDevice. - * - * The PointToPointNetDevice "owns" a queue. This queue is created by the - * PointToPointTopology object and implements a queueing method such as - * DropTail or RED. The PointToPointNetDevice assumes ownership of this - * queue and must delete it when the device is destroyed. - * - * @see PointToPointTopology::AddPointToPointLink () - * @see Queue - * @see DropTailQueue - * @param queue a pointer to the queue for which object is assuming - * ownership. - */ - void AddQueue(Ptr queue); - /** - * Receive a packet from a connected PointToPointChannel. - * - * The PointToPointNetDevice receives packets from its connected channel - * and forwards them up the protocol stack. This is the public method - * used by the channel to indicate that the last bit of a packet has - * arrived at the device. - * - * @see PointToPointChannel - * @param p a reference to the received packet - */ - void Receive (Packet& p); -protected: - virtual void DoDispose (void); - /** - * Get a copy of the attached Queue. - * - * This method is provided for any derived class that may need to get - * direct access to the underlying queue. - * - * @see PointToPointTopology - * @returns a pointer to the queue. - */ - Ptr GetQueue(void) const; - /** - * Get a copy of the attached Channel - * - * This method is provided for any derived class that may need to get - * direct access to the connected channel - * - * @see PointToPointChannel - * @returns a pointer to the channel - */ - virtual Ptr DoGetChannel(void) const; -private: - /** - * Send a Packet Down the Wire. - * - * The SendTo method is defined as the standard way that the level three - * protocol uses to tell a NetDevice to send a packet. SendTo is declared - * as abstract in the NetDevice class and we declare it here. - * - * @see NetDevice - * @param p a reference to the packet to send - * @param dest a reference to the MacAddress of the destination device - * @returns true if success, false on failure - */ - virtual bool SendTo (Packet& p, const MacAddress& dest); - /** - * Start Sending a Packet Down the Wire. - * - * The TransmitStart method is the method that is used internally in the - * PointToPointNetDevice to begin the process of sending a packet out on - * the channel. The corresponding method is called on the channel to let - * it know that the physical device this class represents has virually - * started sending signals. An event is scheduled for the time at which - * the bits have been completely transmitted. - * - * @see PointToPointChannel::TransmitStart () - * @see TransmitCompleteEvent () - * @param p a reference to the packet to send - * @returns true if success, false on failure - */ - bool TransmitStart (Packet &p); - /** - * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. - * - * The TransmitCompleteEvent method is used internally to finish the process - * of sending a packet out on the channel. During execution of this method - * the TransmitEnd method is called on the channel to let it know that the - * physical device this class represents has virually finished sending - * signals. The channel uses this event to begin its speed of light delay - * timer after which it notifies the Net Device at the other end of the - * link that the bits have arrived. During this method, the net device - * also schedules the TransmitReadyEvent at which time the transmitter - * becomes ready to send the next packet. - * - * @see PointToPointChannel::TransmitEnd () - * @see TransmitReadyEvent () - * @returns true if success, false on failure - */ - void TransmitCompleteEvent (void); - /** - * Cause the Transmitter to Become Ready to Send Another Packet. - * - * The TransmitReadyEvent method is used internally to re-enable the - * transmit machine of the net device. It is scheduled after a suitable - * interframe gap after the completion of the previous transmission. - * The queue is checked at this time, and if there is a packet waiting on - * the queue, the transmission process is begun. - * - * @see TransmitStart () - */ - void TransmitReadyEvent (void); - /** - * Create a Trace Resolver for events in the net device. - * - * @see class TraceResolver - */ - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); - virtual bool DoNeedsArp (void) const; - /** - * Enumeration of the states of the transmit machine of the net device. - */ - enum TxMachineState - { - READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY, /**< The transmitter is busy transmitting a packet */ - GAP /**< The transmitter is in the interframe gap time */ - }; - /** - * The state of the Net Device transmit state machine. - * @see TxMachineState - */ - TxMachineState m_txMachineState; - /** - * The data rate that the Net Device uses to simulate packet transmission - * timing. - * @see class DataRate - */ - DataRate m_bps; - /** - * The interframe gap that the Net Device uses to throttle packet - * transmission - * @see class Time - */ - Time m_tInterframeGap; - /** - * The PointToPointChannel to which this PointToPointNetDevice has been - * attached. - * @see class PointToPointChannel - */ - Ptr m_channel; - /** - * The Queue which this PointToPointNetDevice uses as a packet source. - * Management of this Queue has been delegated to the PointToPointNetDevice - * and it has the responsibility for deletion. - * @see class Queue - * @see class DropTailQueue - */ - Ptr m_queue; - /** - * The trace source for the packet reception events that the device can - * fire. - * - * @see class CallBackTraceSource - * @see class TraceResolver - */ - CallbackTraceSource m_rxTrace; -}; - -}; // namespace ns3 - -#endif // POINT_TO_POINT_NET_DEVICE_H - diff --git a/src/devices/p2p/p2p-topology.cc b/src/devices/p2p/p2p-topology.cc deleted file mode 100644 index 0b0ee003b..000000000 --- a/src/devices/p2p/p2p-topology.cc +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// - -// -// Topology helper for ns3. -// George F. Riley, Georgia Tech, Spring 2007 - -#include -#include "ns3/assert.h" -#include "ns3/debug.h" -#include "ns3/fatal-error.h" -#include "ns3/nstime.h" -#include "ns3/internet-node.h" -#include "ns3/ipv4-address.h" -#include "ns3/ipv4.h" -#include "ns3/queue.h" - -#include "p2p-channel.h" -#include "p2p-net-device.h" -#include "p2p-topology.h" - -namespace ns3 { - -Ptr -PointToPointTopology::AddPointToPointLink( - Ptr n1, - Ptr n2, - const DataRate& bps, - const Time& delay) -{ - Ptr channel = Create (bps, delay); - - Ptr net1 = Create (n1); - - Ptr q = Queue::CreateDefault (); - net1->AddQueue(q); - net1->Attach (channel); - - Ptr net2 = Create (n2); - - q = Queue::CreateDefault (); - net2->AddQueue(q); - net2->Attach (channel); - - return channel; -} - -void -PointToPointTopology::AddIpv4Addresses( - Ptr chan, - Ptr n1, const Ipv4Address& addr1, - Ptr n2, const Ipv4Address& addr2) -{ - - // Duplex link is assumed to be subnetted as a /30 - // May run this unnumbered in the future? - Ipv4Mask netmask("255.255.255.252"); - NS_ASSERT (netmask.IsMatch(addr1,addr2)); - - // The PointToPoint channel is used to find the relevant NetDevices - NS_ASSERT (chan->GetNDevices () == 2); - Ptr nd1 = chan->GetDevice (0); - Ptr nd2 = chan->GetDevice (1); - // Make sure that nd1 belongs to n1 and nd2 to n2 - if ( (nd1->GetNode ()->GetId () == n2->GetId () ) && - (nd2->GetNode ()->GetId () == n1->GetId () ) ) - { - std::swap(nd1, nd2); - } - NS_ASSERT (nd1->GetNode ()->GetId () == n1->GetId ()); - NS_ASSERT (nd2->GetNode ()->GetId () == n2->GetId ()); - - Ptr ip1 = n1->QueryInterface (Ipv4::iid); - uint32_t index1 = ip1->AddInterface (nd1); - - ip1->SetAddress (index1, addr1); - ip1->SetNetworkMask (index1, netmask); - ip1->SetUp (index1); - - Ptr ip2 = n2->QueryInterface (Ipv4::iid); - uint32_t index2 = ip2->AddInterface (nd2); - - ip2->SetAddress (index2, addr2); - ip2->SetNetworkMask (index2, netmask); - ip2->SetUp (index2); - -} - -void -PointToPointTopology::AddIpv4Routes ( - Ptr n1, Ptr n2, Ptr chan) -{ - // The PointToPoint channel is used to find the relevant NetDevices - NS_ASSERT (chan->GetNDevices () == 2); - Ptr nd1 = chan->GetDevice (0); - Ptr nd2 = chan->GetDevice (1); - - // Assert that n1 is the Node owning one of the two NetDevices - // and make sure that nd1 corresponds to it - if (nd1->GetNode ()->GetId () == n1->GetId ()) - { - ; // Do nothing - } - else if (nd2->GetNode ()->GetId () == n1->GetId ()) - { - std::swap(nd1, nd2); - } - else - { - NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel"); - } - - // Assert that n2 is the Node owning one of the two NetDevices - // and make sure that nd2 corresponds to it - if (nd2->GetNode ()->GetId () != n2->GetId ()) - { - NS_FATAL_ERROR("P2PTopo: Node does not contain an interface on Channel"); - } - - // Assert that both are Ipv4 nodes - Ptr ip1 = nd1->GetNode ()->QueryInterface (Ipv4::iid); - Ptr ip2 = nd2->GetNode ()->QueryInterface (Ipv4::iid); - NS_ASSERT(ip1 != 0 && ip2 != 0); - - // Get interface indexes for both nodes corresponding to the right channel - uint32_t index1 = 0; - bool found = false; - for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++) - { - if (ip1 ->GetNetDevice (i) == nd1) - { - index1 = i; - found = true; - } - } - NS_ASSERT(found); - - uint32_t index2 = 0; - found = false; - for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++) - { - if (ip2 ->GetNetDevice (i) == nd2) - { - index2 = i; - found = true; - } - } - NS_ASSERT(found); - - ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1); - ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); -} - -} // namespace ns3 - diff --git a/src/devices/p2p/p2p-topology.h b/src/devices/p2p/p2p-topology.h deleted file mode 100644 index c1f037380..000000000 --- a/src/devices/p2p/p2p-topology.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -// -// Copyright (c) 2006 Georgia Tech Research Corporation -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation; -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Author: George F. Riley -// -// Topology helper for ns3. -// George F. Riley, Georgia Tech, Spring 2007 -#ifndef __POINT_TO_POINT_TOPOLOGY_H__ -#define __POINT_TO_POINT_TOPOLOGY_H__ - -#include "ns3/ptr.h" - -// The topology class consists of only static methods thar are used to -// create the topology and data flows for an ns3 simulation - -namespace ns3 { - -class PointToPointChannel; -class Node; -class IPAddr; -class DataRate; -class Queue; - -/** - * \brief A helper class to create Topologies based on the - * ns3::PointToPointNetDevice and ns3::PointToPointChannel objects. - */ -class PointToPointTopology { -public: - /** - * \param n1 Node - * \param n2 Node - * \param dataRate Maximum transmission link rate - * \param delay one-way propagation delay - * \return Pointer to the underlying PointToPointChannel - * - * Add a full-duplex point-to-point link between two nodes - * and attach PointToPointNetDevices to the resulting - * PointToPointChannel. - */ - static Ptr AddPointToPointLink( - Ptr n1, Ptr n2, const DataRate& dataRate, const Time& delay); - - /** - * \param chan PointToPointChannel to use - * \param n1 Node - * \param addr1 Ipv4 Address for n1 - * \param n2 Node - * \param addr2 Ipv4 Address for n2 - * - * Add Ipv4Addresses to the Ipv4 interfaces associated with the - * two PointToPointNetDevices on the provided PointToPointChannel - */ - static void AddIpv4Addresses( - Ptr chan, - Ptr n1, const Ipv4Address& addr1, - Ptr n2, const Ipv4Address& addr2); - - /** - * \param channel PointToPointChannel to use - * \param n1 Node - * \param n2 Node - * - * For the given PointToPointChannel, for each Node, add an - * IPv4 host route to the IPv4 address of the peer node. - */ - static void AddIpv4Routes (Ptr n1, Ptr n2, Ptr channel); -}; - -} // namespace ns3 - -#endif - diff --git a/src/devices/p2p/wscript b/src/devices/p2p/wscript deleted file mode 100644 index c4c0f7952..000000000 --- a/src/devices/p2p/wscript +++ /dev/null @@ -1,24 +0,0 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - - -def configure(conf): - conf.env.append_value('NS3_MODULES', 'ns3-p2p') - - -def build(bld): - p2p = bld.create_obj('cpp', 'shlib') - p2p.name = 'ns3-p2p' - p2p.target = p2p.name - p2p.uselib_local = ['ns3-node'] - p2p.source = [ - 'p2p-net-device.cc', - 'p2p-channel.cc', - 'p2p-topology.cc', - ] - headers = bld.create_obj('ns3header') - headers.source = [ - 'p2p-net-device.h', - 'p2p-channel.h', - 'p2p-topology.h', - ] - From 29014acd87d3fe753a25794eb14241049351dc02 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 9 Aug 2007 13:38:04 +0200 Subject: [PATCH 238/278] add missing space in default PacketPrinter --- src/common/packet-printer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/packet-printer.cc b/src/common/packet-printer.cc index b0c55b359..5ee097e33 100644 --- a/src/common/packet-printer.cc +++ b/src/common/packet-printer.cc @@ -25,7 +25,7 @@ namespace ns3 { PacketPrinter::PacketPrinter () : m_forward (true), - m_separator ("") + m_separator (" ") {} void From aaa8a45658edaaebc9410f96d56c549b39be1b3c Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 9 Aug 2007 15:56:28 -0700 Subject: [PATCH 239/278] rename to csma --- examples/csma-one-subnet.cc | 166 ++++++++++++++++++ ...packet-socket.cc => csma-packet-socket.cc} | 28 +-- examples/wscript | 16 +- src/devices/csma-cd/wscript | 21 --- src/devices/{csma-cd => csma}/backoff.cc | 0 src/devices/{csma-cd => csma}/backoff.h | 0 .../csma-channel.cc} | 120 ++++++------- .../csma-cd-channel.h => csma/csma-channel.h} | 48 ++--- .../csma-ipv4-topology.cc} | 43 +++-- .../csma-ipv4-topology.h} | 60 +++---- .../csma-net-device.cc} | 132 +++++++------- .../csma-net-device.h} | 94 +++++----- .../csma-topology.cc} | 36 ++-- .../csma-topology.h} | 34 ++-- src/devices/csma/wscript | 19 ++ src/wscript | 2 +- 16 files changed, 492 insertions(+), 327 deletions(-) create mode 100644 examples/csma-one-subnet.cc rename examples/{csma-cd-packet-socket.cc => csma-packet-socket.cc} (81%) delete mode 100644 src/devices/csma-cd/wscript rename src/devices/{csma-cd => csma}/backoff.cc (100%) rename src/devices/{csma-cd => csma}/backoff.h (100%) rename src/devices/{csma-cd/csma-cd-channel.cc => csma/csma-channel.cc} (63%) rename src/devices/{csma-cd/csma-cd-channel.h => csma/csma-channel.h} (90%) rename src/devices/{csma-cd/csma-cd-ipv4-topology.cc => csma/csma-ipv4-topology.cc} (73%) rename src/devices/{csma-cd/csma-cd-ipv4-topology.h => csma/csma-ipv4-topology.h} (61%) rename src/devices/{csma-cd/csma-cd-net-device.cc => csma/csma-net-device.cc} (75%) rename src/devices/{csma-cd/csma-cd-net-device.h => csma/csma-net-device.h} (84%) rename src/devices/{csma-cd/csma-cd-topology.cc => csma/csma-topology.cc} (67%) rename src/devices/{csma-cd/csma-cd-topology.h => csma/csma-topology.h} (80%) create mode 100644 src/devices/csma/wscript diff --git a/examples/csma-one-subnet.cc b/examples/csma-one-subnet.cc new file mode 100644 index 000000000..dc1bd58c0 --- /dev/null +++ b/examples/csma-one-subnet.cc @@ -0,0 +1,166 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// Port of ns-2/tcl/ex/simple.tcl to ns-3 +// +// Network topology +// +// n0 n1 n2 n3 +// | | | | +// ===================== +// +// - CBR/UDP flows from n0 to n1, and from n3 to n0 +// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. +// (i.e., DataRate of 448,000 bps) +// - DropTail queues +// - Tracing of queues and packet receptions to file "csma-one-subnet.tr" + +#include +#include +#include +#include + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" +#include "ns3/debug.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/csma-channel.h" +#include "ns3/csma-net-device.h" +#include "ns3/csma-topology.h" +#include "ns3/csma-ipv4-topology.h" +#include "ns3/eui48-address.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/onoff-application.h" + + +using namespace ns3; + + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + DebugComponentEnable("CsmaNetDevice"); + DebugComponentEnable("Ipv4L3Protocol"); + DebugComponentEnable("NetDevice"); + DebugComponentEnable("Channel"); + DebugComponentEnable("CsmaChannel"); + DebugComponentEnable("PacketSocket"); +#endif + + // Set up some default values for the simulation. Use the Bind() + // technique to tell the system what subclass of Queue to use, + // and what the queue limit is + + // The below Bind command tells the queue factory which class to + // instantiate, when the queue factory is invoked in the topology code + DefaultValue::Bind ("Queue", "DropTailQueue"); + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + CsmaTopology::CreateCsmaChannel( + DataRate(5000000), MilliSeconds(2)); + + uint32_t n0ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0, + Eui48Address("10:54:23:54:23:50")); + uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0, + Eui48Address("10:54:23:54:23:51")); + uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel0, + Eui48Address("10:54:23:54:23:52")); + uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channel0, + Eui48Address("10:54:23:54:23:53")); + + // Later, we add IP addresses. + CsmaIpv4Topology::AddIpv4Address ( + n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address ( + n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address ( + n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address ( + n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0")); + + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + // from n0 to n1 + Ptr ooff = Create ( + n0, + InetSocketAddress ("10.1.1.2", 80), + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.0)); + ooff->Stop (Seconds(10.0)); + + // Create a similar flow from n3 to n0, starting at time 1.1 seconds + ooff = Create ( + n3, + InetSocketAddress ("10.1.1.1", 80), + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.1)); + ooff->Stop (Seconds(10.0)); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the csma-one-subnet.tr file + AsciiTrace asciitrace ("csma-one-subnet.tr"); + asciitrace.TraceAllNetDeviceRx (); + asciitrace.TraceAllQueues (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named + // simple-point-to-point.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("csma-one-subnet.pcap"); + pcaptrace.TraceAllIp (); + + Simulator::Run (); + + Simulator::Destroy (); +} diff --git a/examples/csma-cd-packet-socket.cc b/examples/csma-packet-socket.cc similarity index 81% rename from examples/csma-cd-packet-socket.cc rename to examples/csma-packet-socket.cc index ed1976645..9db207fbe 100644 --- a/examples/csma-cd-packet-socket.cc +++ b/examples/csma-packet-socket.cc @@ -26,7 +26,7 @@ // - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. // (i.e., DataRate of 448,000 bps) // - DropTail queues -// - Tracing of queues and packet receptions to file "csma-cd-one-subnet.tr" +// - Tracing of queues and packet receptions to file "csma-one-subnet.tr" #include #include @@ -46,8 +46,8 @@ #include "ns3/ascii-trace.h" #include "ns3/pcap-trace.h" #include "ns3/internet-node.h" -#include "ns3/csma-cd-channel.h" -#include "ns3/csma-cd-net-device.h" +#include "ns3/csma-channel.h" +#include "ns3/csma-net-device.h" #include "ns3/eui48-address.h" #include "ns3/packet-socket-address.h" #include "ns3/socket.h" @@ -56,10 +56,10 @@ using namespace ns3; -static Ptr -CreateCsmaCdDevice (Ptr node, Ptr channel) +static Ptr +CreateCsmaDevice (Ptr node, Ptr channel) { - Ptr device = Create (node); + Ptr device = Create (node); device->Attach (channel); Ptr queue = Queue::CreateDefault (); device->AddQueue (queue); @@ -78,14 +78,14 @@ int main (int argc, char *argv[]) Ptr n2 = Create (); Ptr n3 = Create (); - // create the shared medium used by all csma/cd devices. - Ptr channel = Create (DataRate(5000000), MilliSeconds(2)); + // create the shared medium used by all csma devices. + Ptr channel = Create (DataRate(5000000), MilliSeconds(2)); // use a helper function to connect our nodes to the shared channel. - Ptr n0If = CreateCsmaCdDevice (n0, channel); - Ptr n1If = CreateCsmaCdDevice (n1, channel); - Ptr n2If = CreateCsmaCdDevice (n2, channel); - Ptr n3If = CreateCsmaCdDevice (n3, channel); + Ptr n0If = CreateCsmaDevice (n0, channel); + Ptr n1If = CreateCsmaDevice (n1, channel); + Ptr n2If = CreateCsmaDevice (n2, channel); + Ptr n3If = CreateCsmaDevice (n3, channel); // create the address which identifies n1 from n0 @@ -125,8 +125,8 @@ int main (int argc, char *argv[]) ooff->Stop (Seconds(10.0)); // Configure tracing of all enqueue, dequeue, and NetDevice receive events - // Trace output will be sent to the csma-cd-packet-socket.tr file - AsciiTrace asciitrace ("csma-cd-packet-socket.tr"); + // Trace output will be sent to the csma-packet-socket.tr file + AsciiTrace asciitrace ("csma-packet-socket.tr"); asciitrace.TraceAllNetDeviceRx (); asciitrace.TraceAllQueues (); diff --git a/examples/wscript b/examples/wscript index 93e8f83d6..e7559756f 100644 --- a/examples/wscript +++ b/examples/wscript @@ -3,15 +3,17 @@ def build(bld): obj = bld.create_ns3_program('simple-global-routing', - ['point-to-point', 'internet-node', 'global-routing']) + ['point-to-point', 'internet-node', 'global-routing']) obj.source = 'simple-global-routing.cc' - obj = bld.create_ns3_program('simple-point-to-point', ['point-to-point', 'internet-node']) + obj = bld.create_ns3_program('simple-point-to-point', + ['point-to-point', 'internet-node']) obj.source = 'simple-point-to-point.cc' - obj = bld.create_ns3_program('csma-cd-one-subnet', ['csma-cd', 'internet-node']) - obj.source = 'csma-cd-one-subnet.cc' - - obj = bld.create_ns3_program('csma-cd-packet-socket', ['csma-cd', 'internet-node']) - obj.source = 'csma-cd-packet-socket.cc' + obj = bld.create_ns3_program('csma-one-subnet', + ['csma', 'internet-node']) + obj.source = 'csma-one-subnet.cc' + obj = bld.create_ns3_program('csma-packet-socket', + ['csma', 'internet-node']) + obj.source = 'csma-packet-socket.cc' diff --git a/src/devices/csma-cd/wscript b/src/devices/csma-cd/wscript deleted file mode 100644 index e82c41b58..000000000 --- a/src/devices/csma-cd/wscript +++ /dev/null @@ -1,21 +0,0 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - - -def build(bld): - obj = bld.create_ns3_module('csma-cd', ['node']) - obj.source = [ - 'backoff.cc', - 'csma-cd-net-device.cc', - 'csma-cd-channel.cc', - 'csma-cd-topology.cc', - 'csma-cd-ipv4-topology.cc', - ] - headers = bld.create_obj('ns3header') - headers.source = [ - 'backoff.h', - 'csma-cd-net-device.h', - 'csma-cd-channel.h', - 'csma-cd-topology.h', - 'csma-cd-ipv4-topology.h', - ] - diff --git a/src/devices/csma-cd/backoff.cc b/src/devices/csma/backoff.cc similarity index 100% rename from src/devices/csma-cd/backoff.cc rename to src/devices/csma/backoff.cc diff --git a/src/devices/csma-cd/backoff.h b/src/devices/csma/backoff.h similarity index 100% rename from src/devices/csma-cd/backoff.h rename to src/devices/csma/backoff.h diff --git a/src/devices/csma-cd/csma-cd-channel.cc b/src/devices/csma/csma-channel.cc similarity index 63% rename from src/devices/csma-cd/csma-cd-channel.cc rename to src/devices/csma/csma-channel.cc index 30c84deda..9ba42d854 100644 --- a/src/devices/csma-cd/csma-cd-channel.cc +++ b/src/devices/csma/csma-channel.cc @@ -19,60 +19,60 @@ * Author: Emmanuelle Laprise */ -#include "csma-cd-channel.h" -#include "csma-cd-net-device.h" +#include "csma-channel.h" +#include "csma-net-device.h" #include "ns3/packet.h" #include "ns3/simulator.h" #include "ns3/debug.h" -NS_DEBUG_COMPONENT_DEFINE ("CsmaCdChannel"); +NS_DEBUG_COMPONENT_DEFINE ("CsmaChannel"); namespace ns3 { -CsmaCdDeviceRec::CsmaCdDeviceRec() +CsmaDeviceRec::CsmaDeviceRec() { active = false; } -CsmaCdDeviceRec::CsmaCdDeviceRec(Ptr device) +CsmaDeviceRec::CsmaDeviceRec(Ptr device) { devicePtr = device; active = true; } bool -CsmaCdDeviceRec::IsActive() { +CsmaDeviceRec::IsActive() { return active; } // -// By default, you get a channel with the name "CsmaCd Channel" that +// By default, you get a channel with the name "Csma Channel" that // has an "infitely" fast transmission speed and zero delay. -CsmaCdChannel::CsmaCdChannel() +CsmaChannel::CsmaChannel() : - Channel ("CsmaCd Channel"), + Channel ("Csma Channel"), m_bps (DataRate(0xffffffff)), m_delay (Seconds(0)) { - NS_DEBUG("CsmaCdChannel::CsmaCdChannel ()"); + NS_DEBUG("CsmaChannel::CsmaChannel ()"); Init(); } -CsmaCdChannel::CsmaCdChannel( +CsmaChannel::CsmaChannel( const DataRate& bps, const Time& delay) : - Channel ("CsmaCd Channel"), + Channel ("Csma Channel"), m_bps (bps), m_delay (delay) { - NS_DEBUG("CsmaCdChannel::CsmaCdChannel (" << Channel::GetName() + NS_DEBUG("CsmaChannel::CsmaChannel (" << Channel::GetName() << ", " << bps.GetBitRate() << ", " << delay << ")"); Init(); } -CsmaCdChannel::CsmaCdChannel( +CsmaChannel::CsmaChannel( const std::string& name, const DataRate& bps, const Time& delay) @@ -81,35 +81,35 @@ CsmaCdChannel::CsmaCdChannel( m_bps (bps), m_delay (delay) { - NS_DEBUG("CsmaCdChannel::CsmaCdChannel (" << name << ", " << + NS_DEBUG("CsmaChannel::CsmaChannel (" << name << ", " << bps.GetBitRate() << ", " << delay << ")"); Init(); } -void CsmaCdChannel::Init() { +void CsmaChannel::Init() { m_state = IDLE; m_deviceList.clear(); } int32_t -CsmaCdChannel::Attach(Ptr device) +CsmaChannel::Attach(Ptr device) { - NS_DEBUG("CsmaCdChannel::Attach (" << device << ")"); + NS_DEBUG("CsmaChannel::Attach (" << device << ")"); NS_ASSERT(device != 0); - CsmaCdDeviceRec rec(device); + CsmaDeviceRec rec(device); m_deviceList.push_back(rec); return (m_deviceList.size() - 1); } bool -CsmaCdChannel::Reattach(Ptr device) +CsmaChannel::Reattach(Ptr device) { - NS_DEBUG("CsmaCdChannel::Reattach (" << device << ")"); + NS_DEBUG("CsmaChannel::Reattach (" << device << ")"); NS_ASSERT(device != 0); - std::vector::iterator it; + std::vector::iterator it; for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) { if (it->devicePtr == device) @@ -129,9 +129,9 @@ CsmaCdChannel::Reattach(Ptr device) } bool -CsmaCdChannel::Reattach(uint32_t deviceId) +CsmaChannel::Reattach(uint32_t deviceId) { - NS_DEBUG("CsmaCdChannel::Reattach (" << deviceId << ")"); + NS_DEBUG("CsmaChannel::Reattach (" << deviceId << ")"); if (deviceId < m_deviceList.size()) { return false; @@ -149,15 +149,15 @@ CsmaCdChannel::Reattach(uint32_t deviceId) } bool -CsmaCdChannel::Detach(uint32_t deviceId) +CsmaChannel::Detach(uint32_t deviceId) { - NS_DEBUG("CsmaCdChannel::Detach (" << deviceId << ")"); + NS_DEBUG("CsmaChannel::Detach (" << deviceId << ")"); if (deviceId < m_deviceList.size()) { if (!m_deviceList[deviceId].active) { - NS_DEBUG("CsmaCdChannel::Detach Device is already detached (" + NS_DEBUG("CsmaChannel::Detach Device is already detached (" << deviceId << ")"); return false; } @@ -165,7 +165,7 @@ CsmaCdChannel::Detach(uint32_t deviceId) m_deviceList[deviceId].active = false; if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId)) { - NS_DEBUG("CsmaCdChannel::Detach Device is currently" + NS_DEBUG("CsmaChannel::Detach Device is currently" << "transmitting (" << deviceId << ")"); // Here we will need to place a warning in the packet } @@ -179,12 +179,12 @@ CsmaCdChannel::Detach(uint32_t deviceId) } bool -CsmaCdChannel::Detach(Ptr device) +CsmaChannel::Detach(Ptr device) { - NS_DEBUG("CsmaCdChannel::Detach (" << device << ")"); + NS_DEBUG("CsmaChannel::Detach (" << device << ")"); NS_ASSERT(device != 0); - std::vector::iterator it; + std::vector::iterator it; for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) { if ((it->devicePtr == device) && (it->active)) @@ -197,27 +197,27 @@ CsmaCdChannel::Detach(Ptr device) } bool -CsmaCdChannel::TransmitStart(Packet& p, uint32_t srcId) +CsmaChannel::TransmitStart(Packet& p, uint32_t srcId) { - NS_DEBUG ("CsmaCdChannel::TransmitStart (" << &p << ", " << srcId + NS_DEBUG ("CsmaChannel::TransmitStart (" << &p << ", " << srcId << ")"); - NS_DEBUG ("CsmaCdChannel::TransmitStart (): UID is " << + NS_DEBUG ("CsmaChannel::TransmitStart (): UID is " << p.GetUid () << ")"); if (m_state != IDLE) { - NS_DEBUG("CsmaCdChannel::TransmitStart (): state is not IDLE"); + NS_DEBUG("CsmaChannel::TransmitStart (): state is not IDLE"); return false; } if (!IsActive(srcId)) { - NS_DEBUG("CsmaCdChannel::TransmitStart (): ERROR: Seclected " + NS_DEBUG("CsmaChannel::TransmitStart (): ERROR: Seclected " << "source is not currently attached to network"); return false; } - NS_DEBUG("CsmaCdChannel::TransmitStart (): switch to TRANSMITTING"); + NS_DEBUG("CsmaChannel::TransmitStart (): switch to TRANSMITTING"); m_currentPkt = p; m_currentSrc = srcId; m_state = TRANSMITTING; @@ -225,17 +225,17 @@ CsmaCdChannel::TransmitStart(Packet& p, uint32_t srcId) } bool -CsmaCdChannel::IsActive(uint32_t deviceId) +CsmaChannel::IsActive(uint32_t deviceId) { return (m_deviceList[deviceId].active); } bool -CsmaCdChannel::TransmitEnd() +CsmaChannel::TransmitEnd() { - NS_DEBUG("CsmaCdChannel::TransmitEnd (" << &m_currentPkt << ", " + NS_DEBUG("CsmaChannel::TransmitEnd (" << &m_currentPkt << ", " << m_currentSrc << ")"); - NS_DEBUG("CsmaCdChannel::TransmitEnd (): UID is " << + NS_DEBUG("CsmaChannel::TransmitEnd (): UID is " << m_currentPkt.GetUid () << ")"); NS_ASSERT(m_state == TRANSMITTING); @@ -244,33 +244,33 @@ CsmaCdChannel::TransmitEnd() bool retVal = true; if (!IsActive(m_currentSrc)) { - NS_DEBUG("CsmaCdChannel::TransmitEnd (): ERROR: Seclected source " + NS_DEBUG("CsmaChannel::TransmitEnd (): ERROR: Seclected source " << "was detached before the end of the transmission"); retVal = false; } - NS_DEBUG ("CsmaCdChannel::TransmitEnd (): Schedule event in " << + NS_DEBUG ("CsmaChannel::TransmitEnd (): Schedule event in " << m_delay.GetSeconds () << "sec"); Simulator::Schedule (m_delay, - &CsmaCdChannel::PropagationCompleteEvent, + &CsmaChannel::PropagationCompleteEvent, this); return retVal; } void -CsmaCdChannel::PropagationCompleteEvent() +CsmaChannel::PropagationCompleteEvent() { - NS_DEBUG("CsmaCdChannel::PropagationCompleteEvent (" + NS_DEBUG("CsmaChannel::PropagationCompleteEvent (" << &m_currentPkt << ")"); - NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): UID is " << + NS_DEBUG ("CsmaChannel::PropagationCompleteEvent (): UID is " << m_currentPkt.GetUid () << ")"); NS_ASSERT(m_state == PROPAGATING); - NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): Receive"); + NS_DEBUG ("CsmaChannel::PropagationCompleteEvent (): Receive"); - std::vector::iterator it; + std::vector::iterator it; for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) { if (it->IsActive()) @@ -283,10 +283,10 @@ CsmaCdChannel::PropagationCompleteEvent() uint32_t -CsmaCdChannel::GetNumActDevices (void) +CsmaChannel::GetNumActDevices (void) { int numActDevices = 0; - std::vector::iterator it; + std::vector::iterator it; for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) { if (it->active) @@ -300,24 +300,24 @@ CsmaCdChannel::GetNumActDevices (void) // This is not the number of active devices. This is the total number // of devices even if some were detached after. uint32_t -CsmaCdChannel::GetNDevices (void) const +CsmaChannel::GetNDevices (void) const { return (m_deviceList.size()); } Ptr -CsmaCdChannel::GetDevice (uint32_t i) const +CsmaChannel::GetDevice (uint32_t i) const { - Ptr< CsmaCdNetDevice > netDevice; + Ptr< CsmaNetDevice > netDevice; netDevice = m_deviceList[i].devicePtr; return netDevice; } int32_t -CsmaCdChannel::GetDeviceNum (Ptr device) +CsmaChannel::GetDeviceNum (Ptr device) { - std::vector::iterator it; + std::vector::iterator it; int i = 0; for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) { @@ -338,7 +338,7 @@ CsmaCdChannel::GetDeviceNum (Ptr device) } bool -CsmaCdChannel::IsBusy (void) +CsmaChannel::IsBusy (void) { if (m_state == IDLE) { @@ -351,19 +351,19 @@ CsmaCdChannel::IsBusy (void) } DataRate -CsmaCdChannel::GetDataRate (void) +CsmaChannel::GetDataRate (void) { return m_bps; } Time -CsmaCdChannel::GetDelay (void) +CsmaChannel::GetDelay (void) { return m_delay; } WireState -CsmaCdChannel::GetState(void) +CsmaChannel::GetState(void) { return m_state; } diff --git a/src/devices/csma-cd/csma-cd-channel.h b/src/devices/csma/csma-channel.h similarity index 90% rename from src/devices/csma-cd/csma-cd-channel.h rename to src/devices/csma/csma-channel.h index fafb5b6ad..0efabf77e 100644 --- a/src/devices/csma-cd/csma-cd-channel.h +++ b/src/devices/csma/csma-channel.h @@ -18,8 +18,8 @@ * Author: Emmanuelle Laprise */ -#ifndef CSMA_CD_CHANNEL_H -#define CSMA_CD_CHANNEL_H +#ifndef CSMA_CHANNEL_H +#define CSMA_CHANNEL_H #include "ns3/channel.h" #include "ns3/ptr.h" @@ -29,21 +29,21 @@ namespace ns3 { -class CsmaCdNetDevice; +class CsmaNetDevice; /** - * \brief CsmaCdNetDevice Record + * \brief CsmaNetDevice Record * * Stores the information related to each net device that is * connected to the channel. */ - class CsmaCdDeviceRec { + class CsmaDeviceRec { public: - Ptr< CsmaCdNetDevice > devicePtr; /// Pointer to the net device + Ptr< CsmaNetDevice > devicePtr; /// Pointer to the net device bool active; /// Is net device enabled to TX/RX - CsmaCdDeviceRec(); - CsmaCdDeviceRec(Ptr< CsmaCdNetDevice > device); + CsmaDeviceRec(); + CsmaDeviceRec(Ptr< CsmaNetDevice > device); /* * \return If the net device pointed to by the devicePtr is active * and ready to RX/TX. @@ -65,9 +65,9 @@ class CsmaCdNetDevice; }; /** - * \brief CsmaCd Channel. + * \brief Csma Channel. * - * This class represents a simple Csma/Cd channel that can be used + * This class represents a simple Csma channel that can be used * when many nodes are connected to one wire. It uses a single busy * flag to indicate if the channel is currently in use. It does not * take into account the distances between stations or the speed of @@ -84,32 +84,32 @@ class CsmaCdNetDevice; * packet to the channel is really connected to this channel * */ -class CsmaCdChannel : public Channel { +class CsmaChannel : public Channel { public: /** - * \brief Create a CsmaCdChannel + * \brief Create a CsmaChannel * - * By default, you get a channel with the name "CsmaCd Channel" that + * By default, you get a channel with the name "Csma Channel" that * has an "infitely" fast transmission speed and zero delay. */ - CsmaCdChannel (); + CsmaChannel (); /** - * \brief Create a CsmaCdChannel + * \brief Create a CsmaChannel * * \param bps The bitrate of the channel * \param delay Transmission delay through the channel */ - CsmaCdChannel (const DataRate& bps, const Time& delay); + CsmaChannel (const DataRate& bps, const Time& delay); /** - * \brief Create a CsmaCdChannel + * \brief Create a CsmaChannel * * \param name the name of the channel for identification purposes * \param bps The bitrate of the channel * \param delay Transmission delay through the channel */ - CsmaCdChannel (const std::string& name, + CsmaChannel (const std::string& name, const DataRate& bps, const Time& delay); /** @@ -118,7 +118,7 @@ public: * \param device Device pointer to the netdevice to attach to the channel * \return The assigned device number */ - int32_t Attach (Ptr device); + int32_t Attach (Ptr device); /** * \brief Detach a given netdevice from this channel * @@ -130,7 +130,7 @@ public: * false if the device is not currently connected to the channel or * can't be found. */ - bool Detach (Ptr device); + bool Detach (Ptr device); /** * \brief Detach a given netdevice from this channel * @@ -170,7 +170,7 @@ public: * channel, false if the device is currently connected to the * channel or can't be found. */ - bool Reattach(Ptr device); + bool Reattach(Ptr device); /** * \brief Start transmitting a packet over the channel * @@ -216,7 +216,7 @@ public: * \param device Device pointer to the netdevice for which the device * number is needed */ - int32_t GetDeviceNum (Ptr device); + int32_t GetDeviceNum (Ptr device); /** * \return Returns the state of the channel (IDLE -- free, * TRANSMITTING -- busy, PROPAGATING - busy ) @@ -278,7 +278,7 @@ private: * whole list does not have to be searched when making sure that a * source is attached to a channel when it is transmitting data. */ - std::vector< CsmaCdDeviceRec > m_deviceList; + std::vector< CsmaDeviceRec > m_deviceList; /** * Packet that is currently being transmitted on the channel (or last * packet to have been transmitted on the channel if the channel is @@ -304,4 +304,4 @@ private: } // namespace ns3 -#endif /* CSMA_CD_CHANNEL_H */ +#endif /* CSMA_CHANNEL_H */ diff --git a/src/devices/csma-cd/csma-cd-ipv4-topology.cc b/src/devices/csma/csma-ipv4-topology.cc similarity index 73% rename from src/devices/csma-cd/csma-cd-ipv4-topology.cc rename to src/devices/csma/csma-ipv4-topology.cc index 923f89dc4..02cd0e487 100644 --- a/src/devices/csma-cd/csma-cd-ipv4-topology.cc +++ b/src/devices/csma/csma-ipv4-topology.cc @@ -28,23 +28,22 @@ #include "ns3/ipv4.h" #include "ns3/queue.h" -#include "csma-cd-channel.h" -#include "csma-cd-net-device.h" -#include "csma-cd-ipv4-topology.h" +#include "csma-channel.h" +#include "csma-net-device.h" +#include "csma-ipv4-topology.h" namespace ns3 { - uint32_t -CsmaCdIpv4Topology::AddIpv4CsmaCdNode(Ptr n1, - Ptr ch, +CsmaIpv4Topology::AddIpv4CsmaNode(Ptr n1, + Ptr ch, Eui48Address addr) { Ptr q = Queue::CreateDefault (); // assume full-duplex - Ptr nd0 = Create (n1, addr, - ns3::CsmaCdNetDevice::IP_ARP, + Ptr nd0 = Create (n1, addr, + ns3::CsmaNetDevice::IP_ARP, true, true); nd0->AddQueue(q); nd0->Attach (ch); @@ -53,47 +52,47 @@ CsmaCdIpv4Topology::AddIpv4CsmaCdNode(Ptr n1, void -CsmaCdIpv4Topology::AddIpv4LlcCsmaCdNode(Ptr n1, - Ptr ch, +CsmaIpv4Topology::AddIpv4LlcCsmaNode(Ptr n1, + Ptr ch, Eui48Address addr) { Ptr q = Queue::CreateDefault (); - Ptr nd0 = Create (n1, addr, - ns3::CsmaCdNetDevice::LLC, + Ptr nd0 = Create (n1, addr, + ns3::CsmaNetDevice::LLC, true, false); nd0->AddQueue(q); nd0->Attach (ch); - Ptr nd1 = Create (n1, addr, - ns3::CsmaCdNetDevice::LLC, + Ptr nd1 = Create (n1, addr, + ns3::CsmaNetDevice::LLC, false, true); nd1->AddQueue(q); nd1->Attach (ch); } void -CsmaCdIpv4Topology::AddIpv4RawCsmaCdNode(Ptr n1, - Ptr ch, +CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr n1, + Ptr ch, Eui48Address addr) { Ptr q = Queue::CreateDefault (); - Ptr nd0 = Create (n1, addr, - ns3::CsmaCdNetDevice::RAW, + Ptr nd0 = Create (n1, addr, + ns3::CsmaNetDevice::RAW, true, false); nd0->AddQueue(q); nd0->Attach (ch); - Ptr nd1 = Create (n1, addr, - ns3::CsmaCdNetDevice::RAW, + Ptr nd1 = Create (n1, addr, + ns3::CsmaNetDevice::RAW, false, true); nd1->AddQueue(q); nd1->Attach (ch); } void -CsmaCdIpv4Topology::AddIpv4Address(Ptr n1, +CsmaIpv4Topology::AddIpv4Address(Ptr n1, int ndNum, const Ipv4Address& addr1, const Ipv4Mask& netmask1) @@ -115,7 +114,7 @@ CsmaCdIpv4Topology::AddIpv4Address(Ptr n1, } void -CsmaCdIpv4Topology::AddIpv4Routes ( +CsmaIpv4Topology::AddIpv4Routes ( Ptr nd1, Ptr nd2) { // Assert that both are Ipv4 nodes diff --git a/src/devices/csma-cd/csma-cd-ipv4-topology.h b/src/devices/csma/csma-ipv4-topology.h similarity index 61% rename from src/devices/csma-cd/csma-cd-ipv4-topology.h rename to src/devices/csma/csma-ipv4-topology.h index 84a769880..37f546118 100644 --- a/src/devices/csma-cd/csma-cd-ipv4-topology.h +++ b/src/devices/csma/csma-ipv4-topology.h @@ -18,22 +18,22 @@ // Author: Emmanuelle Laprise // -#ifndef __CSMA_CD_IPV4_TOPOLOGY_H__ -#define __CSMA_CD_IPV4_TOPOLOGY_H__ +#ifndef __CSMA_IPV4_TOPOLOGY_H__ +#define __CSMA_IPV4_TOPOLOGY_H__ #include "ns3/ptr.h" #include "ns3/ipv4-address.h" #include "ns3/ipv4.h" #include "ns3/ipv4-route.h" #include "ns3/internet-node.h" -#include "ns3/csma-cd-net-device.h" +#include "ns3/csma-net-device.h" // The topology class consists of only static methods thar are used to // create the topology and data flows for an ns3 simulation namespace ns3 { -class CsmaCdIpv4Channel; +class CsmaIpv4Channel; class Node; class IPAddr; class DataRate; @@ -41,54 +41,54 @@ class Queue; /** * \brief A helper class to create Topologies based on the - * InternetNodes and CsmaCdChannels. Either the - * SimpleCsmaCdNetDevice or the LLCCsmaCdNetDevice can be used + * InternetNodes and CsmaChannels. Either the + * SimpleCsmaNetDevice or the LLCCsmaNetDevice can be used * when constructing these topologies. */ -class CsmaCdIpv4Topology { +class CsmaIpv4Topology { public: /** - * \param n1 Node to be attached to the Csma/Cd channel - * \param ch CsmaCdChannel to which node n1 should be attached + * \param n1 Node to be attached to the Csma channel + * \param ch CsmaChannel to which node n1 should be attached * \param addr Mac address of the node * - * Add a Csma/Cd node to a Csma/Cd channel. This function adds - * a EthernetCsmaCdNetDevice to the nodes so that they can - * connect to a CsmaCdChannel. This means that Ethernet headers + * Add a Csma node to a Csma channel. This function adds + * a EthernetCsmaNetDevice to the nodes so that they can + * connect to a CsmaChannel. This means that Ethernet headers * and trailers will be added to the packet before sending out on * the net device. * * \return ifIndex of the device */ - static uint32_t AddIpv4CsmaCdNode( Ptr n1, - Ptr ch, + static uint32_t AddIpv4CsmaNode( Ptr n1, + Ptr ch, Eui48Address addr); /** - * \param n1 Node to be attached to the Csma/Cd channel - * \param ch CsmaCdChannel to which node n1 should be attached + * \param n1 Node to be attached to the Csma channel + * \param ch CsmaChannel to which node n1 should be attached * \param addr Mac address of the node * - * Add a Csma/Cd node to a Csma/Cd channel. This function adds - * a RawCsmaCdNetDevice to the nodes so that they can connect - * to a CsmaCdChannel. + * Add a Csma node to a Csma channel. This function adds + * a RawCsmaNetDevice to the nodes so that they can connect + * to a CsmaChannel. */ - static void AddIpv4RawCsmaCdNode( Ptr n1, - Ptr ch, + static void AddIpv4RawCsmaNode( Ptr n1, + Ptr ch, Eui48Address addr); /** - * \param n1 Node to be attached to the Csma/Cd channel - * \param ch CsmaCdChannel to which node n1 should be attached + * \param n1 Node to be attached to the Csma channel + * \param ch CsmaChannel to which node n1 should be attached * \param addr Mac address of the node * - * Add a Csma/Cd node to a Csma/Cd channel. This function adds - * a LlcCsmaCdNetDevice to the nodes so that they can connect - * to a CsmaCdChannel. + * Add a Csma node to a Csma channel. This function adds + * a LlcCsmaNetDevice to the nodes so that they can connect + * to a CsmaChannel. */ - static void AddIpv4LlcCsmaCdNode( Ptr n1, - Ptr ch, + static void AddIpv4LlcCsmaNode( Ptr n1, + Ptr ch, Eui48Address addr); @@ -100,8 +100,8 @@ public: * \param network network mask for ndNum of node n1 * * Add an Ipv4Address to the Ipv4 interface associated with the - * ndNum CsmaCdIpv4NetDevices on the provided - * CsmaCdIpv4Channel + * ndNum CsmaIpv4NetDevices on the provided + * CsmaIpv4Channel */ static void AddIpv4Address(Ptr n1, int ndNum, const Ipv4Address& addr1, diff --git a/src/devices/csma-cd/csma-cd-net-device.cc b/src/devices/csma/csma-net-device.cc similarity index 75% rename from src/devices/csma-cd/csma-cd-net-device.cc rename to src/devices/csma/csma-net-device.cc index d5dfc8501..e3346c3bb 100644 --- a/src/devices/csma-cd/csma-cd-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -25,24 +25,24 @@ #include "ns3/queue.h" #include "ns3/simulator.h" #include "ns3/composite-trace-resolver.h" -#include "csma-cd-net-device.h" -#include "csma-cd-channel.h" +#include "csma-net-device.h" +#include "csma-channel.h" #include "ns3/ethernet-header.h" #include "ns3/ethernet-trailer.h" #include "ns3/llc-snap-header.h" -NS_DEBUG_COMPONENT_DEFINE ("CsmaCdNetDevice"); +NS_DEBUG_COMPONENT_DEFINE ("CsmaNetDevice"); namespace ns3 { -CsmaCdTraceType::CsmaCdTraceType (enum Type type) +CsmaTraceType::CsmaTraceType (enum Type type) : m_type (type) {} -CsmaCdTraceType::CsmaCdTraceType () +CsmaTraceType::CsmaTraceType () : m_type (RX) {} void -CsmaCdTraceType::Print (std::ostream &os) const +CsmaTraceType::Print (std::ostream &os) const { switch (m_type) { case RX: @@ -54,60 +54,60 @@ CsmaCdTraceType::Print (std::ostream &os) const } } uint16_t -CsmaCdTraceType::GetUid (void) +CsmaTraceType::GetUid (void) { - static uint16_t uid = AllocateUid ("CsmaCdTraceType"); + static uint16_t uid = AllocateUid ("CsmaTraceType"); return uid; } -CsmaCdNetDevice::CsmaCdNetDevice (Ptr node) +CsmaNetDevice::CsmaNetDevice (Ptr node) : NetDevice (node, Eui48Address::Allocate ()), m_bps (DataRate (0xffffffff)) { - NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); + NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")"); m_encapMode = IP_ARP; Init(true, true); } -CsmaCdNetDevice::CsmaCdNetDevice (Ptr node, Eui48Address addr, - CsmaCdEncapsulationMode encapMode) +CsmaNetDevice::CsmaNetDevice (Ptr node, Eui48Address addr, + CsmaEncapsulationMode encapMode) : NetDevice(node, addr), m_bps (DataRate (0xffffffff)) { - NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); + NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")"); m_encapMode = encapMode; Init(true, true); } -CsmaCdNetDevice::CsmaCdNetDevice (Ptr node, Eui48Address addr, - CsmaCdEncapsulationMode encapMode, +CsmaNetDevice::CsmaNetDevice (Ptr node, Eui48Address addr, + CsmaEncapsulationMode encapMode, bool sendEnable, bool receiveEnable) : NetDevice(node, addr), m_bps (DataRate (0xffffffff)) { - NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")"); + NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")"); m_encapMode = encapMode; Init(sendEnable, receiveEnable); } -CsmaCdNetDevice::~CsmaCdNetDevice() +CsmaNetDevice::~CsmaNetDevice() { - NS_DEBUG ("CsmaCdNetDevice::~CsmaCdNetDevice ()"); + NS_DEBUG ("CsmaNetDevice::~CsmaNetDevice ()"); m_queue = 0; } void -CsmaCdNetDevice::DoDispose () +CsmaNetDevice::DoDispose () { m_channel = 0; NetDevice::DoDispose (); } // -// Assignment operator for CsmaCdNetDevice. +// Assignment operator for CsmaNetDevice. // // This uses the non-obvious trick of taking the source net device passed by // value instead of by reference. This causes the copy constructor to be @@ -115,16 +115,16 @@ CsmaCdNetDevice::DoDispose () // here is to return the newly constructed net device. // /* -CsmaCdNetDevice& -CsmaCdNetDevice::operator= (const CsmaCdNetDevice nd) +CsmaNetDevice& +CsmaNetDevice::operator= (const CsmaNetDevice nd) { - NS_DEBUG ("CsmaCdNetDevice::operator= (" << &nd << ")"); + NS_DEBUG ("CsmaNetDevice::operator= (" << &nd << ")"); return *this; } */ void -CsmaCdNetDevice::Init(bool sendEnable, bool receiveEnable) +CsmaNetDevice::Init(bool sendEnable, bool receiveEnable) { m_txMachineState = READY; m_tInterframeGap = Seconds(0); @@ -140,42 +140,42 @@ CsmaCdNetDevice::Init(bool sendEnable, bool receiveEnable) } void -CsmaCdNetDevice::SetSendEnable (bool sendEnable) +CsmaNetDevice::SetSendEnable (bool sendEnable) { m_sendEnable = sendEnable; } void -CsmaCdNetDevice::SetReceiveEnable (bool receiveEnable) +CsmaNetDevice::SetReceiveEnable (bool receiveEnable) { m_receiveEnable = receiveEnable; } bool -CsmaCdNetDevice::IsSendEnabled (void) +CsmaNetDevice::IsSendEnabled (void) { return (m_sendEnable); } bool -CsmaCdNetDevice::IsReceiveEnabled (void) +CsmaNetDevice::IsReceiveEnabled (void) { return (m_receiveEnable); } void -CsmaCdNetDevice::SetDataRate (DataRate bps) +CsmaNetDevice::SetDataRate (DataRate bps) { m_bps = bps; } void -CsmaCdNetDevice::SetInterframeGap (Time t) +CsmaNetDevice::SetInterframeGap (Time t) { m_tInterframeGap = t; } void -CsmaCdNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, +CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots, uint32_t ceiling, uint32_t maxRetries) { @@ -186,7 +186,7 @@ CsmaCdNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, m_backoff.m_maxRetries = maxRetries; } void -CsmaCdNetDevice::AddHeader (Packet& p, Eui48Address dest, +CsmaNetDevice::AddHeader (Packet& p, Eui48Address dest, uint16_t protocolNumber) { if (m_encapMode == RAW) @@ -223,7 +223,7 @@ CsmaCdNetDevice::AddHeader (Packet& p, Eui48Address dest, p.AddTrailer(trailer); } bool -CsmaCdNetDevice::ProcessHeader (Packet& p, uint16_t & param) +CsmaNetDevice::ProcessHeader (Packet& p, uint16_t & param) { if (m_encapMode == RAW) { @@ -261,7 +261,7 @@ CsmaCdNetDevice::ProcessHeader (Packet& p, uint16_t & param) } bool -CsmaCdNetDevice::DoNeedsArp (void) const +CsmaNetDevice::DoNeedsArp (void) const { if ((m_encapMode == IP_ARP) || (m_encapMode == LLC)) { @@ -274,10 +274,10 @@ CsmaCdNetDevice::DoNeedsArp (void) const } bool -CsmaCdNetDevice::SendTo (Packet& p, const Address& dest, uint16_t protocolNumber) +CsmaNetDevice::SendTo (Packet& p, const Address& dest, uint16_t protocolNumber) { - NS_DEBUG ("CsmaCdNetDevice::SendTo (" << &p << ")"); - NS_DEBUG ("CsmaCdNetDevice::SendTo (): UID is " << p.GetUid () << ")"); + NS_DEBUG ("CsmaNetDevice::SendTo (" << &p << ")"); + NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << p.GetUid () << ")"); NS_ASSERT (IsLinkUp ()); @@ -308,10 +308,10 @@ CsmaCdNetDevice::SendTo (Packet& p, const Address& dest, uint16_t protocolNumber } void -CsmaCdNetDevice::TransmitStart () +CsmaNetDevice::TransmitStart () { - NS_DEBUG ("CsmaCdNetDevice::TransmitStart (" << &m_currentPkt << ")"); - NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): UID is " + NS_DEBUG ("CsmaNetDevice::TransmitStart (" << &m_currentPkt << ")"); + NS_DEBUG ("CsmaNetDevice::TransmitStart (): UID is " << m_currentPkt.GetUid () << ")"); // // This function is called to start the process of transmitting a packet. @@ -339,12 +339,12 @@ CsmaCdNetDevice::TransmitStart () m_backoff.IncrNumRetries(); Time backoffTime = m_backoff.GetBackoffTime(); - NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " + NS_DEBUG ("CsmaNetDevice::TransmitStart (): " << "Channel busy, backing off for " << backoffTime.GetSeconds () << "sec"); Simulator::Schedule (backoffTime, - &CsmaCdNetDevice::TransmitStart, + &CsmaNetDevice::TransmitStart, this); } } @@ -354,16 +354,16 @@ CsmaCdNetDevice::TransmitStart () m_txMachineState = BUSY; Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize())); - NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " << + NS_DEBUG ("CsmaNetDevice::TransmitStart (): " << "Schedule TransmitCompleteEvent in " << tEvent.GetSeconds () << "sec"); Simulator::Schedule (tEvent, - &CsmaCdNetDevice::TransmitCompleteEvent, + &CsmaNetDevice::TransmitCompleteEvent, this); if (!m_channel->TransmitStart (m_currentPkt, m_deviceId)) { - NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " << + NS_DEBUG ("CsmaNetDevice::TransmitStart (): " << "Channel transmit start did not work at " << tEvent.GetSeconds () << "sec"); m_txMachineState = READY; @@ -378,11 +378,11 @@ CsmaCdNetDevice::TransmitStart () void -CsmaCdNetDevice::TransmitAbort (void) +CsmaNetDevice::TransmitAbort (void) { - NS_DEBUG ("CsmaCdNetDevice::TransmitAbort ()"); + NS_DEBUG ("CsmaNetDevice::TransmitAbort ()"); - NS_DEBUG ("CsmaCdNetDevice::TransmitAbort (): Pkt UID is " << + NS_DEBUG ("CsmaNetDevice::TransmitAbort (): Pkt UID is " << m_currentPkt.GetUid () << ")"); // Try to transmit a new packet @@ -395,9 +395,9 @@ CsmaCdNetDevice::TransmitAbort (void) } void -CsmaCdNetDevice::TransmitCompleteEvent (void) +CsmaNetDevice::TransmitCompleteEvent (void) { - NS_DEBUG ("CsmaCdNetDevice::TransmitCompleteEvent ()"); + NS_DEBUG ("CsmaNetDevice::TransmitCompleteEvent ()"); // // This function is called to finish the process of transmitting a packet. // We need to tell the channel that we've stopped wiggling the wire and @@ -409,24 +409,24 @@ CsmaCdNetDevice::TransmitCompleteEvent (void) NS_ASSERT(m_channel->GetState() == TRANSMITTING); m_txMachineState = GAP; - NS_DEBUG ("CsmaCdNetDevice::TransmitCompleteEvent (): Pkt UID is " << + NS_DEBUG ("CsmaNetDevice::TransmitCompleteEvent (): Pkt UID is " << m_currentPkt.GetUid () << ")"); m_channel->TransmitEnd (); NS_DEBUG ( - "CsmaCdNetDevice::TransmitCompleteEvent (): " << + "CsmaNetDevice::TransmitCompleteEvent (): " << "Schedule TransmitReadyEvent in " << m_tInterframeGap.GetSeconds () << "sec"); Simulator::Schedule (m_tInterframeGap, - &CsmaCdNetDevice::TransmitReadyEvent, + &CsmaNetDevice::TransmitReadyEvent, this); } void -CsmaCdNetDevice::TransmitReadyEvent (void) +CsmaNetDevice::TransmitReadyEvent (void) { - NS_DEBUG ("CsmaCdNetDevice::TransmitReadyEvent ()"); + NS_DEBUG ("CsmaNetDevice::TransmitReadyEvent ()"); // // This function is called to enable the transmitter after the interframe // gap has passed. If there are pending transmissions, we use this opportunity @@ -450,7 +450,7 @@ CsmaCdNetDevice::TransmitReadyEvent (void) } TraceResolver * -CsmaCdNetDevice::DoCreateTraceResolver (TraceContext const &context) +CsmaNetDevice::DoCreateTraceResolver (TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); resolver->Add ("queue", @@ -458,17 +458,17 @@ CsmaCdNetDevice::DoCreateTraceResolver (TraceContext const &context) PeekPointer (m_queue))); resolver->Add ("rx", m_rxTrace, - CsmaCdTraceType (CsmaCdTraceType::RX)); + CsmaTraceType (CsmaTraceType::RX)); resolver->Add ("drop", m_dropTrace, - CsmaCdTraceType (CsmaCdTraceType::DROP)); + CsmaTraceType (CsmaTraceType::DROP)); return resolver; } bool -CsmaCdNetDevice::Attach (Ptr ch) +CsmaNetDevice::Attach (Ptr ch) { - NS_DEBUG ("CsmaCdNetDevice::Attach (" << &ch << ")"); + NS_DEBUG ("CsmaNetDevice::Attach (" << &ch << ")"); m_channel = ch; @@ -484,15 +484,15 @@ CsmaCdNetDevice::Attach (Ptr ch) } void -CsmaCdNetDevice::AddQueue (Ptr q) +CsmaNetDevice::AddQueue (Ptr q) { - NS_DEBUG ("CsmaCdNetDevice::AddQueue (" << q << ")"); + NS_DEBUG ("CsmaNetDevice::AddQueue (" << q << ")"); m_queue = q; } void -CsmaCdNetDevice::Receive (const Packet& packet) +CsmaNetDevice::Receive (const Packet& packet) { EthernetHeader header (false); EthernetTrailer trailer; @@ -500,7 +500,7 @@ CsmaCdNetDevice::Receive (const Packet& packet) Eui48Address destination; Packet p = packet; - NS_DEBUG ("CsmaCdNetDevice::Receive UID is (" << p.GetUid() << ")"); + NS_DEBUG ("CsmaNetDevice::Receive UID is (" << p.GetUid() << ")"); // Only receive if send side of net device is enabled if (!IsReceiveEnabled()) @@ -556,13 +556,13 @@ CsmaCdNetDevice::Receive (const Packet& packet) } Ptr -CsmaCdNetDevice::GetQueue(void) const +CsmaNetDevice::GetQueue(void) const { return m_queue; } Ptr -CsmaCdNetDevice::DoGetChannel(void) const +CsmaNetDevice::DoGetChannel(void) const { return m_channel; } diff --git a/src/devices/csma-cd/csma-cd-net-device.h b/src/devices/csma/csma-net-device.h similarity index 84% rename from src/devices/csma-cd/csma-cd-net-device.h rename to src/devices/csma/csma-net-device.h index 36a555339..40595f22e 100644 --- a/src/devices/csma-cd/csma-cd-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -19,8 +19,8 @@ * Derived from the p2p net device file */ -#ifndef CSMA_CD_NET_DEVICE_H -#define CSMA_CD_NET_DEVICE_H +#ifndef CSMA_NET_DEVICE_H +#define CSMA_NET_DEVICE_H #include #include "ns3/node.h" @@ -39,17 +39,17 @@ namespace ns3 { class Queue; -class CsmaCdChannel; +class CsmaChannel; -class CsmaCdTraceType : public TraceContextElement +class CsmaTraceType : public TraceContextElement { public: enum Type { RX, DROP }; - CsmaCdTraceType (enum Type type); - CsmaCdTraceType (); + CsmaTraceType (enum Type type); + CsmaTraceType (); void Print (std::ostream &os) const; static uint16_t GetUid (void); private: @@ -57,59 +57,59 @@ private: }; /** - * \class CsmaCdNetDevice - * \brief A Device for a CsmaCd Network Link. + * \class CsmaNetDevice + * \brief A Device for a Csma Network Link. * - * The Csma/Cd net device class is analogous to layer 1 and 2 of the + * The Csma net device class is analogous to layer 1 and 2 of the * TCP stack. The NetDevice takes a raw packet of bytes and creates a - * protocol specific packet from them. The Csma/Cd net device class + * protocol specific packet from them. The Csma net device class * takes this packet and adds and processes the headers/trailers that * are associated with EthernetV1, EthernetV2, RAW or LLC * protocols. The EthernetV1 packet type adds and removes Ethernet * destination and source addresses. The LLC packet type adds and * removes LLC snap headers. The raw packet type does not add or - * remove any headers. Each Csma/Cd net device will receive all - * packets written to the Csma/Cd link. The ProcessHeader function can + * remove any headers. Each Csma net device will receive all + * packets written to the Csma link. The ProcessHeader function can * be used to filter out the packets such that higher level layers * only receive packets that are addressed to their associated net * devices * */ -class CsmaCdNetDevice : public NetDevice { +class CsmaNetDevice : public NetDevice { public: /** * Enumeration of the types of packets supported in the class. * */ -enum CsmaCdEncapsulationMode { +enum CsmaEncapsulationMode { ETHERNET_V1, /**< Version one ethernet packet, length field */ IP_ARP, /**< Ethernet packet encapsulates IP/ARP packet */ RAW, /**< Packet that contains no headers */ LLC, /**< LLC packet encapsulation */ }; - CsmaCdNetDevice (Ptr node); + CsmaNetDevice (Ptr node); /** - * Construct a CsmaCdNetDevice + * Construct a CsmaNetDevice * - * This is the constructor for the CsmaCdNetDevice. It takes as a + * This is the constructor for the CsmaNetDevice. It takes as a * parameter the Node to which this device is connected. Ownership of the * Node pointer is not implied and the node must not be deleted. * * \param node the Node to which this device is connected. * \param addr The source MAC address of the net device. */ - CsmaCdNetDevice (Ptr node, Eui48Address addr, CsmaCdEncapsulationMode pktType); - CsmaCdNetDevice (Ptr node, Eui48Address addr, - CsmaCdEncapsulationMode pktType, + CsmaNetDevice (Ptr node, Eui48Address addr, CsmaEncapsulationMode pktType); + CsmaNetDevice (Ptr node, Eui48Address addr, + CsmaEncapsulationMode pktType, bool sendEnable, bool receiveEnable); /** - * Destroy a CsmaCdNetDevice + * Destroy a CsmaNetDevice * - * This is the destructor for the CsmaCdNetDevice. + * This is the destructor for the CsmaNetDevice. */ - virtual ~CsmaCdNetDevice(); + virtual ~CsmaNetDevice(); /** * Set the Data Rate used for transmission of packets. The data rate is * set in the Attach () method from the corresponding field in the channel @@ -146,23 +146,23 @@ enum CsmaCdEncapsulationMode { /** * Attach the device to a channel. * - * The function Attach is used to add a CsmaCdNetDevice to a - * CsmaCdChannel. + * The function Attach is used to add a CsmaNetDevice to a + * CsmaChannel. * * @see SetDataRate () * @see SetInterframeGap () * \param ch a pointer to the channel to which this object is being attached. */ - bool Attach (Ptr ch); + bool Attach (Ptr ch); /** - * Attach a queue to the CsmaCdNetDevice. + * Attach a queue to the CsmaNetDevice. * - * The CsmaCdNetDevice "owns" a queue. This queue is created by the - * CsmaCdTopology object and implements a queueing method such as - * DropTail or RED. The CsmaCdNetDevice assumes ownership of this + * The CsmaNetDevice "owns" a queue. This queue is created by the + * CsmaTopology object and implements a queueing method such as + * DropTail or RED. The CsmaNetDevice assumes ownership of this * queue and must delete it when the device is destroyed. * - * @see CsmaCdTopology::AddCsmaCdLink () + * @see CsmaTopology::AddCsmaLink () * @see Queue * @see DropTailQueue * \param queue a pointer to the queue for which object is assuming @@ -170,14 +170,14 @@ enum CsmaCdEncapsulationMode { */ void AddQueue (Ptr queue); /** - * Receive a packet from a connected CsmaCdChannel. + * Receive a packet from a connected CsmaChannel. * - * The CsmaCdNetDevice receives packets from its connected channel + * The CsmaNetDevice receives packets from its connected channel * and forwards them up the protocol stack. This is the public method * used by the channel to indicate that the last bit of a packet has * arrived at the device. * - * @see CsmaCdChannel + * @see CsmaChannel * \param p a reference to the received packet */ void Receive (const Packet& p); @@ -234,14 +234,14 @@ protected: private: // disable copy constructor and operator = - CsmaCdNetDevice &operator = (const CsmaCdNetDevice &o); - CsmaCdNetDevice (const CsmaCdNetDevice &o); + CsmaNetDevice &operator = (const CsmaNetDevice &o); + CsmaNetDevice (const CsmaNetDevice &o); /** * Initializes variablea when construction object. */ void Init (bool sendEnable, bool receiveEnable); /** - * Send a Packet on the Csma/Cd network + * Send a Packet on the Csma network * * This method does not use a destination address since all packets * are broadcast to all NetDevices attached to the channel. Packet @@ -261,7 +261,7 @@ private: * Start Sending a Packet Down the Wire. * * The TransmitStart method is the method that is used internally in - * the CsmaCdNetDevice to begin the process of sending a packet + * the CsmaNetDevice to begin the process of sending a packet * out on the channel. The corresponding method is called on the * channel to let it know that the physical device this class * represents has virually started sending signals, this causes the @@ -270,7 +270,7 @@ private: * is busy, the method reschedules itself for a later time (within * the backoff period) * - * @see CsmaCdChannel::TransmitStart () + * @see CsmaChannel::TransmitStart () * @see TransmitCompleteEvent () */ void TransmitStart (); @@ -287,7 +287,7 @@ private: * also schedules the TransmitReadyEvent at which time the transmitter * becomes ready to send the next packet. * - * @see CsmaCdChannel::TransmitEnd () + * @see CsmaChannel::TransmitEnd () * @see TransmitReadyEvent () */ void TransmitCompleteEvent (void); @@ -359,7 +359,7 @@ private: * function and that should be processed by the ProcessHeader * function. */ - CsmaCdEncapsulationMode m_encapMode; + CsmaEncapsulationMode m_encapMode; /** * The data rate that the Net Device uses to simulate packet transmission * timing. @@ -385,14 +385,14 @@ private: */ Packet m_currentPkt; /** - * The CsmaCdChannel to which this CsmaCdNetDevice has been + * The CsmaChannel to which this CsmaNetDevice has been * attached. - * @see class CsmaCdChannel + * @see class CsmaChannel */ - Ptr m_channel; + Ptr m_channel; /** - * The Queue which this CsmaCdNetDevice uses as a packet source. - * Management of this Queue has been delegated to the CsmaCdNetDevice + * The Queue which this CsmaNetDevice uses as a packet source. + * Management of this Queue has been delegated to the CsmaNetDevice * and it has the responsibility for deletion. * @see class Queue * @see class DropTailQueue @@ -413,5 +413,5 @@ private: }; // namespace ns3 -#endif // CSMA_CD_NET_DEVICE_H +#endif // CSMA_NET_DEVICE_H diff --git a/src/devices/csma-cd/csma-cd-topology.cc b/src/devices/csma/csma-topology.cc similarity index 67% rename from src/devices/csma-cd/csma-cd-topology.cc rename to src/devices/csma/csma-topology.cc index e4af1a309..27e4e9e29 100644 --- a/src/devices/csma-cd/csma-cd-topology.cc +++ b/src/devices/csma/csma-topology.cc @@ -19,38 +19,38 @@ // // -// Topology helper for CsmaCd channels in ns3. +// Topology helper for Csma channels in ns3. #include "ns3/assert.h" #include "ns3/debug.h" #include "ns3/queue.h" -#include "csma-cd-channel.h" -#include "csma-cd-net-device.h" -#include "csma-cd-topology.h" +#include "csma-channel.h" +#include "csma-net-device.h" +#include "csma-topology.h" #include "ns3/socket-factory.h" namespace ns3 { -Ptr -CsmaCdTopology::CreateCsmaCdChannel( +Ptr +CsmaTopology::CreateCsmaChannel( const DataRate& bps, const Time& delay) { - Ptr channel = Create (bps, delay); + Ptr channel = Create (bps, delay); return channel; } #if 0 -Ptr -CsmaCdTopology::AddCsmaCdEthernetNode( +Ptr +CsmaTopology::AddCsmaEthernetNode( Ptr n1, - Ptr ch, + Ptr ch, MacAddress addr) { - Ptr nd1 = Create (n1, addr, - ns3::CsmaCdNetDevice::ETHERNET_V1); + Ptr nd1 = Create (n1, addr, + ns3::CsmaNetDevice::ETHERNET_V1); Ptr q = Queue::CreateDefault (); nd1->AddQueue(q); @@ -60,9 +60,9 @@ CsmaCdTopology::AddCsmaCdEthernetNode( } Ptr -CsmaCdTopology::ConnectPacketSocket(Ptr app, - Ptr ndSrc, - Ptr ndDest) +CsmaTopology::ConnectPacketSocket(Ptr app, + Ptr ndSrc, + Ptr ndDest) { Ptr socket = Create (); socket->Bind(ndSrc); @@ -73,8 +73,8 @@ CsmaCdTopology::ConnectPacketSocket(Ptr app, } Ptr -CsmaCdTopology::ConnectPacketSocket(Ptr app, - Ptr ndSrc, +CsmaTopology::ConnectPacketSocket(Ptr app, + Ptr ndSrc, MacAddress macAddr) { Ptr socket = Create (); @@ -86,7 +86,7 @@ CsmaCdTopology::ConnectPacketSocket(Ptr app, } Ptr -CsmaCdTopology::CreatePacketSocket(Ptr n1, std::string iid_name) +CsmaTopology::CreatePacketSocket(Ptr n1, std::string iid_name) { InterfaceId iid = InterfaceId::LookupByName (iid_name); diff --git a/src/devices/csma-cd/csma-cd-topology.h b/src/devices/csma/csma-topology.h similarity index 80% rename from src/devices/csma-cd/csma-cd-topology.h rename to src/devices/csma/csma-topology.h index 46c54a022..9f39b73ef 100644 --- a/src/devices/csma-cd/csma-cd-topology.h +++ b/src/devices/csma/csma-topology.h @@ -19,11 +19,11 @@ // // Topology helper for multipoint channels in ns3. // -#ifndef CSMA_CD_TOPOLOGY_H -#define CSMA_CD_TOPOLOGY_H +#ifndef CSMA_TOPOLOGY_H +#define CSMA_TOPOLOGY_H #include "ns3/ptr.h" -#include "ns3/csma-cd-net-device.h" +#include "ns3/csma-net-device.h" #include "ns3/node.h" // The topology class consists of only static methods thar are used to @@ -31,16 +31,16 @@ namespace ns3 { -class CsmaCdChannel; +class CsmaChannel; class Node; class DataRate; class Queue; /** - * \brief A helper class to create CsmaCd Topologies + * \brief A helper class to create Csma Topologies * - * CsmaCd topologies are created based on the - * ns3::CsmaCdNetDevice subclasses and ns3::CsmaCdChannel + * Csma topologies are created based on the + * ns3::CsmaNetDevice subclasses and ns3::CsmaChannel * objects. This class uses the EthernetNetDevice and * PacketSocket classes in order to create logical connections between * net devices. The PacketSocket class generates the data and the @@ -49,30 +49,30 @@ class Queue; * EthernetNetDevice class filters received data packets * according to its destination Mac addresses. */ -class CsmaCdTopology { +class CsmaTopology { public: /** * \param dataRate Maximum transmission link rate * \param delay propagation delay between any two nodes - * \return Pointer to the created CsmaCdChannel + * \return Pointer to the created CsmaChannel * - * Create a CsmaCdChannel. All nodes connected to a multipoint + * Create a CsmaChannel. All nodes connected to a multipoint * channels will receive all packets written to that channel */ - static Ptr CreateCsmaCdChannel( + static Ptr CreateCsmaChannel( const DataRate& dataRate, const Time& delay); #if 0 /** * \param n1 Node to be attached to the multipoint channel - * \param ch CsmaCdChannel to which node n1 should be attached + * \param ch CsmaChannel to which node n1 should be attached * \param addr MacAddress that should be assigned to the * EthernetNetDevice that will be added to the node. * * Add a multipoint node to a multipoint channel */ - static Ptr AddCsmaCdEthernetNode(Ptr n1, - Ptr ch, + static Ptr AddCsmaEthernetNode(Ptr n1, + Ptr ch, MacAddress addr); /** @@ -86,8 +86,8 @@ public: * two net devices */ static Ptr ConnectPacketSocket(Ptr app, - Ptr ndSrc, - Ptr ndDest); + Ptr ndSrc, + Ptr ndDest); /** * \param app Application that will be sending data to the agent @@ -101,7 +101,7 @@ static Ptr ConnectPacketSocket(Ptr app, * net device to a destination MacAddress */ static Ptr ConnectPacketSocket(Ptr app, - Ptr ndSrc, + Ptr ndSrc, MacAddress macAddr); /** diff --git a/src/devices/csma/wscript b/src/devices/csma/wscript new file mode 100644 index 000000000..8257c06dc --- /dev/null +++ b/src/devices/csma/wscript @@ -0,0 +1,19 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_module('csma', ['node']) + obj.source = [ + 'backoff.cc', + 'csma-net-device.cc', + 'csma-channel.cc', + 'csma-topology.cc', + 'csma-ipv4-topology.cc', + ] + headers = bld.create_obj('ns3header') + headers.source = [ + 'backoff.h', + 'csma-net-device.h', + 'csma-channel.h', + 'csma-topology.h', + 'csma-ipv4-topology.h', + ] diff --git a/src/wscript b/src/wscript index 0d50d0889..1e20fb75c 100644 --- a/src/wscript +++ b/src/wscript @@ -17,7 +17,7 @@ all_modules = ( 'node', 'internet-node', 'devices/point-to-point', - 'devices/csma-cd', + 'devices/csma', 'applications', 'routing/global-routing', 'mobility', From 250109b215d121fc8be7b97f17bab94b951da29e Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 9 Aug 2007 15:58:13 -0700 Subject: [PATCH 240/278] remove old file --- examples/csma-cd-one-subnet.cc | 166 --------------------------------- 1 file changed, 166 deletions(-) delete mode 100644 examples/csma-cd-one-subnet.cc diff --git a/examples/csma-cd-one-subnet.cc b/examples/csma-cd-one-subnet.cc deleted file mode 100644 index 743e92bc9..000000000 --- a/examples/csma-cd-one-subnet.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// Port of ns-2/tcl/ex/simple.tcl to ns-3 -// -// Network topology -// -// n0 n1 n2 n3 -// | | | | -// ===================== -// -// - CBR/UDP flows from n0 to n1, and from n3 to n0 -// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. -// (i.e., DataRate of 448,000 bps) -// - DropTail queues -// - Tracing of queues and packet receptions to file "csma-cd-one-subnet.tr" - -#include -#include -#include -#include - -#include "ns3/command-line.h" -#include "ns3/default-value.h" -#include "ns3/ptr.h" -#include "ns3/random-variable.h" -#include "ns3/debug.h" - -#include "ns3/simulator.h" -#include "ns3/nstime.h" -#include "ns3/data-rate.h" - -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" -#include "ns3/internet-node.h" -#include "ns3/csma-cd-channel.h" -#include "ns3/csma-cd-net-device.h" -#include "ns3/csma-cd-topology.h" -#include "ns3/csma-cd-ipv4-topology.h" -#include "ns3/eui48-address.h" -#include "ns3/ipv4-address.h" -#include "ns3/inet-socket-address.h" -#include "ns3/ipv4.h" -#include "ns3/socket.h" -#include "ns3/ipv4-route.h" -#include "ns3/onoff-application.h" - - -using namespace ns3; - - -int main (int argc, char *argv[]) -{ - - // Users may find it convenient to turn on explicit debugging - // for selected modules; the below lines suggest how to do this -#if 0 - DebugComponentEnable("CsmaCdNetDevice"); - DebugComponentEnable("Ipv4L3Protocol"); - DebugComponentEnable("NetDevice"); - DebugComponentEnable("Channel"); - DebugComponentEnable("CsmaCdChannel"); - DebugComponentEnable("PacketSocket"); -#endif - - // Set up some default values for the simulation. Use the Bind() - // technique to tell the system what subclass of Queue to use, - // and what the queue limit is - - // The below Bind command tells the queue factory which class to - // instantiate, when the queue factory is invoked in the topology code - DefaultValue::Bind ("Queue", "DropTailQueue"); - - // Allow the user to override any of the defaults and the above - // Bind()s at run-time, via command-line arguments - CommandLine::Parse (argc, argv); - - // Here, we will explicitly create four nodes. In more sophisticated - // topologies, we could configure a node factory. - Ptr n0 = Create (); - Ptr n1 = Create (); - Ptr n2 = Create (); - Ptr n3 = Create (); - - // We create the channels first without any IP addressing information - Ptr channel0 = - CsmaCdTopology::CreateCsmaCdChannel( - DataRate(5000000), MilliSeconds(2)); - - uint32_t n0ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n0, channel0, - Eui48Address("10:54:23:54:23:50")); - uint32_t n1ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n1, channel0, - Eui48Address("10:54:23:54:23:51")); - uint32_t n2ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n2, channel0, - Eui48Address("10:54:23:54:23:52")); - uint32_t n3ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n3, channel0, - Eui48Address("10:54:23:54:23:53")); - - // Later, we add IP addresses. - CsmaCdIpv4Topology::AddIpv4Address ( - n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0")); - - CsmaCdIpv4Topology::AddIpv4Address ( - n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0")); - - CsmaCdIpv4Topology::AddIpv4Address ( - n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0")); - - CsmaCdIpv4Topology::AddIpv4Address ( - n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0")); - - // Create the OnOff application to send UDP datagrams of size - // 210 bytes at a rate of 448 Kb/s - // from n0 to n1 - Ptr ooff = Create ( - n0, - InetSocketAddress ("10.1.1.2", 80), - "Udp", - ConstantVariable(1), - ConstantVariable(0)); - // Start the application - ooff->Start(Seconds(1.0)); - ooff->Stop (Seconds(10.0)); - - // Create a similar flow from n3 to n0, starting at time 1.1 seconds - ooff = Create ( - n3, - InetSocketAddress ("10.1.1.1", 80), - "Udp", - ConstantVariable(1), - ConstantVariable(0)); - // Start the application - ooff->Start(Seconds(1.1)); - ooff->Stop (Seconds(10.0)); - - // Configure tracing of all enqueue, dequeue, and NetDevice receive events - // Trace output will be sent to the csma-cd-one-subnet.tr file - AsciiTrace asciitrace ("csma-cd-one-subnet.tr"); - asciitrace.TraceAllNetDeviceRx (); - asciitrace.TraceAllQueues (); - - // Also configure some tcpdump traces; each interface will be traced - // The output files will be named - // simple-point-to-point.pcap-- - // and can be read by the "tcpdump -r" command (use "-tt" option to - // display timestamps correctly) - PcapTrace pcaptrace ("csma-cd-one-subnet.pcap"); - pcaptrace.TraceAllIp (); - - Simulator::Run (); - - Simulator::Destroy (); -} From ee2b9fc8858f6e8e5fcae7434c2205e11ff1df2a Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 10 Aug 2007 13:17:57 +0200 Subject: [PATCH 241/278] avoid output of spurious whitespaces during testing --- src/common/packet-metadata-test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index 7f3711735..e3e61c45e 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -230,6 +230,7 @@ PacketMetadataTest::PacketMetadataTest () : Test ("PacketMetadata") { m_printer.SetPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this)); + m_printer.SetSeparator (""); } PacketMetadataTest::~PacketMetadataTest () From 8881f8bd913d620b4dbd977523f2912cef1f1e20 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 10 Aug 2007 13:24:36 +0200 Subject: [PATCH 242/278] avoid more spurious whitespaces during testing --- src/common/packet.cc | 2 +- src/common/tags.cc | 16 ++++++++-------- src/common/tags.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/common/packet.cc b/src/common/packet.cc index 4c1a3b87d..5159f3e2c 100644 --- a/src/common/packet.cc +++ b/src/common/packet.cc @@ -128,7 +128,7 @@ Packet::GetUid (void) const void Packet::PrintTags (std::ostream &os) const { - m_tags.Print (os); + m_tags.Print (os, " "); } void diff --git a/src/common/tags.cc b/src/common/tags.cc index 635f82b65..e2206b7af 100644 --- a/src/common/tags.cc +++ b/src/common/tags.cc @@ -119,14 +119,14 @@ Tags::Remove (uint32_t id) } void -Tags::Print (std::ostream &os) const +Tags::Print (std::ostream &os, std::string separator) const { for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { TagRegistry::Print (cur->m_id, cur->m_data, os); if (cur->m_next != 0) { - os << " "; + os << separator; } } } @@ -347,7 +347,7 @@ TagsTest::RunTests (void) ok = false; } g_a = false; - tags.Print (std::cout); + tags.Print (std::cout, ""); if (!g_a) { ok = false; @@ -363,7 +363,7 @@ TagsTest::RunTests (void) } g_b = false; g_a = false; - tags.Print (std::cout); + tags.Print (std::cout, ""); if (!g_a || !g_b) { ok = false; @@ -372,14 +372,14 @@ TagsTest::RunTests (void) Tags other = tags; g_b = false; g_a = false; - other.Print (std::cout); + other.Print (std::cout, ""); if (!g_a || !g_b) { ok = false; } g_b = false; g_a = false; - tags.Print (std::cout); + tags.Print (std::cout, ""); if (!g_a || !g_b) { ok = false; @@ -406,7 +406,7 @@ TagsTest::RunTests (void) } g_b = false; g_a = false; - other.Print (std::cout); + other.Print (std::cout, ""); if (g_a || !g_b) { ok = false; @@ -452,7 +452,7 @@ TagsTest::RunTests (void) tagZ.z = 0; testLastTag.Add (tagZ); g_z = false; - testLastTag.Print (std::cout); + testLastTag.Print (std::cout, ""); if (!g_z) { ok = false; diff --git a/src/common/tags.h b/src/common/tags.h index ff52a49fe..4002ae4f8 100644 --- a/src/common/tags.h +++ b/src/common/tags.h @@ -52,7 +52,7 @@ public: template bool Peek (T &tag) const; - void Print (std::ostream &os) const; + void Print (std::ostream &os, std::string separator) const; uint32_t GetSerializedSize (void) const; void Serialize (Buffer::Iterator i, uint32_t size) const; uint32_t Deserialize (Buffer::Iterator i); From 971997fbc13550c0897b85baa8be1ff986753498 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 10 Aug 2007 19:18:19 +0200 Subject: [PATCH 243/278] use implicit conversion rather than private explicit conversion: fixes build --- src/internet-node/ipv4-loopback-interface.cc | 2 +- src/node/packet-socket.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internet-node/ipv4-loopback-interface.cc b/src/internet-node/ipv4-loopback-interface.cc index fb9ac1fc9..be680a022 100644 --- a/src/internet-node/ipv4-loopback-interface.cc +++ b/src/internet-node/ipv4-loopback-interface.cc @@ -45,7 +45,7 @@ void Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest) { Ptr ipv4 = m_node->QueryInterface (Ipv4L3Protocol::iid); - ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff").ConvertTo ()); + ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff")); } }//namespace ns3 diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index 6035f74f6..f642eee9e 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -279,7 +279,7 @@ PacketSocket::ForwardUp (Ptr device, const Packet &packet, NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid() << " PacketSocket " << this); - NotifyDataReceived (p, address.ConvertTo ()); + NotifyDataReceived (p, address); } }//namespace ns3 From c298892833b51d8fd017e43bd495bcd688692c66 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 10 Aug 2007 10:44:02 -0700 Subject: [PATCH 244/278] print length/type in hex --- src/node/ethernet-header.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/node/ethernet-header.cc b/src/node/ethernet-header.cc index e6bffaf1c..88803b4f5 100644 --- a/src/node/ethernet-header.cc +++ b/src/node/ethernet-header.cc @@ -19,6 +19,8 @@ * Author: Emmanuelle Laprise */ +#include +#include #include "ns3/assert.h" #include "ns3/debug.h" #include "ns3/header.h" @@ -118,7 +120,8 @@ EthernetHeader::Print (std::ostream &os) const { os << " preamble/sfd=" << m_preambleSfd << ","; } - os << " length/type=" << m_lengthType + + os << " length/type=0x" << std::hex << m_lengthType << std::dec << ", source=" << m_source << ", destination=" << m_destination; } From 8e6b694d6e27ee35778523f2c1541d4ac8861f92 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 10 Aug 2007 10:45:59 -0700 Subject: [PATCH 245/278] move m_rxTrace to trace enet header --- src/devices/csma/csma-net-device.cc | 3 ++- src/devices/point-to-point/point-to-point-net-device.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index e3346c3bb..4217f8941 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -528,6 +528,8 @@ CsmaNetDevice::Receive (const Packet& packet) m_dropTrace (p); return; } + + m_rxTrace (p); // // protocol must be initialized to avoid a compiler warning in the RAW // case that breaks the optimized build. @@ -550,7 +552,6 @@ CsmaNetDevice::Receive (const Packet& packet) break; } - m_rxTrace (p); ForwardUp (p, protocol, header.GetSource ()); return; } diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 86c9d9a4c..e77508e46 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -237,8 +237,8 @@ void PointToPointNetDevice::Receive (Packet& p) uint16_t protocol = 0; Packet packet = p; - ProcessHeader(packet, protocol); m_rxTrace (packet); + ProcessHeader(packet, protocol); ForwardUp (packet, protocol, GetBroadcast ()); } From 5da9cd22050f940b56bcb3da9cde4e6261c9febf Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 10 Aug 2007 13:49:41 -0700 Subject: [PATCH 246/278] remove spurious examples/simple-p2p.cc --- examples/simple-p2p.cc | 189 ----------------------------------------- 1 file changed, 189 deletions(-) delete mode 100644 examples/simple-p2p.cc diff --git a/examples/simple-p2p.cc b/examples/simple-p2p.cc deleted file mode 100644 index d06ef329f..000000000 --- a/examples/simple-p2p.cc +++ /dev/null @@ -1,189 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ns-2 simple.tcl script (ported from ns-2) - * Originally authored by Steve McCanne, 12/19/1996 - */ - -// Port of ns-2/tcl/ex/simple.tcl to ns-3 -// -// Network topology -// -// n0 -// \ 5 Mb/s, 2ms -// \ 1.5Mb/s, 10ms -// n2 -------------------------n3 -// / -// / 5 Mb/s, 2ms -// n1 -// -// - all links are p2p links with indicated one-way BW/delay -// - CBR/UDP flows from n0 to n3, and from n3 to n1 -// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. -// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. -// (i.e., DataRate of 448,000 bps) -// - DropTail queues -// - Tracing of queues and packet receptions to file "simple-p2p.tr" - -#include -#include -#include -#include - -#include "ns3/command-line.h" -#include "ns3/default-value.h" -#include "ns3/ptr.h" -#include "ns3/random-variable.h" - -#include "ns3/simulator.h" -#include "ns3/nstime.h" -#include "ns3/data-rate.h" - -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" -#include "ns3/internet-node.h" -#include "ns3/p2p-channel.h" -#include "ns3/p2p-net-device.h" -#include "ns3/ipv4-address.h" -#include "ns3/inet-socket-address.h" -#include "ns3/ipv4.h" -#include "ns3/socket.h" -#include "ns3/ipv4-route.h" -#include "ns3/p2p-topology.h" -#include "ns3/onoff-application.h" - -using namespace ns3; - -int main (int argc, char *argv[]) -{ - - // Users may find it convenient to turn on explicit debugging - // for selected modules; the below lines suggest how to do this -#if 0 - DebugComponentEnable("Object"); - DebugComponentEnable("Queue"); - DebugComponentEnable("DropTailQueue"); - DebugComponentEnable("Channel"); - DebugComponentEnable("PointToPointChannel"); - DebugComponentEnable("PointToPointNetDevice"); -#endif - - // Set up some default values for the simulation. Use the Bind() - // technique to tell the system what subclass of Queue to use, - // and what the queue limit is - - // The below Bind command tells the queue factory which class to - // instantiate, when the queue factory is invoked in the topology code - Bind ("Queue", "DropTailQueue"); - - Bind ("OnOffApplicationPacketSize", "210"); - Bind ("OnOffApplicationDataRate", "448kb/s"); - - //Bind ("DropTailQueue::m_maxPackets", 30); - - // Allow the user to override any of the defaults and the above - // Bind()s at run-time, via command-line arguments - CommandLine::Parse (argc, argv); - - // Here, we will explicitly create four nodes. In more sophisticated - // topologies, we could configure a node factory. - Ptr n0 = Create (); - Ptr n1 = Create (); - Ptr n2 = Create (); - Ptr n3 = Create (); - - // We create the channels first without any IP addressing information - Ptr channel0 = - PointToPointTopology::AddPointToPointLink ( - n0, n2, DataRate(5000000), MilliSeconds(2)); - - Ptr channel1 = - PointToPointTopology::AddPointToPointLink ( - n1, n2, DataRate(5000000), MilliSeconds(2)); - - Ptr channel2 = - PointToPointTopology::AddPointToPointLink ( - n2, n3, DataRate(1500000), MilliSeconds(10)); - - // Later, we add IP addresses. - PointToPointTopology::AddIpv4Addresses ( - channel0, n0, Ipv4Address("10.1.1.1"), - n2, Ipv4Address("10.1.1.2")); - - PointToPointTopology::AddIpv4Addresses ( - channel1, n1, Ipv4Address("10.1.2.1"), - n2, Ipv4Address("10.1.2.2")); - - PointToPointTopology::AddIpv4Addresses ( - channel2, n2, Ipv4Address("10.1.3.1"), - n3, Ipv4Address("10.1.3.2")); - - // Finally, we add static routes. These three steps (Channel and - // NetDevice creation, IP Address assignment, and routing) are - // separated because there may be a need to postpone IP Address - // assignment (emulation) or modify to use dynamic routing - PointToPointTopology::AddIpv4Routes(n0, n2, channel0); - PointToPointTopology::AddIpv4Routes(n1, n2, channel1); - PointToPointTopology::AddIpv4Routes(n2, n3, channel2); - - - // Create the OnOff application to send UDP datagrams of size - // 210 bytes at a rate of 448 Kb/s - Ptr ooff = Create ( - n0, - InetSocketAddress("10.1.3.2", 80).ConvertTo (), - "Udp", - ConstantVariable(1), - ConstantVariable(0)); - // Start the application - ooff->Start(Seconds(1.0)); - ooff->Stop (Seconds(10.0)); - - // Create a similar flow from n3 to n1, starting at time 1.1 seconds - ooff = Create ( - n3, - InetSocketAddress("10.1.2.1", 80).ConvertTo (), - "Udp", - ConstantVariable(1), - ConstantVariable(0)); - // Start the application - ooff->Start(Seconds(1.1)); - ooff->Stop (Seconds(10.0)); - - // Here, finish off packet routing configuration - // This will likely set by some global StaticRouting object in the future - Ptr ipv4; - ipv4 = n0->QueryInterface (Ipv4::iid); - ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); - ipv4 = n3->QueryInterface (Ipv4::iid); - ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); - - // Configure tracing of all enqueue, dequeue, and NetDevice receive events - // Trace output will be sent to the simple-p2p.tr file - AsciiTrace asciitrace ("simple-p2p.tr"); - asciitrace.TraceAllQueues (); - asciitrace.TraceAllNetDeviceRx (); - - // Also configure some tcpdump traces; each interface will be traced - // The output files will be named simple-p2p.pcap-- - // and can be read by the "tcpdump -r" command (use "-tt" option to - // display timestamps correctly) - PcapTrace pcaptrace ("simple-p2p.pcap"); - pcaptrace.TraceAllIp (); - - Simulator::Run (); - - Simulator::Destroy (); -} From 883d92940f66f365eb095023d947c8c06edac9b3 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 10 Aug 2007 13:33:45 -0700 Subject: [PATCH 247/278] global routing csma patch --- examples/mixed-global-routing.cc | 199 ++++++ examples/wscript | 4 + src/devices/csma/csma-net-device.cc | 1 - .../global-route-manager-impl.cc | 575 +++++++++++++----- .../global-route-manager-impl.h | 76 ++- .../global-routing/global-router-interface.cc | 481 +++++++++++---- .../global-routing/global-router-interface.h | 236 ++++--- 7 files changed, 1201 insertions(+), 371 deletions(-) create mode 100644 examples/mixed-global-routing.cc diff --git a/examples/mixed-global-routing.cc b/examples/mixed-global-routing.cc new file mode 100644 index 000000000..b3017e029 --- /dev/null +++ b/examples/mixed-global-routing.cc @@ -0,0 +1,199 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +// This script exercises global routing code in a mixed point-to-point +// and csma/cd environment +// +// Network topology +// +// n0 +// \ p-p +// \ (shared csma/cd) +// n2 -------------------------n3 +// / | | +// / p-p n4 n5 ---------- n6 +// n1 p-p +// +// - CBR/UDP flows from n0 to n6 +// - Tracing of queues and packet receptions to file "mixed-global-routing.tr" + +#include +#include +#include +#include + +#include "ns3/debug.h" + +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" +#include "ns3/random-variable.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/csma-channel.h" +#include "ns3/csma-net-device.h" +#include "ns3/csma-topology.h" +#include "ns3/csma-ipv4-topology.h" +#include "ns3/eui48-address.h" +#include "ns3/ipv4-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/global-route-manager.h" + +using namespace ns3; + +int main (int argc, char *argv[]) +{ + + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + DebugComponentEnable ("Object"); + DebugComponentEnable ("Queue"); + DebugComponentEnable ("DropTailQueue"); + DebugComponentEnable ("Channel"); + DebugComponentEnable ("PointToPointChannel"); + DebugComponentEnable ("PointToPointNetDevice"); + DebugComponentEnable ("GlobalRouter"); + DebugComponentEnable ("GlobalRouteManager"); +#endif + + // Set up some default values for the simulation. Use the Bind () + // technique to tell the system what subclass of Queue to use, + // and what the queue limit is + + // The below DefaultValue::Bind command tells the queue factory which + // class to instantiate, when the queue factory is invoked in the + // topology code + DefaultValue::Bind ("Queue", "DropTailQueue"); + + DefaultValue::Bind ("OnOffApplicationPacketSize", "210"); + DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s"); + + //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30); + + // Allow the user to override any of the defaults and the above + // Bind ()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + Ptr n4 = Create (); + Ptr n5 = Create (); + Ptr n6 = Create (); + + // We create the channels first without any IP addressing information + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n2, DataRate (5000000), MilliSeconds (2)); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate (5000000), MilliSeconds (2)); + + Ptr channel2 = + PointToPointTopology::AddPointToPointLink ( + n5, n6, DataRate (1500000), MilliSeconds (10)); + + // We create the channels first without any IP addressing information + Ptr channelc0 = + CsmaTopology::CreateCsmaChannel( + DataRate(5000000), MilliSeconds(2)); + + uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channelc0, + Eui48Address("10:54:23:54:23:50")); + uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channelc0, + Eui48Address("10:54:23:54:23:51")); + uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n4, channelc0, + Eui48Address("10:54:23:54:23:52")); + uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n5, channelc0, + Eui48Address("10:54:23:54:23:53")); + + // Later, we add IP addresses. + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address ("10.1.1.1"), + n2, Ipv4Address ("10.1.1.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address ("10.1.2.1"), + n2, Ipv4Address ("10.1.2.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel2, n5, Ipv4Address ("10.1.3.1"), + n6, Ipv4Address ("10.1.3.2")); + + CsmaIpv4Topology::AddIpv4Address ( + n2, n2ifIndex, Ipv4Address("10.250.1.1"), Ipv4Mask("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address ( + n3, n3ifIndex, Ipv4Address("10.250.1.2"), Ipv4Mask("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address ( + n4, n4ifIndex, Ipv4Address("10.250.1.3"), Ipv4Mask("255.255.255.0")); + + CsmaIpv4Topology::AddIpv4Address ( + n5, n5ifIndex, Ipv4Address("10.250.1.4"), Ipv4Mask("255.255.255.0")); + + // Create router nodes, initialize routing database and set up the routing + // tables in the nodes. + GlobalRouteManager::PopulateRoutingTables (); + + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + Ptr ooff = Create ( + n0, + InetSocketAddress ("10.1.3.2", 80), + "Udp", + ConstantVariable (1), + ConstantVariable (0), + DataRate("300bps"), + 50); + // Start the application + ooff->Start (Seconds (1.0)); + ooff->Stop (Seconds (10.0)); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-global-routing.tr file + AsciiTrace asciitrace ("mixed-global-routing.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + // Also configure some tcpdump traces; each interface will be traced + // The output files will be named simple-p2p.pcap-- + // and can be read by the "tcpdump -r" command (use "-tt" option to + // display timestamps correctly) + PcapTrace pcaptrace ("mixed-global-routing.pcap"); + pcaptrace.TraceAllIp (); + + Simulator::Run (); + + Simulator::Destroy (); +} diff --git a/examples/wscript b/examples/wscript index e7559756f..e5e771555 100644 --- a/examples/wscript +++ b/examples/wscript @@ -17,3 +17,7 @@ def build(bld): obj = bld.create_ns3_program('csma-packet-socket', ['csma', 'internet-node']) obj.source = 'csma-packet-socket.cc' + + obj = bld.create_ns3_program( 'mixed-global-routing', + ['point-to-point', 'internet-node', 'global-routing' , 'csma-cd']) + obj.source = 'mixed-global-routing.cc' diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index a493fa12a..531bf7314 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -133,7 +133,6 @@ CsmaNetDevice::Init(bool sendEnable, bool receiveEnable) EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff")); EnableMulticast(); - EnablePointToPoint(); SetSendEnable (sendEnable); SetReceiveEnable (receiveEnable); diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 142f613be..e78dfedf6 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -48,8 +48,7 @@ SPFVertex::SPFVertex () : { } -SPFVertex::SPFVertex (GlobalRouterLSA* lsa) : - m_vertexType (VertexRouter), +SPFVertex::SPFVertex (GlobalRoutingLSA* lsa) : m_vertexId (lsa->GetLinkStateId ()), m_lsa (lsa), m_distanceFromRoot (SPF_INFINITY), @@ -58,6 +57,16 @@ SPFVertex::SPFVertex (GlobalRouterLSA* lsa) : m_parent (0), m_children () { + if (lsa->GetLSType () == GlobalRoutingLSA::RouterLSA) + { + NS_DEBUG ("SPFVertex:: setting m_vertexType to VertexRouter"); + m_vertexType = SPFVertex::VertexRouter; + } + else if (lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA) + { + NS_DEBUG ("SPFVertex:: setting m_vertexType to VertexNetwork"); + m_vertexType = SPFVertex::VertexNetwork; + } } SPFVertex::~SPFVertex () @@ -99,12 +108,12 @@ SPFVertex::GetVertexId (void) const } void -SPFVertex::SetLSA (GlobalRouterLSA* lsa) +SPFVertex::SetLSA (GlobalRoutingLSA* lsa) { m_lsa = lsa; } - GlobalRouterLSA* + GlobalRoutingLSA* SPFVertex::GetLSA (void) const { return m_lsa; @@ -210,7 +219,7 @@ GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB () for (i= m_database.begin (); i!= m_database.end (); i++) { NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ():free LSA"); - GlobalRouterLSA* temp = i->second; + GlobalRoutingLSA* temp = i->second; delete temp; } NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB (): clear map"); @@ -225,19 +234,19 @@ GlobalRouteManagerLSDB::Initialize () LSDBMap_t::iterator i; for (i= m_database.begin (); i!= m_database.end (); i++) { - GlobalRouterLSA* temp = i->second; - temp->SetStatus (GlobalRouterLSA::LSA_SPF_NOT_EXPLORED); + GlobalRoutingLSA* temp = i->second; + temp->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); } } void -GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRouterLSA* lsa) +GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRoutingLSA* lsa) { NS_DEBUG ("GlobalRouteManagerLSDB::Insert ()"); m_database.insert (LSDBPair_t (addr, lsa)); } - GlobalRouterLSA* + GlobalRoutingLSA* GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const { NS_DEBUG ("GlobalRouteManagerLSDB::GetLSA ()"); @@ -255,6 +264,31 @@ GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const return 0; } + GlobalRoutingLSA* +GlobalRouteManagerLSDB::GetLSAByLinkData (Ipv4Address addr) const +{ + NS_DEBUG ("GlobalRouteManagerLSDB::GetLSAByLinkData ()"); +// +// Look up an LSA by its address. +// + LSDBMap_t::const_iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + GlobalRoutingLSA* temp = i->second; +// Iterate among temp's Link Records + for (uint32_t j = 0; j < temp->GetNLinkRecords (); j++) + { + GlobalRoutingLinkRecord *lr = temp->GetLinkRecord (j); + if ( lr->GetLinkType () == GlobalRoutingLinkRecord::TransitNetwork && + lr->GetLinkData () == addr) + { + return temp; + } + } + } + return 0; +} + // --------------------------------------------------------------------------- // // GlobalRouteManagerImpl Implementation @@ -359,13 +393,12 @@ GlobalRouteManagerImpl::BuildGlobalRoutingDatabase () for (uint32_t j = 0; j < numLSAs; ++j) { - GlobalRouterLSA* lsa = new GlobalRouterLSA (); + GlobalRoutingLSA* lsa = new GlobalRoutingLSA (); // // This is the call to actually fetch a Link State Advertisement from the // router. // rtr->GetLSA (j, *lsa); - NS_DEBUG ("LSA " << j); NS_DEBUG (*lsa); // // Write the newly discovered link state advertisement to the database. @@ -453,52 +486,86 @@ GlobalRouteManagerImpl::InitializeRoutes () GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) { SPFVertex* w = 0; - GlobalRouterLSA* w_lsa = 0; + GlobalRoutingLSA* w_lsa = 0; + GlobalRoutingLinkRecord *l = 0; uint32_t distance = 0; + uint32_t numRecordsInVertex = 0; NS_DEBUG ("GlobalRouteManagerImpl::SPFNext ()"); -// -// Always true for now, since all our LSAs are RouterLSAs. -// - if (v->GetVertexType () == SPFVertex::VertexRouter) + +// V points to a Router-LSA or Network-LSA +// Loop over the links in router LSA or attached routers in Network LSA + if (v->GetVertexType () == SPFVertex::VertexRouter) { - if (true) + numRecordsInVertex = v->GetLSA ()->GetNLinkRecords (); + } + if (v->GetVertexType () == SPFVertex::VertexNetwork) + { + numRecordsInVertex = v->GetLSA ()->GetNAttachedRouters (); + } + + for (uint32_t i = 0; i < numRecordsInVertex; i++) + { +// Get w_lsa: In case of V is Router-LSA + if (v->GetVertexType () == SPFVertex::VertexRouter) { NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " << v->GetLSA ()->GetNLinkRecords () << " link records"); // -// Walk the list of link records in the link state advertisement associated -// with the "current" router (represented by vertex ). -// - for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) - { -// // (a) If this is a link to a stub network, examine the next link in V's LSA. // Links to stub networks will be considered in the second stage of the // shortest path calculation. // - GlobalRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () == GlobalRouterLinkRecord::StubNetwork) - { - NS_DEBUG ("SPFNext: Found a Stub record to " << - l->GetLinkId ()); - continue; - } + l = v->GetLSA ()->GetLinkRecord (i); + if (l->GetLinkType () == GlobalRoutingLinkRecord::StubNetwork) + { + NS_DEBUG ("SPFNext: Found a Stub record to " << + l->GetLinkId ()); + continue; + } // // (b) Otherwise, W is a transit vertex (router or transit network). Look up // the vertex W's LSA (router-LSA or network-LSA) in Area A's link state // database. // - if (l->GetLinkType () == GlobalRouterLinkRecord::PointToPoint) - { + if (l->GetLinkType () == GlobalRoutingLinkRecord::PointToPoint) + { // // Lookup the link state advertisement of the new link -- we call it in // the link state database. // - w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); - NS_ASSERT (w_lsa); - NS_DEBUG ("SPFNext: Found a P2P record from " << - v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); + w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); + NS_ASSERT (w_lsa); + NS_DEBUG ("SPFNext: Found a P2P record from " << + v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); + } + else if (l->GetLinkType () == + GlobalRoutingLinkRecord::TransitNetwork) + { + w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); + NS_ASSERT (w_lsa); + NS_DEBUG ("SPFNext: Found a Transit record from " << + v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); + } + else + { + NS_ASSERT_MSG (0, "illegal Link Type"); + } + } +// Get w_lsa: In case of V is Network-LSA + if (v->GetVertexType () == SPFVertex::VertexNetwork) + { + w_lsa = m_lsdb->GetLSAByLinkData + (v->GetLSA ()->GetAttachedRouter (i)); + if (!w_lsa) + { + continue; + } + NS_DEBUG ("SPFNext: Found a Network LSA from " << + v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); + } + +// Note: w_lsa at this point may be either RouterLSA or NetworkLSA // // (c) If vertex W is already on the shortest-path tree, examine the next // link in the LSA. @@ -506,57 +573,56 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // If the link is to a router that is already in the shortest path first tree // then we have it covered -- ignore it. // - if (w_lsa->GetStatus () == - GlobalRouterLSA::LSA_SPF_IN_SPFTREE) - { - NS_DEBUG ("SPFNext: Skipping-> LSA "<< - w_lsa->GetLinkStateId () << " already in SPF tree"); - continue; - } -// -// The link is to a router we haven't dealt with yet. + if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_IN_SPFTREE) + { + NS_DEBUG ("SPFNext: Skipping-> LSA "<< + w_lsa->GetLinkStateId () << " already in SPF tree"); + continue; + } // // (d) Calculate the link state cost D of the resulting path from the root to // vertex W. D is equal to the sum of the link state cost of the (already // calculated) shortest path to vertex V and the advertised cost of the link // between vertices V and W. // - distance = v->GetDistanceFromRoot () + l->GetMetric (); + if (v->GetLSA ()->GetLSType () == GlobalRoutingLSA::RouterLSA) + { + distance = v->GetDistanceFromRoot () + l->GetMetric (); + } + else + { + distance = v->GetDistanceFromRoot (); + } - NS_DEBUG ("SPFNext: Considering w_lsa " << - w_lsa->GetLinkStateId ()); + NS_DEBUG ("SPFNext: Considering w_lsa " << w_lsa->GetLinkStateId ()); - if (w_lsa->GetStatus () == - GlobalRouterLSA::LSA_SPF_NOT_EXPLORED) - { -// -// If we haven't yet considered the link represented by we have to create -// a new SPFVertex to represent it. -// - w = new SPFVertex (w_lsa); -// +// Is there already vertex w in candidate list? + if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED) + { + +// prepare vertex w + w = new SPFVertex (w_lsa); +// Calculate nexthop to w // We need to figure out how to actually get to the new router represented // by . This will (among other things) find the next hop address to send // packets destined for this network to, and also find the outbound interface // used to forward the packets. // - if (SPFNexthopCalculation (v, w, l, distance)) - { - w_lsa->SetStatus ( - GlobalRouterLSA::LSA_SPF_CANDIDATE); + if (SPFNexthopCalculation (v, w, l, distance)) + { + w_lsa->SetStatus (GlobalRoutingLSA::LSA_SPF_CANDIDATE); // // Push this new vertex onto the priority queue (ordered by distance from the // root node). // - candidate.Push (w); - NS_DEBUG ("SPFNext: Pushing " << - w->GetVertexId () << ", parent vertexId: " << - v->GetVertexId ()); - } - } - } else if (w_lsa->GetStatus () == - GlobalRouterLSA::LSA_SPF_CANDIDATE) - { + candidate.Push (w); + NS_DEBUG ("SPFNext: Pushing " << + w->GetVertexId () << ", parent vertexId: " << + v->GetVertexId ()); + } + } + else if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_CANDIDATE) + { // // We have already considered the link represented by . What wse have to // do now is to decide if this new router represents a route with a shorter @@ -564,23 +630,23 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // // So, locate the vertex in the candidate queue and take a look at the // distance. - w = candidate.Find (w_lsa->GetLinkStateId ()); - if (w->GetDistanceFromRoot () < distance) - { + w = candidate.Find (w_lsa->GetLinkStateId ()); + if (w->GetDistanceFromRoot () < distance) + { // // This is not a shorter path, so don't do anything. // - continue; - } - else if (w->GetDistanceFromRoot () == distance) - { + continue; + } + else if (w->GetDistanceFromRoot () == distance) + { // // This path is one with an equal cost. Do nothing for now -- we're not doing // equal-cost multipath cases yet. // - } - else - { + } + else + { // // this path represents a new, lower-cost path to (the vertex we found in // the current link record of the link state advertisement of the current root @@ -589,27 +655,26 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) // N.B. the nexthop_calculation is conditional, if it finds a valid nexthop // it will call spf_add_parents, which will flush the old parents // - if (SPFNexthopCalculation (v, w, l, distance)) - { + if (SPFNexthopCalculation (v, w, l, distance)) + { // // If we've changed the cost to get to the vertex represented by , we // must reorder the priority queue keyed to that cost. // - candidate.Reorder (); - } - } - } // point-to-point - } // for loop - } - } + candidate.Reorder (); + } + } // new lower cost path found + } // end W is already on the candidate list + } // end loop over the links in V's LSA } // // This method is derived from quagga ospf_next_hop_calculation() 16.1.1. // -// Calculate the next hop IP address and the outgoing interface required to -// get packets from the root through (parent) to vertex (destination), -// over a given distance. +// Calculate nexthop from root through V (parent) to vertex W (destination) +// with given distance from root->W. +// +// As appropriate, set w's parent, distance, and nexthop information // // For now, this is greatly simplified from the quagga code // @@ -617,10 +682,19 @@ GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) GlobalRouteManagerImpl::SPFNexthopCalculation ( SPFVertex* v, SPFVertex* w, - GlobalRouterLinkRecord* l, + GlobalRoutingLinkRecord* l, uint32_t distance) { NS_DEBUG ("GlobalRouteManagerImpl::SPFNexthopCalculation ()"); + +// If w is a NetworkVertex, l should be null +/* + if (w->GetVertexType () == SPFVertex::VertexNetwork && l) + { + NS_ASSERT_MSG(0, "Error: SPFNexthopCalculation parameter problem"); + } +*/ + // // The vertex m_spfroot is a distinguished vertex representing the node at // the root of the calculations. That is, it is the node for which we are @@ -669,7 +743,8 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( // return the link record describing the link from to . Think of it as // SPFGetLink. // - GlobalRouterLinkRecord *linkRemote = 0; + NS_ASSERT(l); + GlobalRoutingLinkRecord *linkRemote = 0; linkRemote = SPFGetNextLink (w, v, linkRemote); // // At this point, is the Global Router Link Record describing the point- @@ -695,6 +770,56 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( v->GetVertexId () << " to " << w->GetVertexId () << " goes through next hop " << w->GetNextHop () << " via outgoing interface " << w->GetOutgoingInterfaceId ()); + } // end W is a router vertes + else + { + NS_ASSERT (w->GetVertexType () == SPFVertex::VertexNetwork); +// W is a directly connected network; no next hop is required + GlobalRoutingLSA* w_lsa = w->GetLSA (); + NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA); +// Find outgoing interface ID for this network + w->SetOutgoingInterfaceId ( + FindOutgoingInterfaceId (w_lsa->GetLinkStateId (), + w_lsa->GetNetworkLSANetworkMask () )); + w->SetDistanceFromRoot (distance); + w->SetParent (v); + NS_DEBUG ("SPFNexthopCalculation: Next hop from " << + v->GetVertexId () << " to network " << w->GetVertexId () << + " via outgoing interface " << w->GetOutgoingInterfaceId ()); + return 1; + } + } // end v is the root + else if (v->GetVertexType () == SPFVertex::VertexNetwork) + { +// See if any of v's parents are the root + if (v->GetParent () == m_spfroot) + { +// 16.1.1 para 5. ...the parent vertex is a network that +// directly connects the calculating router to the destination +// router. The list of next hops is then determined by +// examining the destination's router-LSA... + NS_ASSERT (w->GetVertexType () == SPFVertex::VertexRouter); + GlobalRoutingLinkRecord *linkRemote = 0; + while ((linkRemote = SPFGetNextLink (w, v, linkRemote))) + { +/* ...For each link in the router-LSA that points back to the + * parent network, the link's Link Data field provides the IP + * address of a next hop router. The outgoing interface to + * use can then be derived from the next hop IP address (or + * it can be inherited from the parent network). + */ + w->SetNextHop(linkRemote->GetLinkData ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); + NS_DEBUG ("SPFNexthopCalculation: Next hop from " << + v->GetVertexId () << " to " << w->GetVertexId () << + " goes through next hop " << w->GetNextHop () << + " via outgoing interface " << w->GetOutgoingInterfaceId ()); + } + } + else + { + w->SetNextHop (v->GetNextHop ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); } } else @@ -739,16 +864,17 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( // BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for // any link records after pre_link and not just after the first? // - GlobalRouterLinkRecord* + GlobalRoutingLinkRecord* GlobalRouteManagerImpl::SPFGetNextLink ( SPFVertex* v, SPFVertex* w, - GlobalRouterLinkRecord* prev_link) + GlobalRoutingLinkRecord* prev_link) { NS_DEBUG ("GlobalRouteManagerImpl::SPFGetNextLink ()"); bool skip = true; - GlobalRouterLinkRecord* l; + bool found_prev_link = false; + GlobalRoutingLinkRecord* l; // // If prev_link is 0, we are really looking for the first link, not the next // link. @@ -756,6 +882,7 @@ GlobalRouteManagerImpl::SPFGetNextLink ( if (prev_link == 0) { skip = false; + found_prev_link = true; } // // Iterate through the Global Router Link Records advertised by the vertex @@ -765,10 +892,6 @@ GlobalRouteManagerImpl::SPFGetNextLink ( for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) { l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () != GlobalRouterLinkRecord::PointToPoint) - { - continue; - } // // The link ID of a link record representing a point-to-point link is set to // the router ID of the neighboring router -- the router to which the link @@ -777,8 +900,16 @@ GlobalRouteManagerImpl::SPFGetNextLink ( // We're just checking to see if the link is actually the link from to // . // - if (l->GetLinkId () == w->GetVertexId ()) { - NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << + if (l->GetLinkId () == w->GetVertexId ()) + { + if (!found_prev_link) + { + NS_DEBUG ("SPFGetNextLink: Skipping links before prev_link found"); + found_prev_link = true; + continue; + } + + NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << l->GetLinkId () << " linkData = " << l->GetLinkData ()); // // If skip is false, don't (not too surprisingly) skip the link found -- it's @@ -849,7 +980,7 @@ GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root) // m_spfroot= v; v->SetDistanceFromRoot (0); - v->GetLSA ()->SetStatus (GlobalRouterLSA::LSA_SPF_IN_SPFTREE); + v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE); for (;;) { @@ -894,7 +1025,7 @@ GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root) // Update the status field of the vertex to indicate that it is in the SPF // tree. // - v->GetLSA ()->SetStatus (GlobalRouterLSA::LSA_SPF_IN_SPFTREE); + v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE); // // The current vertex has a parent pointer. By calling this rather oddly // named method (blame quagga) we add the current vertex to the list of @@ -932,7 +1063,18 @@ GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root) // through its point-to-point links, adding a *host* route to the local IP // address (at the side) for each of those links. // - SPFIntraAddRouter (v); + if (v->GetVertexType () == SPFVertex::VertexRouter) + { + SPFIntraAddRouter (v); + } + else if (v->GetVertexType () == SPFVertex::VertexNetwork) + { + SPFIntraAddTransit (v); + } + else + { + NS_ASSERT_MSG(0, "illegal SPFVertex type"); + } // // RFC2328 16.1. (5). // @@ -1025,6 +1167,80 @@ GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) return 0; } +// +// XXX This should probably be a method on Ipv4 +// +// Return the interface index corresponding to a given IP address +// + uint32_t +GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask) +{ +// +// We have an IP address and a vertex ID of the root of the SPF tree. +// The question is what interface index does this address correspond to. +// The answer is a little complicated since we have to find a pointer to +// the node corresponding to the vertex ID, find the Ipv4 interface on that +// node in order to iterate the interfaces and find the one corresponding to +// the address in question. +// + Ipv4Address routerId = m_spfroot->GetVertexId (); +// +// Walk the list of nodes in the system looking for the one corresponding to +// the node at the root of the SPF tree. This is the node for which we are +// building the routing table. +// + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (GlobalRouter::iid); +// +// If the node doesn't have a GlobalRouter interface it can't be the one +// we're interested in. +// + if (rtr == 0) + { + continue; + } + + if (rtr->GetRouterId () == routerId) + { +// +// This is the node we're building the routing table for. We're going to need +// the Ipv4 interface to look for the ipv4 interface index. Since this node +// is participating in routing IP version 4 packets, it certainly must have +// an Ipv4 interface. +// + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG (ipv4, + "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): " + "QI for interface failed"); +// +// Look through the interfaces on this node for one that has the IP address +// we're looking for. If we find one, return the corresponding interface +// index. +// + for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) + { + if (ipv4->GetAddress (i).CombineMask(amask) == + a.CombineMask(amask) ) + { + NS_DEBUG ( + "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): " + "Interface match for " << a); + return i; + } + } + } + } +// +// Couldn't find it. +// + return 0; +} + // // This method is derived from quagga ospf_intra_add_router () // @@ -1109,7 +1325,7 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // Link Records corresponding to links off of that vertex / node. We're going // to be interested in the records corresponding to point-to-point links. // - GlobalRouterLSA *lsa = v->GetLSA (); + GlobalRoutingLSA *lsa = v->GetLSA (); NS_ASSERT_MSG (lsa, "GlobalRouteManagerImpl::SPFIntraAddRouter (): " "Expected valid LSA in SPFVertex* v"); @@ -1128,8 +1344,8 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // // We are only concerned about point-to-point links // - GlobalRouterLinkRecord *lr = lsa->GetLinkRecord (j); - if (lr->GetLinkType () != GlobalRouterLinkRecord::PointToPoint) + GlobalRoutingLinkRecord *lr = lsa->GetLinkRecord (j); + if (lr->GetLinkType () != GlobalRoutingLinkRecord::PointToPoint) { continue; } @@ -1162,6 +1378,91 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) } } } + void +GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v) +{ + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit ()"); + + NS_ASSERT_MSG (m_spfroot, + "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set"); +// +// The root of the Shortest Path First tree is the router to which we are +// going to write the actual routing table entries. The vertex corresponding +// to this router has a vertex ID which is the router ID of that node. We're +// going to use this ID to discover which node it is that we're actually going +// to update. +// + Ipv4Address routerId = m_spfroot->GetVertexId (); + + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): " + "Vertex ID = " << routerId); +// +// We need to walk the list of nodes looking for the one that has the router +// ID corresponding to the root vertex. This is the one we're going to write +// the routing information to. +// + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) + { + Ptr node = *i; +// +// The router ID is accessible through the GlobalRouter interface, so we need +// to QI for that interface. If there's no GlobalRouter interface, the node +// in question cannot be the router we want, so we continue. +// + Ptr rtr = + node->QueryInterface (GlobalRouter::iid); + + if (rtr == 0) + { + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): " + "No GlobalRouter interface on node " << node->GetId ()); + continue; + } +// +// If the router ID of the current node is equal to the router ID of the +// root of the SPF tree, then this node is the one for which we need to +// write the routing tables. +// + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): " + "Considering router " << rtr->GetRouterId ()); + + if (rtr->GetRouterId () == routerId) + { + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): " + "setting routes for node " << node->GetId ()); +// +// Routing information is updated using the Ipv4 interface. We need to QI +// for that interface. If the node is acting as an IP version 4 router, it +// should absolutely have an Ipv4 interface. +// + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG (ipv4, + "GlobalRouteManagerImpl::SPFIntraAddTransit (): " + "QI for interface failed"); +// +// Get the Global Router Link State Advertisement from the vertex we're +// adding the routes to. The LSA will have a number of attached Global Router +// Link Records corresponding to links off of that vertex / node. We're going +// to be interested in the records corresponding to point-to-point links. +// + GlobalRoutingLSA *lsa = v->GetLSA (); + NS_ASSERT_MSG (lsa, + "GlobalRouteManagerImpl::SPFIntraAddTransit (): " + "Expected valid LSA in SPFVertex* v"); + Ipv4Mask tempmask = v->GetLSA ()->GetNetworkLSANetworkMask (); + Ipv4Address tempip = v->GetLSA ()->GetLinkStateId (); + tempip = tempip.CombineMask (tempmask); + ipv4->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), + v->GetOutgoingInterfaceId ()); + NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddNetwork (): " + " Node " << node->GetId () << + " add network route to " << tempip << + " using next hop " << v->GetNextHop () << + " via interface " << v->GetOutgoingInterfaceId ()); + } + } +} // Derived from quagga ospf_vertex_add_parents () // @@ -1275,81 +1576,81 @@ GlobalRouteManagerImplTest::RunTests (void) // link2: 10.1.3.1/30, 10.1.3.2/30 // // Router 0 - GlobalRouterLinkRecord* lr0 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::PointToPoint, + GlobalRoutingLinkRecord* lr0 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::PointToPoint, "0.0.0.2", // router ID 0.0.0.2 "10.1.1.1", // local ID 1); // metric - GlobalRouterLinkRecord* lr1 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::StubNetwork, + GlobalRoutingLinkRecord* lr1 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::StubNetwork, "10.1.1.1", "255.255.255.252", 1); - GlobalRouterLSA* lsa0 = new GlobalRouterLSA (); + GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA (); lsa0->SetLinkStateId ("0.0.0.0"); lsa0->SetAdvertisingRouter ("0.0.0.0"); lsa0->AddLinkRecord (lr0); lsa0->AddLinkRecord (lr1); // Router 1 - GlobalRouterLinkRecord* lr2 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::PointToPoint, + GlobalRoutingLinkRecord* lr2 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::PointToPoint, "0.0.0.2", "10.1.2.1", 1); - GlobalRouterLinkRecord* lr3 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::StubNetwork, + GlobalRoutingLinkRecord* lr3 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::StubNetwork, "10.1.2.1", "255.255.255.252", 1); - GlobalRouterLSA* lsa1 = new GlobalRouterLSA (); + GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA (); lsa1->SetLinkStateId ("0.0.0.1"); lsa1->SetAdvertisingRouter ("0.0.0.1"); lsa1->AddLinkRecord (lr2); lsa1->AddLinkRecord (lr3); // Router 2 - GlobalRouterLinkRecord* lr4 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::PointToPoint, + GlobalRoutingLinkRecord* lr4 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::PointToPoint, "0.0.0.0", "10.1.1.2", 1); - GlobalRouterLinkRecord* lr5 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::StubNetwork, + GlobalRoutingLinkRecord* lr5 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::StubNetwork, "10.1.1.2", "255.255.255.252", 1); - GlobalRouterLinkRecord* lr6 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::PointToPoint, + GlobalRoutingLinkRecord* lr6 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::PointToPoint, "0.0.0.1", "10.1.2.2", 1); - GlobalRouterLinkRecord* lr7 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::StubNetwork, + GlobalRoutingLinkRecord* lr7 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::StubNetwork, "10.1.2.2", "255.255.255.252", 1); - GlobalRouterLinkRecord* lr8 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::PointToPoint, + GlobalRoutingLinkRecord* lr8 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::PointToPoint, "0.0.0.3", "10.1.3.2", 1); - GlobalRouterLinkRecord* lr9 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::StubNetwork, + GlobalRoutingLinkRecord* lr9 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::StubNetwork, "10.1.3.2", "255.255.255.252", 1); - GlobalRouterLSA* lsa2 = new GlobalRouterLSA (); + GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA (); lsa2->SetLinkStateId ("0.0.0.2"); lsa2->SetAdvertisingRouter ("0.0.0.2"); lsa2->AddLinkRecord (lr4); @@ -1360,19 +1661,19 @@ GlobalRouteManagerImplTest::RunTests (void) lsa2->AddLinkRecord (lr9); // Router 3 - GlobalRouterLinkRecord* lr10 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::PointToPoint, + GlobalRoutingLinkRecord* lr10 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::PointToPoint, "0.0.0.2", "10.1.2.1", 1); - GlobalRouterLinkRecord* lr11 = new GlobalRouterLinkRecord ( - GlobalRouterLinkRecord::StubNetwork, + GlobalRoutingLinkRecord* lr11 = new GlobalRoutingLinkRecord ( + GlobalRoutingLinkRecord::StubNetwork, "10.1.2.1", "255.255.255.252", 1); - GlobalRouterLSA* lsa3 = new GlobalRouterLSA (); + GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA (); lsa3->SetLinkStateId ("0.0.0.3"); lsa3->SetAdvertisingRouter ("0.0.0.3"); lsa3->AddLinkRecord (lr10); diff --git a/src/routing/global-routing/global-route-manager-impl.h b/src/routing/global-routing/global-route-manager-impl.h index 7979cb4a2..739e20592 100644 --- a/src/routing/global-routing/global-route-manager-impl.h +++ b/src/routing/global-routing/global-route-manager-impl.h @@ -102,10 +102,10 @@ public: * * @see SPFVertex::SPFVertex () * @see VertexType - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @param lsa The Link State Advertisement used for finding initial values. */ - SPFVertex(GlobalRouterLSA* lsa); + SPFVertex(GlobalRoutingLSA* lsa); /** * @brief Destroy an SPFVertex (Shortest Path First Vertex). @@ -181,12 +181,12 @@ public: * @internal * * @see GlobalRouter - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @see GlobalRouter::DiscoverLSAs () - * @returns A pointer to the GlobalRouterLSA found by the router represented + * @returns A pointer to the GlobalRoutingLSA found by the router represented * by this SPFVertex object. */ - GlobalRouterLSA* GetLSA (void) const; + GlobalRoutingLSA* GetLSA (void) const; /** * @brief Set the Global Router Link State Advertisement returned by the @@ -196,13 +196,13 @@ public: * * @see SPFVertex::GetLSA () * @see GlobalRouter - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @see GlobalRouter::DiscoverLSAs () * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You * must not delete the LSA after calling this method. - * @param lsa A pointer to the GlobalRouterLSA. + * @param lsa A pointer to the GlobalRoutingLSA. */ - void SetLSA (GlobalRouterLSA* lsa); + void SetLSA (GlobalRoutingLSA* lsa); /** * @brief Get the distance from the root vertex to "this" SPFVertex object. @@ -283,8 +283,8 @@ public: * SPFVertex." * * @see GlobalRouter - * @see GlobalRouterLSA - * @see GlobalRouterLinkRecord + * @see GlobalRoutingLSA + * @see GlobalRoutingLinkRecord * @returns The interface index to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ @@ -325,8 +325,8 @@ public: * by "this" SPFVertex. * * @see GlobalRouter - * @see GlobalRouterLSA - * @see GlobalRouterLinkRecord + * @see GlobalRoutingLSA + * @see GlobalRoutingLinkRecord * @param id The interface index to use when forwarding packets to the host or * network represented by "this" SPFVertex. */ @@ -368,8 +368,8 @@ public: * by 'this' SPFVertex." * * @see GlobalRouter - * @see GlobalRouterLSA - * @see GlobalRouterLinkRecord + * @see GlobalRoutingLSA + * @see GlobalRoutingLinkRecord * @returns The IP address to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ @@ -411,8 +411,8 @@ public: * host represented by 'this' SPFVertex." * * @see GlobalRouter - * @see GlobalRouterLSA - * @see GlobalRouterLinkRecord + * @see GlobalRoutingLSA + * @see GlobalRoutingLinkRecord * @param nextHop The IP address to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ @@ -543,7 +543,7 @@ public: private: VertexType m_vertexType; Ipv4Address m_vertexId; - GlobalRouterLSA* m_lsa; + GlobalRoutingLSA* m_lsa; uint32_t m_distanceFromRoot; uint32_t m_rootOif; Ipv4Address m_nextHop; @@ -604,33 +604,47 @@ public: * State Database. * @internal * - * The IPV4 address and the GlobalRouterLSA given as parameters are converted + * The IPV4 address and the GlobalRoutingLSA given as parameters are converted * to an STL pair and are inserted into the database map. * - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @see Ipv4Address * @param addr The IP address associated with the LSA. Typically the Router * ID. * @param lsa A pointer to the Link State Advertisement for the router. */ - void Insert(Ipv4Address addr, GlobalRouterLSA* lsa); + void Insert(Ipv4Address addr, GlobalRoutingLSA* lsa); /** * @brief Look up the Link State Advertisement associated with the given - * IP Address. + * link state ID (address). * @internal * * The database map is searched for the given IPV4 address and corresponding - * GlobalRouterLSA is returned. + * GlobalRoutingLSA is returned. * - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @see Ipv4Address * @param addr The IP address associated with the LSA. Typically the Router * ID. * @returns A pointer to the Link State Advertisement for the router specified * by the IP address addr. */ - GlobalRouterLSA* GetLSA (Ipv4Address addr) const; + GlobalRoutingLSA* GetLSA (Ipv4Address addr) const; +/** + * @brief Look up the Link State Advertisement associated with the given + * link state ID (address). This is a variation of the GetLSA call + * to allow the LSA to be found by matching addr with the LinkData field + * of the TransitNetwork link record. + * @internal + * + * @see GetLSA + * @param addr The IP address associated with the LSA. Typically the Router + * @returns A pointer to the Link State Advertisement for the router specified + * by the IP address addr. + * ID. + */ + GlobalRoutingLSA* GetLSAByLinkData (Ipv4Address addr) const; /** * @brief Set all LSA flags to an initialized state, for SPF computation @@ -641,14 +655,14 @@ public: * prior to each SPF calculation to reset the state of the SPFVertex structures * that will reference the LSAs during the calculation. * - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @see SPFVertex */ void Initialize (); private: - typedef std::map LSDBMap_t; - typedef std::pair LSDBPair_t; + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; LSDBMap_t m_database; /** @@ -734,12 +748,14 @@ private: void SPFCalculate (Ipv4Address root); void SPFNext (SPFVertex*, CandidateQueue&); int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, - GlobalRouterLinkRecord* l, uint32_t distance); + GlobalRoutingLinkRecord* l, uint32_t distance); void SPFVertexAddParent (SPFVertex* v); - GlobalRouterLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w, - GlobalRouterLinkRecord* prev_link); + GlobalRoutingLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w, + GlobalRoutingLinkRecord* prev_link); void SPFIntraAddRouter (SPFVertex* v); + void SPFIntraAddTransit (SPFVertex* v); uint32_t FindOutgoingInterfaceId (Ipv4Address a); + uint32_t FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask); }; } // namespace ns3 diff --git a/src/routing/global-routing/global-router-interface.cc b/src/routing/global-routing/global-router-interface.cc index 778d91bcc..c057f9ddf 100644 --- a/src/routing/global-routing/global-router-interface.cc +++ b/src/routing/global-routing/global-router-interface.cc @@ -28,21 +28,21 @@ namespace ns3 { // --------------------------------------------------------------------------- // -// GlobalRouterLinkRecord Implementation +// GlobalRoutingLinkRecord Implementation // // --------------------------------------------------------------------------- -GlobalRouterLinkRecord::GlobalRouterLinkRecord () +GlobalRoutingLinkRecord::GlobalRoutingLinkRecord () : m_linkId ("0.0.0.0"), m_linkData ("0.0.0.0"), m_linkType (Unknown), m_metric (0) { - NS_DEBUG("GlobalRouterLinkRecord::GlobalRouterLinkRecord ()"); + NS_DEBUG("GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()"); } -GlobalRouterLinkRecord::GlobalRouterLinkRecord ( +GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ( LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, @@ -53,116 +53,126 @@ GlobalRouterLinkRecord::GlobalRouterLinkRecord ( m_linkType (linkType), m_metric (metric) { - NS_DEBUG("GlobalRouterLinkRecord::GlobalRouterLinkRecord (" << + NS_DEBUG("GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (" << linkType << ", " << linkId << ", " << linkData << ", " << metric << ")"); } -GlobalRouterLinkRecord::~GlobalRouterLinkRecord () +GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord () { - NS_DEBUG("GlobalRouterLinkRecord::~GlobalRouterLinkRecord ()"); + NS_DEBUG("GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()"); } Ipv4Address -GlobalRouterLinkRecord::GetLinkId (void) const +GlobalRoutingLinkRecord::GetLinkId (void) const { - NS_DEBUG("GlobalRouterLinkRecord::GetLinkId ()"); + NS_DEBUG("GlobalRoutingLinkRecord::GetLinkId ()"); return m_linkId; } void -GlobalRouterLinkRecord::SetLinkId (Ipv4Address addr) +GlobalRoutingLinkRecord::SetLinkId (Ipv4Address addr) { - NS_DEBUG("GlobalRouterLinkRecord::SetLinkId ()"); + NS_DEBUG("GlobalRoutingLinkRecord::SetLinkId ()"); m_linkId = addr; } Ipv4Address -GlobalRouterLinkRecord::GetLinkData (void) const +GlobalRoutingLinkRecord::GetLinkData (void) const { - NS_DEBUG("GlobalRouterLinkRecord::GetLinkData ()"); + NS_DEBUG("GlobalRoutingLinkRecord::GetLinkData ()"); return m_linkData; } void -GlobalRouterLinkRecord::SetLinkData (Ipv4Address addr) +GlobalRoutingLinkRecord::SetLinkData (Ipv4Address addr) { - NS_DEBUG("GlobalRouterLinkRecord::SetLinkData ()"); + NS_DEBUG("GlobalRoutingLinkRecord::SetLinkData ()"); m_linkData = addr; } - GlobalRouterLinkRecord::LinkType -GlobalRouterLinkRecord::GetLinkType (void) const + GlobalRoutingLinkRecord::LinkType +GlobalRoutingLinkRecord::GetLinkType (void) const { - NS_DEBUG("GlobalRouterLinkRecord::GetLinkType ()"); + NS_DEBUG("GlobalRoutingLinkRecord::GetLinkType ()"); return m_linkType; } void -GlobalRouterLinkRecord::SetLinkType ( - GlobalRouterLinkRecord::LinkType linkType) +GlobalRoutingLinkRecord::SetLinkType ( + GlobalRoutingLinkRecord::LinkType linkType) { - NS_DEBUG("GlobalRouterLinkRecord::SetLinkType ()"); + NS_DEBUG("GlobalRoutingLinkRecord::SetLinkType ()"); m_linkType = linkType; } uint32_t -GlobalRouterLinkRecord::GetMetric (void) const +GlobalRoutingLinkRecord::GetMetric (void) const { - NS_DEBUG("GlobalRouterLinkRecord::GetMetric ()"); + NS_DEBUG("GlobalRoutingLinkRecord::GetMetric ()"); return m_metric; } void -GlobalRouterLinkRecord::SetMetric (uint32_t metric) +GlobalRoutingLinkRecord::SetMetric (uint32_t metric) { - NS_DEBUG("GlobalRouterLinkRecord::SetMetric ()"); + NS_DEBUG("GlobalRoutingLinkRecord::SetMetric ()"); m_metric = metric; } // --------------------------------------------------------------------------- // -// GlobalRouterLSA Implementation +// GlobalRoutingLSA Implementation // // --------------------------------------------------------------------------- -GlobalRouterLSA::GlobalRouterLSA() +GlobalRoutingLSA::GlobalRoutingLSA() : + m_lsType (GlobalRoutingLSA::Unknown), m_linkStateId("0.0.0.0"), m_advertisingRtr("0.0.0.0"), m_linkRecords(), - m_status(GlobalRouterLSA::LSA_SPF_NOT_EXPLORED) + m_networkLSANetworkMask("0.0.0.0"), + m_attachedRouters(), + m_status(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED) { - NS_DEBUG("GlobalRouterLSA::GlobalRouterLSA ()"); + NS_DEBUG("GlobalRoutingLSA::GlobalRoutingLSA ()"); } -GlobalRouterLSA::GlobalRouterLSA ( - GlobalRouterLSA::SPFStatus status, +GlobalRoutingLSA::GlobalRoutingLSA ( + GlobalRoutingLSA::SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr) : + m_lsType (GlobalRoutingLSA::Unknown), m_linkStateId(linkStateId), m_advertisingRtr(advertisingRtr), m_linkRecords(), + m_networkLSANetworkMask("0.0.0.0"), + m_attachedRouters(), m_status(status) { - NS_DEBUG("GlobalRouterLSA::GlobalRouterLSA (" << status << ", " << + NS_DEBUG("GlobalRoutingLSA::GlobalRoutingLSA (" << status << ", " << linkStateId << ", " << advertisingRtr << ")"); } -GlobalRouterLSA::GlobalRouterLSA (GlobalRouterLSA& lsa) - : m_linkStateId(lsa.m_linkStateId), m_advertisingRtr(lsa.m_advertisingRtr), +GlobalRoutingLSA::GlobalRoutingLSA (GlobalRoutingLSA& lsa) + : m_lsType(lsa.m_lsType), m_linkStateId(lsa.m_linkStateId), + m_advertisingRtr(lsa.m_advertisingRtr), + m_networkLSANetworkMask(lsa.m_networkLSANetworkMask), m_status(lsa.m_status) { NS_ASSERT_MSG(IsEmpty(), - "GlobalRouterLSA::GlobalRouterLSA (): Non-empty LSA in constructor"); + "GlobalRoutingLSA::GlobalRoutingLSA (): Non-empty LSA in constructor"); CopyLinkRecords (lsa); } - GlobalRouterLSA& -GlobalRouterLSA::operator= (const GlobalRouterLSA& lsa) + GlobalRoutingLSA& +GlobalRoutingLSA::operator= (const GlobalRoutingLSA& lsa) { + m_lsType = lsa.m_lsType; m_linkStateId = lsa.m_linkStateId; m_advertisingRtr = lsa.m_advertisingRtr; + m_networkLSANetworkMask = lsa.m_networkLSANetworkMask, m_status = lsa.m_status; ClearLinkRecords (); @@ -171,14 +181,14 @@ GlobalRouterLSA::operator= (const GlobalRouterLSA& lsa) } void -GlobalRouterLSA::CopyLinkRecords (const GlobalRouterLSA& lsa) +GlobalRoutingLSA::CopyLinkRecords (const GlobalRoutingLSA& lsa) { for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin (); i != lsa.m_linkRecords.end (); i++) { - GlobalRouterLinkRecord *pSrc = *i; - GlobalRouterLinkRecord *pDst = new GlobalRouterLinkRecord; + GlobalRoutingLinkRecord *pSrc = *i; + GlobalRoutingLinkRecord *pDst = new GlobalRoutingLinkRecord; pDst->SetLinkType (pSrc->GetLinkType ()); pDst->SetLinkId (pSrc->GetLinkId ()); @@ -187,48 +197,50 @@ GlobalRouterLSA::CopyLinkRecords (const GlobalRouterLSA& lsa) m_linkRecords.push_back(pDst); pDst = 0; } + + m_attachedRouters = lsa.m_attachedRouters; } -GlobalRouterLSA::~GlobalRouterLSA() +GlobalRoutingLSA::~GlobalRoutingLSA() { - NS_DEBUG("GlobalRouterLSA::~GlobalRouterLSA ()"); + NS_DEBUG("GlobalRoutingLSA::~GlobalRoutingLSA ()"); ClearLinkRecords (); } void -GlobalRouterLSA::ClearLinkRecords(void) +GlobalRoutingLSA::ClearLinkRecords(void) { for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin (); i != m_linkRecords.end (); i++) { - NS_DEBUG("GlobalRouterLSA::ClearLinkRecords (): free link record"); + NS_DEBUG("GlobalRoutingLSA::ClearLinkRecords (): free link record"); - GlobalRouterLinkRecord *p = *i; + GlobalRoutingLinkRecord *p = *i; delete p; p = 0; *i = 0; } - NS_DEBUG("GlobalRouterLSA::ClearLinkRecords(): clear list"); + NS_DEBUG("GlobalRoutingLSA::ClearLinkRecords(): clear list"); m_linkRecords.clear(); } uint32_t -GlobalRouterLSA::AddLinkRecord (GlobalRouterLinkRecord* lr) +GlobalRoutingLSA::AddLinkRecord (GlobalRoutingLinkRecord* lr) { m_linkRecords.push_back (lr); return m_linkRecords.size (); } uint32_t -GlobalRouterLSA::GetNLinkRecords (void) const +GlobalRoutingLSA::GetNLinkRecords (void) const { return m_linkRecords.size (); } - GlobalRouterLinkRecord * -GlobalRouterLSA::GetLinkRecord (uint32_t n) const + GlobalRoutingLinkRecord * +GlobalRoutingLSA::GetLinkRecord (uint32_t n) const { uint32_t j = 0; for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin (); @@ -240,70 +252,146 @@ GlobalRouterLSA::GetLinkRecord (uint32_t n) const return *i; } } - NS_ASSERT_MSG(false, "GlobalRouterLSA::GetLinkRecord (): invalid index"); + NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index"); return 0; } bool -GlobalRouterLSA::IsEmpty (void) const +GlobalRoutingLSA::IsEmpty (void) const { return m_linkRecords.size () == 0; } + GlobalRoutingLSA::LSType +GlobalRoutingLSA::GetLSType (void) const +{ + return m_lsType; +} + + void +GlobalRoutingLSA::SetLSType (GlobalRoutingLSA::LSType typ) +{ + m_lsType = typ; +} + Ipv4Address -GlobalRouterLSA::GetLinkStateId (void) const +GlobalRoutingLSA::GetLinkStateId (void) const { return m_linkStateId; } void -GlobalRouterLSA::SetLinkStateId (Ipv4Address addr) +GlobalRoutingLSA::SetLinkStateId (Ipv4Address addr) { m_linkStateId = addr; } Ipv4Address -GlobalRouterLSA::GetAdvertisingRouter (void) const +GlobalRoutingLSA::GetAdvertisingRouter (void) const { return m_advertisingRtr; } void -GlobalRouterLSA::SetAdvertisingRouter (Ipv4Address addr) +GlobalRoutingLSA::SetAdvertisingRouter (Ipv4Address addr) { m_advertisingRtr = addr; } - GlobalRouterLSA::SPFStatus -GlobalRouterLSA::GetStatus (void) const + void +GlobalRoutingLSA::SetNetworkLSANetworkMask (Ipv4Mask mask) +{ + m_networkLSANetworkMask = mask; +} + + Ipv4Mask +GlobalRoutingLSA::GetNetworkLSANetworkMask (void) const +{ + return m_networkLSANetworkMask; +} + + GlobalRoutingLSA::SPFStatus +GlobalRoutingLSA::GetStatus (void) const { return m_status; } + uint32_t +GlobalRoutingLSA::AddAttachedRouter (Ipv4Address addr) +{ + m_attachedRouters.push_back (addr); + return m_attachedRouters.size (); +} + + uint32_t +GlobalRoutingLSA::GetNAttachedRouters (void) const +{ + return m_attachedRouters.size (); +} + + Ipv4Address +GlobalRoutingLSA::GetAttachedRouter (uint32_t n) const +{ + uint32_t j = 0; + for ( ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin (); + i != m_attachedRouters.end (); + i++, j++) + { + if (j == n) + { + return *i; + } + } + NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetAttachedRouter (): invalid index"); + return Ipv4Address("0.0.0.0"); +} + void -GlobalRouterLSA::SetStatus (GlobalRouterLSA::SPFStatus status) +GlobalRoutingLSA::SetStatus (GlobalRoutingLSA::SPFStatus status) { m_status = status; } void -GlobalRouterLSA::Print (std::ostream &os) const +GlobalRoutingLSA::Print (std::ostream &os) const { - os << "m_linkStateId = " << m_linkStateId << std::endl << + os << "m_lsType = " << m_lsType << std::endl << + "m_linkStateId = " << m_linkStateId << std::endl << "m_advertisingRtr = " << m_advertisingRtr << std::endl; - for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin (); - i != m_linkRecords.end (); - i++) + if (m_lsType == GlobalRoutingLSA::RouterLSA) + { + for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin (); + i != m_linkRecords.end (); + i++) + { + GlobalRoutingLinkRecord *p = *i; + os << "----------" << std::endl; + os << "m_linkId = " << p->GetLinkId () << std::endl; + os << "m_linkData = " << p->GetLinkData () << std::endl; + } + } + else if (m_lsType == GlobalRoutingLSA::NetworkLSA) { - GlobalRouterLinkRecord *p = *i; os << "----------" << std::endl; - os << "m_linkId = " << p->GetLinkId () << std::endl; - os << "m_linkData = " << p->GetLinkData () << std::endl; + os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask + << std::endl; + for ( ListOfAttachedRouters_t::const_iterator i = + m_attachedRouters.begin (); + i != m_attachedRouters.end (); + i++) + { + Ipv4Address p = *i; + os << "attachedRouter = " << p << std::endl; + } + } + else + { + NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType); } } -std::ostream& operator<< (std::ostream& os, GlobalRouterLSA& lsa) +std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa) { lsa.Print (os); return os; @@ -350,7 +438,7 @@ GlobalRouter::ClearLSAs () { NS_DEBUG("GlobalRouter::ClearLSAs (): free LSA"); - GlobalRouterLSA *p = *i; + GlobalRoutingLSA *p = *i; delete p; p = 0; @@ -373,11 +461,16 @@ GlobalRouter::GetRouterId (void) const uint32_t GlobalRouter::DiscoverLSAs (void) { - NS_DEBUG("GlobalRouter::DiscoverLSAs ()"); + NS_DEBUG("GlobalRouter::DiscoverLSAs () for node " << m_node->GetId () ); NS_ASSERT_MSG(m_node, "GlobalRouter::DiscoverLSAs (): interface not set"); ClearLSAs (); + +// While building the router-LSA, keep a list of those NetDevices for +// which I am the designated router and need to later build a NetworkLSA + std::list > listOfDRInterfaces; + // // We're aggregated to a node. We need to ask the node for a pointer to its // Ipv4 interface. This is where the information regarding the attached @@ -387,118 +480,252 @@ GlobalRouter::DiscoverLSAs (void) NS_ASSERT_MSG(ipv4Local, "GlobalRouter::DiscoverLSAs (): QI for interface failed"); // -// We are, for now at least, only going to report RouterLSAs in this method. -// What this means is that there is going to be one advertisement with some -// number of link records. This means that GetNumLSAs will actually always -// return exactly one. +// Each node originates a Router-LSA // - GlobalRouterLSA *pLSA = new GlobalRouterLSA; + GlobalRoutingLSA *pLSA = new GlobalRoutingLSA; + pLSA->SetLSType (GlobalRoutingLSA::RouterLSA); pLSA->SetLinkStateId (m_routerId); pLSA->SetAdvertisingRouter (m_routerId); - pLSA->SetStatus (GlobalRouterLSA::LSA_SPF_NOT_EXPLORED); + pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); // // We need to ask the node for the number of net devices attached. This isn't // necessarily equal to the number of links to adjacent nodes (other routers) // as the number of devices may include those for stub networks (e.g., -// ethernets, etc.). So we have to walk through the list of net devices and -// pay attention to those that are directly connected to another router through -// a point-to-point channel. +// ethernets, etc.). // uint32_t numDevices = m_node->GetNDevices(); NS_DEBUG("GlobalRouter::DiscoverLSAs (): numDevices = " << numDevices); -// -// Loop through the devices looking for those connected to a point-to-point -// channel. -// for (uint32_t i = 0; i < numDevices; ++i) { Ptr ndLocal = m_node->GetDevice(i); - if (!ndLocal->IsPointToPoint ()) + if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () ) { - NS_DEBUG("GlobalRouter::DiscoverLSAs (): non-point-to-point device"); - continue; - } - - NS_DEBUG("GlobalRouter::DiscoverLSAs (): Point-to-point device"); + NS_DEBUG("GlobalRouter::DiscoverLSAs (): broadcast link"); + GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord; +// +// We need to determine whether we are on a transit or stub network +// If we find at least one more router on this channel, we are a transit +// // // Now, we have to find the Ipv4 interface whose netdevice is the one we // just found. This is still the IP on the local side of the channel. There // is a function to do this used down in the guts of the stack, but it's not // exported so we had to whip up an equivalent. // - uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal); -// -// Now that we have the Ipv4 interface index, we can get the address and mask -// we need. -// - Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); - Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); - NS_DEBUG("Working with local address " << addrLocal); + uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal); + Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); + Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); + NS_DEBUG("Working with local address " << addrLocal); // // Now, we're going to walk over to the remote net device on the other end of // the point-to-point channel we now know we have. This is where our adjacent // router (to use OSPF lingo) is running. // - Ptr ch = ndLocal->GetChannel(); - Ptr ndRemote = GetAdjacent(ndLocal, ch); + Ptr ch = ndLocal->GetChannel(); + uint32_t nDevices = ch->GetNDevices(); + if (nDevices == 1) + { + // This is a stub broadcast interface + NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA stub broadcast link"); + // XXX in future, need to consider if >1 includes other routers + plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork); + // Link ID is IP network number of attached network + plr->SetLinkId (addrLocal.CombineMask(maskLocal)); + // Link Data is network mask; convert to Ipv4Address + Ipv4Address maskLocalAddr; + maskLocalAddr.Set(maskLocal.GetHostOrder ()); + plr->SetLinkData (maskLocalAddr); + // Cost is interface's configured output cost (NOTYET) + plr->SetMetric (1); + pLSA->AddLinkRecord(plr); + plr = 0; + continue; + } + else + { + NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA Broadcast link"); + // multiple routers on a broadcast interface + // lowest IP address is designated router + plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork); + // Link ID is IP interface address of designated router + Ipv4Address desigRtr = + FindDesignatedRouterForLink (m_node, ndLocal); + if (desigRtr == addrLocal) + { + listOfDRInterfaces.push_back (ndLocal); + NS_DEBUG("GlobalRouter::DiscoverLSAs (): " << + m_node->GetId () << " is a DR"); + } + plr->SetLinkId (desigRtr); + // Link Data is router's own IP address + plr->SetLinkData (addrLocal); + // Cost is interface's configured output cost (NOTYET) + plr->SetMetric (1); + pLSA->AddLinkRecord (plr); + plr = 0; + continue; + } + } + else if (ndLocal->IsPointToPoint () ) + { + NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA Point-to-point device"); +// +// Now, we have to find the Ipv4 interface whose netdevice is the one we +// just found. This is still the IP on the local side of the channel. There +// is a function to do this used down in the guts of the stack, but it's not +// exported so we had to whip up an equivalent. +// + uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal); +// +// Now that we have the Ipv4 interface index, we can get the address and mask +// we need. +// + Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); + Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); + NS_DEBUG("Working with local address " << addrLocal); +// +// Now, we're going to walk over to the remote net device on the other end of +// the point-to-point channel we now know we have. This is where our adjacent +// router (to use OSPF lingo) is running. +// + Ptr ch = ndLocal->GetChannel(); + Ptr ndRemote = GetAdjacent(ndLocal, ch); // // The adjacent net device is aggregated to a node. We need to ask that net // device for its node, then ask that node for its Ipv4 interface. // - Ptr nodeRemote = ndRemote->GetNode(); - Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG(ipv4Remote, - "GlobalRouter::DiscoverLSAs (): QI for remote failed"); + Ptr nodeRemote = ndRemote->GetNode(); + Ptr ipv4Remote = nodeRemote->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG(ipv4Remote, + "GlobalRouter::DiscoverLSAs (): QI for remote failed"); // // Per the OSPF spec, we're going to need the remote router ID, so we might as // well get it now. // - Ptr srRemote = - nodeRemote->QueryInterface (GlobalRouter::iid); - NS_ASSERT_MSG(srRemote, - "GlobalRouter::DiscoverLSAs (): QI for remote failed"); - Ipv4Address rtrIdRemote = srRemote->GetRouterId(); - NS_DEBUG("Working with remote router " << rtrIdRemote); + Ptr srRemote = + nodeRemote->QueryInterface (GlobalRouter::iid); + NS_ASSERT_MSG(srRemote, + "GlobalRouter::DiscoverLSAs():QI for remote failed"); + Ipv4Address rtrIdRemote = srRemote->GetRouterId(); + NS_DEBUG("Working with remote router " << rtrIdRemote); // // Now, just like we did above, we need to get the IP interface index for the // net device on the other end of the point-to-point channel. // - uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote); + uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote); // // Now that we have the Ipv4 interface, we can get the (remote) address and // mask we need. // - Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote); - Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); - NS_DEBUG("Working with remote address " << addrRemote); + Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote); + Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote); + NS_DEBUG("Working with remote address " << addrRemote); // // Now we can fill out the link records for this link. There are always two // link records; the first is a point-to-point record describing the link and // the second is a stub network record with the network number. // - GlobalRouterLinkRecord *plr = new GlobalRouterLinkRecord; - plr->SetLinkType (GlobalRouterLinkRecord::PointToPoint); - plr->SetLinkId (rtrIdRemote); - plr->SetLinkData (addrLocal); - pLSA->AddLinkRecord(plr); - plr = 0; + GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord; + plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint); + plr->SetLinkId (rtrIdRemote); + plr->SetLinkData (addrLocal); + pLSA->AddLinkRecord (plr); + plr = 0; + + plr = new GlobalRoutingLinkRecord; + plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork); + plr->SetLinkId (addrRemote); + plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown + pLSA->AddLinkRecord (plr); + plr = 0; + } + else + { + NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type"); + } - plr = new GlobalRouterLinkRecord; - plr->SetLinkType (GlobalRouterLinkRecord::StubNetwork); - plr->SetLinkId (addrRemote); - plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder())); // Frown - pLSA->AddLinkRecord(plr); - plr = 0; } // // The LSA goes on a list of LSAs in case we want to begin exporting other // kinds of advertisements (than Router LSAs). m_LSAs.push_back (pLSA); NS_DEBUG(*pLSA); + + +// Now, determine whether we need to build a NetworkLSA + if (listOfDRInterfaces.size () > 0) + { + for (std::list >::iterator i = listOfDRInterfaces.begin (); + i != listOfDRInterfaces.end (); i++) + { +// Build one NetworkLSA for each interface that is a DR + Ptr ndLocal = *i; + uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal); + Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); + Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); + + GlobalRoutingLSA *pLSA = new GlobalRoutingLSA; + pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA); + pLSA->SetLinkStateId (addrLocal); + pLSA->SetAdvertisingRouter (m_routerId); + pLSA->SetNetworkLSANetworkMask (maskLocal); + pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); +// Build list of AttachedRouters + Ptr ch = ndLocal->GetChannel(); + uint32_t nDevices = ch->GetNDevices(); + NS_ASSERT (nDevices); + for (uint32_t i = 0; i < nDevices; i++) + { + Ptr tempNd = ch->GetDevice (i); + NS_ASSERT (tempNd); + Ptr tempNode = tempNd->GetNode (); + uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd); + Ptr tempIpv4 = tempNode->QueryInterface (Ipv4::iid); + NS_ASSERT (tempIpv4); + Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex); + pLSA->AddAttachedRouter (tempAddr); + } + m_LSAs.push_back (pLSA); + NS_DEBUG(*pLSA); + } + } + return m_LSAs.size (); } + Ipv4Address +GlobalRouter::FindDesignatedRouterForLink (Ptr node, + Ptr ndLocal) const +{ + uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal); + Ptr ipv4Local = m_node->QueryInterface (Ipv4::iid); + NS_ASSERT (ipv4Local); + Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal); + Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal); + + Ptr ch = ndLocal->GetChannel(); + uint32_t nDevices = ch->GetNDevices(); + NS_ASSERT (nDevices); + Ipv4Address lowest = addrLocal; + // iterate all NetDevices and return the lowest numbered IP address + for (uint32_t i = 0; i < nDevices; i++) + { + Ptr tempNd = ch->GetDevice (i); + NS_ASSERT (tempNd); + Ptr tempNode = tempNd->GetNode (); + uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd); + Ptr tempIpv4 = tempNode->QueryInterface (Ipv4::iid); + NS_ASSERT (tempIpv4); + Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex); + if (tempAddr < addrLocal) + { + addrLocal = tempAddr; + } + } + return addrLocal; +} + uint32_t GlobalRouter::GetNumLSAs (void) const { @@ -510,7 +737,7 @@ GlobalRouter::GetNumLSAs (void) const // Get the nth link state advertisement from this router. // bool -GlobalRouter::GetLSA (uint32_t n, GlobalRouterLSA &lsa) const +GlobalRouter::GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const { NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA"); // @@ -525,7 +752,7 @@ GlobalRouter::GetLSA (uint32_t n, GlobalRouterLSA &lsa) const { if (j == n) { - GlobalRouterLSA *p = *i; + GlobalRoutingLSA *p = *i; lsa = *p; return true; } diff --git a/src/routing/global-routing/global-router-interface.h b/src/routing/global-routing/global-router-interface.h index 61351d34b..66f0c7543 100644 --- a/src/routing/global-routing/global-router-interface.h +++ b/src/routing/global-routing/global-router-interface.h @@ -31,16 +31,16 @@ namespace ns3 { /** * @brief A single link record for a link state advertisement. * - * The GlobalRouterLinkRecord is modeled after the OSPF link record field of + * The GlobalRoutingLinkRecord is modeled after the OSPF link record field of * a Link State Advertisement. Right now we will only see two types of link * records corresponding to a stub network and a point-to-point link (channel). */ -class GlobalRouterLinkRecord +class GlobalRoutingLinkRecord { public: /** * @enum LinkType - * @brief Enumeration of the possible types of Global Router Link Records. + * @brief Enumeration of the possible types of Global Routing Link Records. * * These values are defined in the OSPF spec. We currently only use * PointToPoint and StubNetwork types. @@ -54,16 +54,16 @@ public: }; /** - * @brief Construct an empty ("uninitialized") Global Router Link Record. + * @brief Construct an empty ("uninitialized") Global Routing Link Record. * * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0"; * The Link Type is set to Unknown; * The metric is set to 0. */ - GlobalRouterLinkRecord (); + GlobalRoutingLinkRecord (); /** - * Construct an initialized Global Router Link Record. + * Construct an initialized Global Routing Link Record. * * @param linkType The type of link record to construct. * @param linkId The link ID for the record. @@ -73,21 +73,21 @@ public: * @see SetLinkId * @see SetLinkData */ - GlobalRouterLinkRecord ( + GlobalRoutingLinkRecord ( LinkType linkType, Ipv4Address linkId, Ipv4Address linkData, uint32_t metric); /** - * @brief Destroy a Global Router Link Record. + * @brief Destroy a Global Routing Link Record. * * Currently does nothing. Here as a placeholder only. */ - ~GlobalRouterLinkRecord (); + ~GlobalRoutingLinkRecord (); /** - * Get the Link ID field of the Global Router Link Record. + * Get the Link ID field of the Global Routing Link Record. * * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID * of the neighboring router. @@ -100,7 +100,7 @@ public: Ipv4Address GetLinkId(void) const; /** - * @brief Set the Link ID field of the Global Router Link Record. + * @brief Set the Link ID field of the Global Routing Link Record. * * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID * of the neighboring router. @@ -113,7 +113,7 @@ public: void SetLinkId(Ipv4Address addr); /** - * @brief Get the Link Data field of the Global Router Link Record. + * @brief Get the Link Data field of the Global Routing Link Record. * * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP * address of the node of the local side of the link. @@ -126,7 +126,7 @@ public: Ipv4Address GetLinkData(void) const; /** - * @brief Set the Link Data field of the Global Router Link Record. + * @brief Set the Link Data field of the Global Routing Link Record. * * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP * address of the node of the local side of the link. @@ -139,29 +139,29 @@ public: void SetLinkData(Ipv4Address addr); /** - * @brief Get the Link Type field of the Global Router Link Record. + * @brief Get the Link Type field of the Global Routing Link Record. * * The Link Type describes the kind of link a given record represents. The * values are defined by OSPF. * * @see LinkType - * @returns The LinkType of the current Global Router Link Record. + * @returns The LinkType of the current Global Routing Link Record. */ LinkType GetLinkType(void) const; /** - * @brief Set the Link Type field of the Global Router Link Record. + * @brief Set the Link Type field of the Global Routing Link Record. * * The Link Type describes the kind of link a given record represents. The * values are defined by OSPF. * * @see LinkType - * @param linkType The new LinkType for the current Global Router Link Record. + * @param linkType The new LinkType for the current Global Routing Link Record. */ void SetLinkType(LinkType linkType); /** - * @brief Get the Metric Data field of the Global Router Link Record. + * @brief Get the Metric Data field of the Global Routing Link Record. * * The metric is an abstract cost associated with forwarding a packet across * a link. A sum of metrics must have a well-defined meaning. That is, you @@ -169,12 +169,12 @@ public: * two hops relate to the cost of sending a packet); rather you should use * something like delay. * - * @returns The metric field of the Global Router Link Record. + * @returns The metric field of the Global Routing Link Record. */ uint32_t GetMetric(void) const; /** - * @brief Set the Metric Data field of the Global Router Link Record. + * @brief Set the Metric Data field of the Global Routing Link Record. * * The metric is an abstract cost associated with forwarding a packet across * a link. A sum of metrics must have a well-defined meaning. That is, you @@ -182,7 +182,7 @@ public: * two hops relate to the cost of sending a packet); rather you should use * something like delay. * - * @param metric The new metric for the current Global Router Link Record. + * @param metric The new metric for the current Global Routing Link Record. */ void SetMetric(uint32_t metric); @@ -211,7 +211,7 @@ private: Ipv4Address m_linkData; // for links to RouterLSA, /** - * The type of the Global Router Link Record. Defined in the OSPF spec. + * The type of the Global Routing Link Record. Defined in the OSPF spec. * We currently only use PointToPoint and StubNetwork types. */ LinkType m_linkType; @@ -236,12 +236,24 @@ private: * combined with a list of Link Records. Since it's global, there's * no need for age or sequence number. See RFC 2328, Appendix A. */ -class GlobalRouterLSA +class GlobalRoutingLSA { public: +/** + * @enum LSType + * @brief corresponds to LS type field of RFC 2328 OSPF LSA header + */ + enum LSType { + Unknown = 0, /**< Uninitialized Type */ + RouterLSA, + NetworkLSA, + SummaryLSA, + SummaryLSA_ASBR, + ASExternalLSAs + }; /** * @enum SPFStatus - * @brief Enumeration of the possible values of the status flag in the Router + * @brief Enumeration of the possible values of the status flag in the Routing * Link State Advertisements. */ enum SPFStatus { @@ -249,17 +261,16 @@ public: LSA_SPF_CANDIDATE, /**< Vertex is in the SPF candidate queue */ LSA_SPF_IN_SPFTREE /**< Vertex is in the SPF tree */ }; - /** - * @brief Create a blank Global Router Link State Advertisement. + * @brief Create a blank Global Routing Link State Advertisement. * * On completion Ipv4Address variables initialized to 0.0.0.0 and the * list of Link State Records is empty. */ - GlobalRouterLSA(); + GlobalRoutingLSA(); /** - * @brief Create an initialized Global Router Link State Advertisement. + * @brief Create an initialized Global Routing Link State Advertisement. * * On completion the list of Link State Records is empty. * @@ -267,42 +278,42 @@ public: * @param linkStateId The Ipv4Address for the link state ID field. * @param advertisingRtr The Ipv4Address for the advertising router field. */ - GlobalRouterLSA(SPFStatus status, Ipv4Address linkStateId, + GlobalRoutingLSA(SPFStatus status, Ipv4Address linkStateId, Ipv4Address advertisingRtr); /** - * @brief Copy constructor for a Global Router Link State Advertisement. + * @brief Copy constructor for a Global Routing Link State Advertisement. * * Takes a piece of memory and constructs a semantically identical copy of * the given LSA. * * @param lsa The existing LSA to be used as the source. */ - GlobalRouterLSA (GlobalRouterLSA& lsa); + GlobalRoutingLSA (GlobalRoutingLSA& lsa); /** - * @brief Destroy an existing Global Router Link State Advertisement. + * @brief Destroy an existing Global Routing Link State Advertisement. * - * Any Global Router Link Records present in the list are freed. + * Any Global Routing Link Records present in the list are freed. */ - ~GlobalRouterLSA(); + ~GlobalRoutingLSA(); /** - * @brief Assignment operator for a Global Router Link State Advertisement. + * @brief Assignment operator for a Global Routing Link State Advertisement. * - * Takes an existing Global Router Link State Advertisement and overwrites + * Takes an existing Global Routing Link State Advertisement and overwrites * it to make a semantically identical copy of a given prototype LSA. * - * If there are any Global Router Link Records present in the existing + * If there are any Global Routing Link Records present in the existing * LSA, they are freed before the assignment happens. * * @param lsa The existing LSA to be used as the source. * @returns Reference to the overwritten LSA. */ - GlobalRouterLSA& operator= (const GlobalRouterLSA& lsa); + GlobalRoutingLSA& operator= (const GlobalRoutingLSA& lsa); /** - * @brief Copy any Global Router Link Records in a given Global Router Link + * @brief Copy any Global Routing Link Records in a given Global Routing Link * State Advertisement to the current LSA. * * Existing Link Records are not deleted -- this is a concatenation of Link @@ -311,57 +322,66 @@ public: * @see ClearLinkRecords () * @param lsa The LSA to copy the Link Records from. */ - void CopyLinkRecords (const GlobalRouterLSA& lsa); + void CopyLinkRecords (const GlobalRoutingLSA& lsa); /** - * @brief Add a given Global Router Link Record to the LSA. + * @brief Add a given Global Routing Link Record to the LSA. * - * @param lr The Global Router Link Record to be added. + * @param lr The Global Routing Link Record to be added. * @returns The number of link records in the list. */ - uint32_t AddLinkRecord (GlobalRouterLinkRecord* lr); + uint32_t AddLinkRecord (GlobalRoutingLinkRecord* lr); /** - * @brief Return the number of Global Router Link Records in the LSA. + * @brief Return the number of Global Routing Link Records in the LSA. * * @returns The number of link records in the list. */ uint32_t GetNLinkRecords (void) const; /** - * @brief Return a pointer to the specified Global Router Link Record. + * @brief Return a pointer to the specified Global Routing Link Record. * * @param n The LSA number desired. * @returns The number of link records in the list. */ - GlobalRouterLinkRecord* GetLinkRecord (uint32_t n) const; + GlobalRoutingLinkRecord* GetLinkRecord (uint32_t n) const; /** - * @brief Release all of the Global Router Link Records present in the Global - * Router Link State Advertisement and make the list of link records empty. + * @brief Release all of the Global Routing Link Records present in the Global + * Routing Link State Advertisement and make the list of link records empty. */ void ClearLinkRecords(void); /** - * @brief Check to see if the list of Global Router Link Records present in the - * Global Router Link State Advertisement is empty. + * @brief Check to see if the list of Global Routing Link Records present in the + * Global Routing Link State Advertisement is empty. * * @returns True if the list is empty, false otherwise. */ bool IsEmpty(void) const; /** - * @brief Print the contents of the Global Router Link State Advertisement and - * any Global Router Link Records present in the list. Quite verbose. + * @brief Print the contents of the Global Routing Link State Advertisement and + * any Global Routing Link Records present in the list. Quite verbose. */ void Print (std::ostream &os) const; +/** + * @brief Return the LSType field of the LSA + */ + LSType GetLSType (void) const; +/** + * @brief Set the LS type field of the LSA + */ + void SetLSType (LSType typ); + /** * @brief Get the Link State ID as defined by the OSPF spec. We always set it * to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see GlobalRouter::GetRouterId () + * @see GlobalRouting::GetRouterId () * @returns The Ipv4Address stored as the link state ID. */ Ipv4Address GetLinkStateId (void) const; @@ -371,7 +391,7 @@ public: * to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see GlobalRouter::GetRouterId () + * @see GlobalRouting::GetRouterId () */ void SetLinkStateId (Ipv4Address addr); @@ -380,7 +400,7 @@ public: * set it to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see GlobalRouter::GetRouterId () + * @see GlobalRouting::GetRouterId () * @returns The Ipv4Address stored as the advetising router. */ Ipv4Address GetAdvertisingRouter (void) const; @@ -390,10 +410,47 @@ public: * set it to the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see GlobalRouter::GetRouterId () + * @see GlobalRouting::GetRouterId () */ void SetAdvertisingRouter (Ipv4Address rtr); +/** + * @brief For a Network LSA, set the Network Mask field that precedes + * the list of attached routers. + */ + void SetNetworkLSANetworkMask (Ipv4Mask mask); + +/** + * @brief For a Network LSA, get the Network Mask field that precedes + * the list of attached routers. + * + * @returns the NetworkLSANetworkMask + */ + Ipv4Mask GetNetworkLSANetworkMask (void) const; + +/** + * @brief Add an attached router to the list in the NetworkLSA + * + * @param address The Ipv4Address of the interface on the network link + * @returns The number of addresses in the list. + */ + uint32_t AddAttachedRouter (Ipv4Address addr); + +/** + * @brief Return the number of attached routers listed in the NetworkLSA + * + * @returns The number of attached routers. + */ + uint32_t GetNAttachedRouters (void) const; + +/** + * @brief Return an Ipv4Address corresponding to the specified attached router + * + * @param n The attached router number desired (number in the list). + * @returns The Ipv4Address of the requested router + */ + Ipv4Address GetAttachedRouter (uint32_t n) const; + /** * @brief Get the SPF status of the advertisement. * @@ -410,12 +467,17 @@ public: void SetStatus (SPFStatus status); private: +/** + * The type of the LSA. Each LSA type has a separate advertisement + * format. + */ + LSType m_lsType; /** * The Link State ID is defined by the OSPF spec. We always set it to the * router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see GlobalRouter::GetRouterId () + * @see GlobalRouting::GetRouterId () */ Ipv4Address m_linkStateId; @@ -424,14 +486,14 @@ private: * the router ID of the router making the advertisement. * * @see RoutingEnvironment::AllocateRouterId () - * @see GlobalRouter::GetRouterId () + * @see GlobalRouting::GetRouterId () */ Ipv4Address m_advertisingRtr; /** * A convenience typedef to avoid too much writers cramp. */ - typedef std::list ListOfLinkRecords_t; + typedef std::list ListOfLinkRecords_t; /** * Each Link State Advertisement contains a number of Link Records that @@ -441,10 +503,30 @@ private: * m_linkRecords is an STL list container to hold the Link Records that have * been discovered and prepared for the advertisement. * - * @see GlobalRouter::DiscoverLSAs () + * @see GlobalRouting::DiscoverLSAs () */ ListOfLinkRecords_t m_linkRecords; +/** + * Each Network LSA contains the network mask of the attached network + */ + Ipv4Mask m_networkLSANetworkMask; + +/** + * A convenience typedef to avoid too much writers cramp. + */ + typedef std::list ListOfAttachedRouters_t; + +/** + * Each Network LSA contains a list of attached routers + * + * m_attachedRouters is an STL list container to hold the addresses that have + * been discovered and prepared for the advertisement. + * + * @see GlobalRouting::DiscoverLSAs () + */ + ListOfAttachedRouters_t m_attachedRouters; + /** * This is a tristate flag used internally in the SPF computation to mark * if an SPFVertex (a data structure representing a vertex in the SPF tree @@ -454,7 +536,7 @@ private: SPFStatus m_status; }; -std::ostream& operator<< (std::ostream& os, GlobalRouterLSA& lsa); +std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa); /** * @brief An interface aggregated to a node to provide global routing info @@ -496,7 +578,7 @@ public: /** * @brief Walk the connected channels, discover the adjacent routers and build - * the associated number of Global Router Link State Advertisements that + * the associated number of Global Routing Link State Advertisements that * this router can export. * * This is a fairly expensive operation in that every time it is called @@ -507,14 +589,14 @@ public: * advertisements after a network topology change by calling DiscoverLSAs * and then by reading those advertisements. * - * @see GlobalRouterLSA + * @see GlobalRoutingLSA * @see GlobalRouter::GetLSA () - * @returns The number of Global Router Link State Advertisements. + * @returns The number of Global Routing Link State Advertisements. */ uint32_t DiscoverLSAs (void); /** - * @brief Get the Number of Global Router Link State Advertisements that this + * @brief Get the Number of Global Routing Link State Advertisements that this * router can export. * * To get meaningful information you must have previously called DiscoverLSAs. @@ -522,19 +604,19 @@ public: * GetLSA () to retrieve the actual advertisement. * * @see GlobalRouterLSA - * @see GlobalRouter::DiscoverLSAs () - * @see GlobalRouter::GetLSA () - * @returns The number of Global Router Link State Advertisements. + * @see GlobalRouting::DiscoverLSAs () + * @see GlobalRouting::GetLSA () + * @returns The number of Global Routing Link State Advertisements. */ uint32_t GetNumLSAs (void) const; /** - * @brief Get a Global Router Link State Advertisements that this router has + * @brief Get a Global Routing Link State Advertisements that this router has * said that it can export. * * This is a fairly inexpensive expensive operation in that the hard work - * was done in GetNumLSAs. We just copy the indicated Global Router Link - * State Advertisement into the requested GlobalRouterLSA object. + * was done in GetNumLSAs. We just copy the indicated Global Routing Link + * State Advertisement into the requested GlobalRoutingLSA object. * * You must call GlobalRouter::GetNumLSAs before calling this method in * order to discover the adjacent routers and build the advertisements. @@ -542,13 +624,13 @@ public: * The parameter n (requested LSA number) must be in the range 0 to * GetNumLSAs() - 1. * - * @see GlobalRouterLSA - * @see GlobalRouter::GetNumLSAs () + * @see GlobalRoutingLSA + * @see GlobalRouting::GetNumLSAs () * @param n The index number of the LSA you want to read. - * @param lsa The GlobalRouterLSA class to receive the LSA information. + * @param lsa The GlobalRoutingLSA class to receive the LSA information. * @returns The number of Global Router Link State Advertisements. */ - bool GetLSA (uint32_t n, GlobalRouterLSA &lsa) const; + bool GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const; private: virtual ~GlobalRouter (); @@ -556,10 +638,12 @@ private: Ptr GetAdjacent(Ptr nd, Ptr ch) const; uint32_t FindIfIndexForDevice(Ptr node, Ptr nd) const; + Ipv4Address FindDesignatedRouterForLink (Ptr node, + Ptr ndLocal) const; Ptr m_node; - typedef std::list ListOfLSAs_t; + typedef std::list ListOfLSAs_t; ListOfLSAs_t m_LSAs; Ipv4Address m_routerId; From 915e34b32bc3068725c50d0db544f8d7ccd73017 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Sun, 12 Aug 2007 14:24:49 -0700 Subject: [PATCH 248/278] fix optimized build; remove old comment --- src/routing/global-routing/global-route-manager-impl.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index e78dfedf6..217513df8 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -860,9 +860,6 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( // Router Link Record we find that describes a point-to-point link from // to . If prev_link is not NULL, we return a Global Router Link Record // representing a possible *second* link from to . -// -// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for -// any link records after pre_link and not just after the first? // GlobalRoutingLinkRecord* GlobalRouteManagerImpl::SPFGetNextLink ( @@ -1450,8 +1447,8 @@ GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v) NS_ASSERT_MSG (lsa, "GlobalRouteManagerImpl::SPFIntraAddTransit (): " "Expected valid LSA in SPFVertex* v"); - Ipv4Mask tempmask = v->GetLSA ()->GetNetworkLSANetworkMask (); - Ipv4Address tempip = v->GetLSA ()->GetLinkStateId (); + Ipv4Mask tempmask = lsa->GetNetworkLSANetworkMask (); + Ipv4Address tempip = lsa->GetLinkStateId (); tempip = tempip.CombineMask (tempmask); ipv4->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), v->GetOutgoingInterfaceId ()); From ad3b6a04ccdfd0999a8de4022d3f193ff84790bd Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 13 Aug 2007 20:53:29 -0700 Subject: [PATCH 249/278] Doxygen cleanup --- src/devices/csma/csma-ipv4-topology.h | 2 +- src/devices/csma/csma-net-device.h | 15 +++++++++++++++ .../point-to-point/point-to-point-net-device.h | 1 - src/node/socket.h | 2 -- .../global-routing/global-router-interface.h | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/devices/csma/csma-ipv4-topology.h b/src/devices/csma/csma-ipv4-topology.h index 37f546118..86be99d7a 100644 --- a/src/devices/csma/csma-ipv4-topology.h +++ b/src/devices/csma/csma-ipv4-topology.h @@ -97,7 +97,7 @@ public: * \param n1 Node * \param ndNum NetDevice number with which to associate address * \param addr1 Ipv4 Address for ndNum of n1 - * \param network network mask for ndNum of node n1 + * \param netmask1 network mask for ndNum of node n1 * * Add an Ipv4Address to the Ipv4 interface associated with the * ndNum CsmaIpv4NetDevices on the provided diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 62e07f6fc..441ea04cd 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -99,8 +99,23 @@ enum CsmaEncapsulationMode { * * \param node the Node to which this device is connected. * \param addr The source MAC address of the net device. + * \param pktType the type of encapsulation */ CsmaNetDevice (Ptr node, Eui48Address addr, CsmaEncapsulationMode pktType); + + /** + * Construct a CsmaNetDevice + * + * This is the constructor for the CsmaNetDevice. It takes as a + * parameter the Node to which this device is connected. Ownership of the + * Node pointer is not implied and the node must not be deleted. + * + * \param node the Node to which this device is connected. + * \param addr The source MAC address of the net device. + * \param pktType the type of encapsulation + * \param sendEnable whether this device is able to send + * \param receiveEnable whether this device is able to receive + */ CsmaNetDevice (Ptr node, Eui48Address addr, CsmaEncapsulationMode pktType, bool sendEnable, bool receiveEnable); diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index 6112c7e19..d8d8d3242 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -175,7 +175,6 @@ protected: virtual Ptr DoGetChannel(void) const; /** * Set a new default data rate - * @param Data rate to set for new default */ static void SetDefaultRate(const DataRate&); diff --git a/src/node/socket.h b/src/node/socket.h index e3365fcd8..c717ec0a5 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -170,7 +170,6 @@ public: /** * \brief Send data (or dummy data) to the remote host * \param p packet to send - * \param dataSent Data sent callback. * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ @@ -180,7 +179,6 @@ public: * \brief Send data to a specified peer. * \param address IP Address of remote host * \param p packet to send - * \param dataSent Data sent callback. * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ diff --git a/src/routing/global-routing/global-router-interface.h b/src/routing/global-routing/global-router-interface.h index 66f0c7543..b6558eb20 100644 --- a/src/routing/global-routing/global-router-interface.h +++ b/src/routing/global-routing/global-router-interface.h @@ -431,7 +431,7 @@ public: /** * @brief Add an attached router to the list in the NetworkLSA * - * @param address The Ipv4Address of the interface on the network link + * @param addr The Ipv4Address of the interface on the network link * @returns The number of addresses in the list. */ uint32_t AddAttachedRouter (Ipv4Address addr); From ad457017909f52aec9643e2901cdc3abc09bee32 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 13 Aug 2007 22:53:20 -0700 Subject: [PATCH 250/278] restore ns-2 .tr format --- src/internet-node/ascii-trace.cc | 39 ++++++++++++++++++++++++++++---- src/internet-node/ascii-trace.h | 4 +++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/internet-node/ascii-trace.cc b/src/internet-node/ascii-trace.cc index cb48f06fc..0331bb5fd 100644 --- a/src/internet-node/ascii-trace.cc +++ b/src/internet-node/ascii-trace.cc @@ -25,6 +25,7 @@ #include "ns3/simulator.h" #include "ns3/node.h" #include "ns3/packet.h" +#include "ns3/queue.h" namespace ns3 { @@ -40,8 +41,12 @@ void AsciiTrace::TraceAllQueues (void) { Packet::EnableMetadata (); - TraceRoot::Connect ("/nodes/*/devices/*/queue/*", - MakeCallback (&AsciiTrace::LogDevQueue, this)); + TraceRoot::Connect ("/nodes/*/devices/*/queue/enqueue", + MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this)); + TraceRoot::Connect ("/nodes/*/devices/*/queue/dequeue", + MakeCallback (&AsciiTrace::LogDevQueueDequeue, this)); + TraceRoot::Connect ("/nodes/*/devices/*/queue/drop", + MakeCallback (&AsciiTrace::LogDevQueueDrop, this)); } void AsciiTrace::TraceAllNetDeviceRx (void) @@ -52,8 +57,34 @@ AsciiTrace::TraceAllNetDeviceRx (void) } void -AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet) +AsciiTrace::LogDevQueueEnqueue (TraceContext const &context, + Packet const &packet) { + m_os << "+ "; + m_os << Simulator::Now ().GetSeconds () << " "; + context.Print (m_os); + m_os << " pkt-uid=" << packet.GetUid () << " "; + packet.Print (m_os); + m_os << std::endl; +} + +void +AsciiTrace::LogDevQueueDequeue (TraceContext const &context, + Packet const &packet) +{ + m_os << "- "; + m_os << Simulator::Now ().GetSeconds () << " "; + context.Print (m_os); + m_os << " pkt-uid=" << packet.GetUid () << " "; + packet.Print (m_os); + m_os << std::endl; +} + +void +AsciiTrace::LogDevQueueDrop (TraceContext const &context, + Packet const &packet) +{ + m_os << "d "; m_os << Simulator::Now ().GetSeconds () << " "; context.Print (m_os); m_os << " pkt-uid=" << packet.GetUid () << " "; @@ -63,7 +94,7 @@ AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet) void AsciiTrace::LogDevRx (TraceContext const &context, Packet &p) { - m_os << Simulator::Now ().GetSeconds () << " "; + m_os << "r " << Simulator::Now ().GetSeconds () << " "; context.Print (m_os); m_os << " pkt-uid=" << p.GetUid () << " "; p.Print (m_os); diff --git a/src/internet-node/ascii-trace.h b/src/internet-node/ascii-trace.h index 56b4195cb..e219afc41 100644 --- a/src/internet-node/ascii-trace.h +++ b/src/internet-node/ascii-trace.h @@ -37,7 +37,9 @@ public: void TraceAllQueues (void); void TraceAllNetDeviceRx (void); private: - void LogDevQueue (TraceContext const &context, const Packet &p); + void LogDevQueueEnqueue (TraceContext const &context, const Packet &p); + void LogDevQueueDequeue (TraceContext const &context, const Packet &p); + void LogDevQueueDrop (TraceContext const &context, const Packet &p); void LogDevRx (TraceContext const &context, Packet &p); std::ofstream m_os; }; From 6c2a73ebda2b7d453e01d571e4621b501867ed67 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Mon, 13 Aug 2007 23:06:25 -0700 Subject: [PATCH 251/278] cleanup valgrind errors --- src/routing/global-routing/global-route-manager-impl.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 217513df8..9ede0a134 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -1586,6 +1586,7 @@ GlobalRouteManagerImplTest::RunTests (void) 1); GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA (); + lsa0->SetLSType (GlobalRoutingLSA::RouterLSA); lsa0->SetLinkStateId ("0.0.0.0"); lsa0->SetAdvertisingRouter ("0.0.0.0"); lsa0->AddLinkRecord (lr0); @@ -1605,6 +1606,7 @@ GlobalRouteManagerImplTest::RunTests (void) 1); GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA (); + lsa1->SetLSType (GlobalRoutingLSA::RouterLSA); lsa1->SetLinkStateId ("0.0.0.1"); lsa1->SetAdvertisingRouter ("0.0.0.1"); lsa1->AddLinkRecord (lr2); @@ -1648,6 +1650,7 @@ GlobalRouteManagerImplTest::RunTests (void) 1); GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA (); + lsa2->SetLSType (GlobalRoutingLSA::RouterLSA); lsa2->SetLinkStateId ("0.0.0.2"); lsa2->SetAdvertisingRouter ("0.0.0.2"); lsa2->AddLinkRecord (lr4); @@ -1671,6 +1674,7 @@ GlobalRouteManagerImplTest::RunTests (void) 1); GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA (); + lsa3->SetLSType (GlobalRoutingLSA::RouterLSA); lsa3->SetLinkStateId ("0.0.0.3"); lsa3->SetAdvertisingRouter ("0.0.0.3"); lsa3->AddLinkRecord (lr10); From 9d2617d9a00b88b6466c5efd5003f4719c9c1e1d Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 14 Aug 2007 12:00:03 -0700 Subject: [PATCH 252/278] Fix bug 68. Implement IsMulticast --- src/node/ipv4-address.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/node/ipv4-address.cc b/src/node/ipv4-address.cc index 34b15372d..4e1e344c5 100644 --- a/src/node/ipv4-address.cc +++ b/src/node/ipv4-address.cc @@ -171,8 +171,11 @@ Ipv4Address::IsBroadcast (void) const bool Ipv4Address::IsMulticast (void) const { - // XXX - return false; +// +// Multicast addresses are defined as ranging from 224.0.0.0 through +// 239.255.255.255 (which is E0000000 through EFFFFFFF in hex). +// + return (m_address >= 0xe0000000 && m_address <= 0xefffffff); } uint32_t From 8d5ddc0ddfd8fc9b8211f4cb04f704f65774db84 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 15 Aug 2007 22:48:40 -0700 Subject: [PATCH 253/278] Release notes updated --- RELEASE_NOTES | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 9b3b40b1b..85a5f2d6e 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -3,12 +3,16 @@ This file contains ns-3 release notes (most recent releases first). -Release 3.0.5 (2007/08/XX) +Release 3.0.5 (2007/08/15) ======================== - - Add CSMA/CD model (Emmanuelle Laprise) - - Modularize ipv4 routing support (Gustavo Carneiro) - - Add mobility framework and basic mobility models + - Refactoring to support win32-based unix environments (Cygwin, mingw) + - "Packet socket" for allowing applications to access NetDevices directly + - Generalized, polymorphic Address class + - Add CSMA NetDevice model (from Emmanuelle Laprise) + - Modularize IPv4 routing support (from Gustavo Carneiro) + - Add mobility framework and basic mobility models + - Global unicast centralized routing Release 3.0.4 (2007/07/15) ======================== From 89758558cfb3649338ff448fed2cca5cd61230e7 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 15 Aug 2007 22:49:06 -0700 Subject: [PATCH 254/278] bump version number --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b0f2dcb32..eca690e73 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.4 +3.0.5 From 365e662472d04ca9f30d6ab3d99ae7091ec6624e Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 15 Aug 2007 22:50:31 -0700 Subject: [PATCH 255/278] update release_steps.txt --- doc/release_steps.txt | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/doc/release_steps.txt b/doc/release_steps.txt index 689013ce6..5fe843d77 100644 --- a/doc/release_steps.txt +++ b/doc/release_steps.txt @@ -5,23 +5,20 @@ Steps in doing an ns-3 release - revise and check in RELEASE_NOTES - update and check in VERSION to the latest release number 2. make a new "architecture.pdf" document and place it in the doc/ directory -3. add current version of waf script from subversion: - - svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf - - build waf script and put it into top of ns-3-dev -4. cd ns-3-dev; ./waf configure; ./waf dist -5. test tarball on release platforms (run-tests and simple-p2p) -6. tag ns-3-dev with "release ns-3.0.X" +3. cd ns-3-dev; ./waf configure; ./waf dist +4. test tarball on release platforms (waf check and maybe some other scripts) +5. tag ns-3-dev with "release ns-3.0.X" - hg tag "release ns-3.0.x" - hg push -7. clone the tagged ns-3-dev and place it on the repository +6. clone the tagged ns-3-dev and place it on the repository - ssh code.nsnam.org; sudo; su code; - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x - cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately -8. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server -9. update web page +7. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server +8. update web page - add link to news.html - update download.html - update roadmap.html - build and update Doxygen directory on the server - update and upload software architecture document (PDF, HTML) -10. announce to ns-developers, with summary of release notes +9. announce to ns-developers, with summary of release notes From 52de20c3b639e3ce782b4344f51b76b7203c9504 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 15 Aug 2007 23:03:06 -0700 Subject: [PATCH 256/278] Add Emmanuelle to authors list --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index f36dad9ce..1cb4b0af7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,4 +3,5 @@ Gustavo Carneiro (gjc@inescporto.pt, gjcarneiro@gmail.com) Craig Dowell (craigdo@ee.washington.edu) Tom Henderson (tomhend@u.washington.edu) Mathieu Lacage (mathieu.lacage@sophia.inria.fr) +Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca) George F. Riley (riley@ece.gatech.edu) From bea15392ec3216b26487029825100c6782b85099 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 15 Aug 2007 23:31:51 -0700 Subject: [PATCH 257/278] Added tag release ns-3.0.5 for changeset 08046b6aef37 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index bff7cf994..aac74dfcf 100644 --- a/.hgtags +++ b/.hgtags @@ -3,3 +3,4 @@ 0dc81e76166c56aaae64da48b673b62155943aad packet-history-working 38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3 5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4 +08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5 From 35f5503e26a54daff6b3e4719687f3bdd2079d88 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 21 Aug 2007 18:04:48 +0100 Subject: [PATCH 258/278] WAF: fix compatibility with Python 2.3 --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 6801b7e56..48b731729 100644 --- a/wscript +++ b/wscript @@ -37,7 +37,7 @@ def set_options(opt): opt.add_option('-d', '--debug-level', action='callback', - type=str, dest='debug_level', default='debug', + type="string", dest='debug_level', default='debug', help=('Specify the debug level, does nothing if CFLAGS is set' ' in the environment. [Allowed Values: debug, optimized].' ' WARNING: this option only has effect ' From 08bcb4249d99c10585953df4379976b5340dc7c3 Mon Sep 17 00:00:00 2001 From: Raj Bhattacharjea Date: Wed, 22 Aug 2007 12:02:42 -0400 Subject: [PATCH 259/278] clarified a comment --- examples/simple-point-to-point.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/simple-point-to-point.cc b/examples/simple-point-to-point.cc index 9b185143b..4e7657cdb 100644 --- a/examples/simple-point-to-point.cc +++ b/examples/simple-point-to-point.cc @@ -72,6 +72,7 @@ int main (int argc, char *argv[]) // Users may find it convenient to turn on explicit debugging // for selected modules; the below lines suggest how to do this + // remember to add #include "ns3/debug.h" before enabling these #if 0 DebugComponentEnable("Object"); DebugComponentEnable("Queue"); From d8b046a69fe55fea9b43916f681d3f12916f273a Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 24 Aug 2007 10:32:35 +0200 Subject: [PATCH 260/278] add missing include --- src/applications/onoff-application.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/onoff-application.h b/src/applications/onoff-application.h index c42d9d14f..92dceb7f7 100644 --- a/src/applications/onoff-application.h +++ b/src/applications/onoff-application.h @@ -28,13 +28,13 @@ #include "ns3/application.h" #include "ns3/event-id.h" #include "ns3/ptr.h" +#include "ns3/data-rate.h" namespace ns3 { class Address; class RandomVariable; class Socket; -class DataRate; /** * \brief Generate traffic to a single destination according to an From 2ee1d5fca6acd0779bf5f1d53d2096ba1872f4dd Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 24 Aug 2007 10:33:58 +0200 Subject: [PATCH 261/278] the protocol number field is a 16 bit integer, not a 32 bit integer --- src/node/net-device.cc | 2 +- src/node/net-device.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/net-device.cc b/src/node/net-device.cc index 1ffe6d4b1..e3b9537aa 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -197,7 +197,7 @@ NetDevice::GetChannel (void) const // Receive packets from below bool -NetDevice::ForwardUp(const Packet& p, uint32_t param, const Address &from) +NetDevice::ForwardUp(const Packet& p, uint16_t param, const Address &from) { bool retval = false; diff --git a/src/node/net-device.h b/src/node/net-device.h index 315f16033..cc93e6420 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -251,7 +251,7 @@ public: * forwards it to the higher layers by calling this method * which is responsible for passing it up to the Rx callback. */ - bool ForwardUp (const Packet& p, uint32_t param, const Address &address); + bool ForwardUp (const Packet& p, uint16_t param, const Address &address); /** From 00a9973ca84f0c094dedea2bf44847cb85dda2bc Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 24 Aug 2007 12:45:45 +0200 Subject: [PATCH 262/278] use a Ptr<> where needed. --- src/mobility/mobility-model.cc | 4 ++-- src/mobility/mobility-model.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mobility/mobility-model.cc b/src/mobility/mobility-model.cc index 959e29a1e..808c5f4dd 100644 --- a/src/mobility/mobility-model.cc +++ b/src/mobility/mobility-model.cc @@ -52,9 +52,9 @@ MobilityModel::Set (const Position &position) } double -MobilityModel::GetDistanceFrom (const MobilityModel &other) const +MobilityModel::GetDistanceFrom (Ptr other) const { - Position oPosition = other.DoGet (); + Position oPosition = other->DoGet (); Position position = DoGet (); return CalculateDistance (position, oPosition); } diff --git a/src/mobility/mobility-model.h b/src/mobility/mobility-model.h index 4c4cf9000..5d0e6ee4a 100644 --- a/src/mobility/mobility-model.h +++ b/src/mobility/mobility-model.h @@ -57,7 +57,7 @@ public: * \param position a reference to another mobility model * \returns the distance between the two objects. Unit is meters. */ - double GetDistanceFrom (const MobilityModel &position) const; + double GetDistanceFrom (Ptr position) const; protected: /** * Must be invoked by subclasses when the course of the From ca21c26638456b3f60b331b53293e9954ffa7e74 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 24 Aug 2007 14:45:25 +0200 Subject: [PATCH 263/278] add failing tests --- src/simulator/simulator.cc | 146 +++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index e6f2d332b..e13c3976f 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -546,6 +546,7 @@ public: private: uint64_t NowUs (); bool RunOneTest (void); + void RunTestsConst (void) const; void A (int a); void B (int b); void C (int c); @@ -566,6 +567,24 @@ private: void cbaz3 (const int &, const int &, const int &); void cbaz4 (const int &, const int &, const int &, const int &); void cbaz5 (const int &, const int &, const int &, const int &, const int &); + + void bar0c (void) const; + void bar1c (int) const; + void bar2c (int, int) const; + void bar3c (int, int, int) const; + void bar4c (int, int, int, int) const; + void bar5c (int, int, int, int, int) const; + void baz1c (int &) const; + void baz2c (int &, int &) const; + void baz3c (int &, int &, int &) const; + void baz4c (int &, int &, int &, int &) const; + void baz5c (int &, int &, int &, int &, int &) const; + void cbaz1c (const int &) const; + void cbaz2c (const int &, const int &) const; + void cbaz3c (const int &, const int &, const int &) const; + void cbaz4c (const int &, const int &, const int &, const int &) const; + void cbaz5c (const int &, const int &, const int &, const int &, const int &) const; + void destroy (void); bool m_b; @@ -689,6 +708,57 @@ void SimulatorTests::cbaz5 (const int &, const int &, const int &, const int &, const int &) {} +void +SimulatorTests::bar0c (void) const +{} +void +SimulatorTests::bar1c (int) const +{} +void +SimulatorTests::bar2c (int, int) const +{} +void +SimulatorTests::bar3c (int, int, int) const +{} +void +SimulatorTests::bar4c (int, int, int, int) const +{} +void +SimulatorTests::bar5c (int, int, int, int, int) const +{} + +void +SimulatorTests::baz1c (int &) const +{} +void +SimulatorTests::baz2c (int &, int &) const +{} +void +SimulatorTests::baz3c (int &, int &, int &) const +{} +void +SimulatorTests::baz4c (int &, int &, int &, int &) const +{} +void +SimulatorTests::baz5c (int &, int &, int &, int &, int &) const +{} + +void +SimulatorTests::cbaz1c (const int &) const +{} +void +SimulatorTests::cbaz2c (const int &, const int &) const +{} +void +SimulatorTests::cbaz3c (const int &, const int &, const int &) const +{} +void +SimulatorTests::cbaz4c (const int &, const int &, const int &, const int &) const +{} +void +SimulatorTests::cbaz5c (const int &, const int &, const int &, const int &, const int &) const +{} + bool SimulatorTests::RunOneTest (void) { @@ -723,6 +793,80 @@ SimulatorTests::RunOneTest (void) } return ok; } +void +SimulatorTests::RunTestsConst (void) const +{ + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, this); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, this, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, this, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, this, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, this, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, this, 0, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr (this)); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr (this), 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr (this), 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr (this), 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1c, this, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2c, this, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3c, this, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4c, this, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar0c, this); + Simulator::ScheduleNow (&SimulatorTests::bar1c, this, 0); + Simulator::ScheduleNow (&SimulatorTests::bar2c, this, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar3c, this, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar4c, this, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::cbaz1c, this, 0); + Simulator::ScheduleNow (&SimulatorTests::cbaz2c, this, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::cbaz3c, this, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr (this)); + Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr (this), 0); + Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr (this), 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr (this), 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar0c, this); + Simulator::ScheduleDestroy (&SimulatorTests::bar1c, this, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar2c, this, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar3c, this, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar4c, this, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::cbaz1c, this, 0); + Simulator::ScheduleDestroy (&SimulatorTests::cbaz2c, this, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::cbaz3c, this, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr (this)); + Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr (this), 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr (this), 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr (this), 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1c, this, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2c, this, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3c, this, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4c, this, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::baz1c, this, 0); + Simulator::ScheduleNow (&SimulatorTests::baz2c, this, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::baz3c, this, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::baz4c, this, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::baz1c, this, 0); + Simulator::ScheduleDestroy (&SimulatorTests::baz2c, this, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::baz3c, this, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::baz4c, this, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0); + + Simulator::Run (); + Simulator::Destroy (); +} + bool SimulatorTests::RunTests (void) { @@ -870,6 +1014,8 @@ SimulatorTests::RunTests (void) Simulator::ScheduleDestroy (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0); #endif + RunTestsConst (); + EventId nowId = Simulator::ScheduleNow (&foo0); m_destroyId = Simulator::ScheduleDestroy (&SimulatorTests::destroy, this); if (m_destroyId.IsExpired ()) From 02418f7498443636ea35143f59c46415a6cc0497 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 24 Aug 2007 15:05:34 +0200 Subject: [PATCH 264/278] fix first part of errors introduced by new tests --- src/simulator/simulator.h | 278 ++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 163 deletions(-) diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index 9c9cd201e..cdf2f8b4e 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -163,8 +163,8 @@ public: * @param obj the object on which to invoke the member method * @returns an id for the scheduled event. */ - template - static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj); + template + static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj); /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -172,8 +172,8 @@ public: * @param a1 the first argument to pass to the invoked method * @returns an id for the scheduled event. */ - template - static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1), OBJ obj, T1 a1); + template + static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1); /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -182,8 +182,8 @@ public: * @param a2 the second argument to pass to the invoked method * @returns an id for the scheduled event. */ - template - static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2); + template + static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2); /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -193,10 +193,9 @@ public: * @param a3 the third argument to pass to the invoked method * @returns an id for the scheduled event. */ - template - static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3); + static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3); /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -207,10 +206,9 @@ public: * @param a4 the fourth argument to pass to the invoked method * @returns an id for the scheduled event. */ - template - static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); + static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -222,10 +220,9 @@ public: * @param a5 the fifth argument to pass to the invoked method * @returns an id for the scheduled event. */ - template - static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, + static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); /** * @param time the relative expiration time of the event. @@ -295,27 +292,25 @@ public: * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method */ - template - static EventId ScheduleNow (void (T::*mem_ptr) (void), OBJ obj); + template + static EventId ScheduleNow (MEM mem_ptr, OBJ obj); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method * @param a1 the first argument to pass to the invoked method */ - template - static EventId ScheduleNow (void (T::*mem_ptr) (U1), OBJ obj, T1 a1); + static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method * @param a1 the first argument to pass to the invoked method * @param a2 the second argument to pass to the invoked method */ - template - static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2); + static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method @@ -323,10 +318,9 @@ public: * @param a2 the second argument to pass to the invoked method * @param a3 the third argument to pass to the invoked method */ - template - static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3); + static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method @@ -335,11 +329,10 @@ public: * @param a3 the third argument to pass to the invoked method * @param a4 the fourth argument to pass to the invoked method */ - template - static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4); + static EventId ScheduleNow (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method @@ -349,11 +342,10 @@ public: * @param a4 the fourth argument to pass to the invoked method * @param a5 the fifth argument to pass to the invoked method */ - template - static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + static EventId ScheduleNow (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); /** * @param f the function to invoke */ @@ -414,27 +406,25 @@ public: * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method */ - template - static EventId ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj); + template + static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method * @param a1 the first argument to pass to the invoked method */ - template - static EventId ScheduleDestroy (void (T::*mem_ptr) (U1), OBJ obj, T1 a1); + static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method * @param a1 the first argument to pass to the invoked method * @param a2 the second argument to pass to the invoked method */ - template - static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2); + static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method @@ -442,10 +432,9 @@ public: * @param a2 the second argument to pass to the invoked method * @param a3 the third argument to pass to the invoked method */ - template - static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3); + static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method @@ -454,11 +443,10 @@ public: * @param a3 the third argument to pass to the invoked method * @param a4 the fourth argument to pass to the invoked method */ - template - static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4); + static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4); /** * @param mem_ptr member method pointer to invoke * @param obj the object on which to invoke the member method @@ -468,11 +456,10 @@ public: * @param a4 the fourth argument to pass to the invoked method * @param a5 the fifth argument to pass to the invoked method */ - template - static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); /** * @param f the function to invoke */ @@ -569,29 +556,24 @@ private: Simulator (); ~Simulator (); - template - static Ptr MakeEvent (void (T::*mem_ptr) (void), OBJ obj); - template + static Ptr MakeEvent (MEM mem_ptr, OBJ obj); + template - static Ptr MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1); - template MakeEvent (MEM mem_ptr, OBJ obj, T1 a1); + template - static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2); - template MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2); + template - static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3); - template MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3); + template - static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); - template MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); + template - static Ptr MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + static Ptr MakeEvent (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); static Ptr MakeEvent (void (*f) (void)); template @@ -649,14 +631,13 @@ struct EventMemberImplObjTraits } }; -template -Ptr Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) +template +Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj) { // zero argument version class EventMemberImpl0 : public EventImpl { public: - typedef void (T::*F)(void); - EventMemberImpl0 (OBJ obj, F function) + EventMemberImpl0 (OBJ obj, MEM function) : m_obj (obj), m_function (function) {} @@ -666,22 +647,20 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (); } OBJ m_obj; - F m_function; + MEM m_function; } * ev = new EventMemberImpl0 (obj, mem_ptr); return Ptr (ev, false); } -template -Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) +Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1) { // one argument version class EventMemberImpl1 : public EventImpl { public: - typedef void (T::*F)(U1); - EventMemberImpl1 (OBJ obj, F function, T1 a1) + EventMemberImpl1 (OBJ obj, MEM function, T1 a1) : m_obj (obj), m_function (function), m_a1 (a1) @@ -693,23 +672,20 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1); } OBJ m_obj; - F m_function; + MEM m_function; typename TypeTraits::ReferencedType m_a1; } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); return Ptr (ev, false); } -template -Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) +Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) { // two argument version class EventMemberImpl2 : public EventImpl { public: - typedef void (T::*F)(U1, U2); - - EventMemberImpl2 (OBJ obj, F function, T1 a1, T2 a2) + EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2) : m_obj (obj), m_function (function), m_a1 (a1), @@ -722,24 +698,21 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2); } OBJ m_obj; - F m_function; + MEM m_function; typename TypeTraits::ReferencedType m_a1; typename TypeTraits::ReferencedType m_a2; } *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2); return Ptr (ev, false); } -template -Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) +Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) { // three argument version class EventMemberImpl3 : public EventImpl { public: - typedef void (T::*F)(U1,U2,U3); - - EventMemberImpl3 (OBJ obj, F function, T1 a1, T2 a2, T3 a3) + EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3) : m_obj (obj), m_function (function), m_a1 (a1), @@ -753,7 +726,7 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3); } OBJ m_obj; - F m_function; + MEM m_function; typename TypeTraits::ReferencedType m_a1; typename TypeTraits::ReferencedType m_a2; typename TypeTraits::ReferencedType m_a3; @@ -761,17 +734,14 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 return Ptr (ev, false); } -template -Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) +Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) { // four argument version class EventMemberImpl4 : public EventImpl { public: - typedef void (T::*F)(U1, U2, U3, U4); - - EventMemberImpl4 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4) + EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4) : m_obj (obj), m_function (function), m_a1 (a1), @@ -786,7 +756,7 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4); } OBJ m_obj; - F m_function; + MEM m_function; typename TypeTraits::ReferencedType m_a1; typename TypeTraits::ReferencedType m_a2; typename TypeTraits::ReferencedType m_a3; @@ -795,18 +765,15 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, return Ptr (ev, false); } -template -Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) +Ptr Simulator::MakeEvent (MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { // five argument version class EventMemberImpl5 : public EventImpl { public: - typedef void (T::*F)(U1, U2, U3, U4, U5); - - EventMemberImpl5 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) : m_obj (obj), m_function (function), m_a1 (a1), @@ -822,7 +789,7 @@ Ptr Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ ob (EventMemberImplObjTraits::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); } OBJ m_obj; - F m_function; + MEM m_function; typename TypeTraits::ReferencedType m_a1; typename TypeTraits::ReferencedType m_a2; typename TypeTraits::ReferencedType m_a3; @@ -975,50 +942,45 @@ Ptr Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T return Ptr (ev, false); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj) +template +EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj) { return Schedule (time, MakeEvent (mem_ptr, obj)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1), OBJ obj, T1 a1) +EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1) { return Schedule (time, MakeEvent (mem_ptr, obj, a1)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) +EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2) { return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) +EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) { return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) +EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) { return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, - T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) +EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, + T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5)); } @@ -1060,55 +1022,50 @@ EventId Simulator::Schedule (Time const &time, void (*f) (U1,U2,U3,U4,U5), T1 a1 -template +template EventId -Simulator::ScheduleNow (void (T::*mem_ptr) (void), OBJ obj) +Simulator::ScheduleNow (MEM mem_ptr, OBJ obj) { return ScheduleNow (MakeEvent (mem_ptr, obj)); } -template EventId -Simulator::ScheduleNow (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) +Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1) { return ScheduleNow (MakeEvent (mem_ptr, obj, a1)); } -template EventId -Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) +Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) { return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2)); } -template EventId -Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) +Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) { return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3)); } -template EventId -Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) +Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) { return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4)); } -template EventId -Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, +Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5)); @@ -1156,55 +1113,50 @@ Simulator::ScheduleNow (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, -template +template EventId -Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj) +Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj) { return ScheduleDestroy (MakeEvent (mem_ptr, obj)); } -template EventId -Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) +Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1) { return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1)); } -template EventId -Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) +Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) { return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2)); } -template EventId -Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) +Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) { return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3)); } -template EventId -Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) +Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) { return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4)); } -template EventId -Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, +Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5)); From 490d38c9f1ffd62a56999f1cce5f8f6fd1adb5ef Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Fri, 24 Aug 2007 15:11:08 +0200 Subject: [PATCH 265/278] fix last errors for new tests --- src/simulator/simulator.cc | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index e13c3976f..6ee0340fd 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -539,8 +539,8 @@ class SimulatorTests : public Test { public: SimulatorTests (); // only here for testing of Ptr<> - void Ref (void); - void Unref (void); + void Ref (void) const; + void Unref (void) const; virtual ~SimulatorTests (); virtual bool RunTests (void); private: @@ -602,10 +602,10 @@ SimulatorTests::SimulatorTests () SimulatorTests::~SimulatorTests () {} void -SimulatorTests::Ref (void) +SimulatorTests::Ref (void) const {} void -SimulatorTests::Unref (void) +SimulatorTests::Unref (void) const {} uint64_t SimulatorTests::NowUs (void) @@ -802,12 +802,12 @@ SimulatorTests::RunTestsConst (void) const Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, this, 0, 0, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, this, 0, 0, 0, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, this, 0, 0, 0, 0, 0); - Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr (this)); - Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr (this), 0); - Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr (this), 0, 0); - Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr (this), 0, 0, 0); - Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); - Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr (this)); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr (this), 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr (this), 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr (this), 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1c, this, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2c, this, 0, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3c, this, 0, 0, 0); @@ -824,12 +824,12 @@ SimulatorTests::RunTestsConst (void) const Simulator::ScheduleNow (&SimulatorTests::cbaz3c, this, 0, 0, 0); Simulator::ScheduleNow (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0); Simulator::ScheduleNow (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0); - Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr (this)); - Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr (this), 0); - Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr (this), 0, 0); - Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr (this), 0, 0, 0); - Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); - Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr (this)); + Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr (this), 0); + Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr (this), 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr (this), 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); Simulator::ScheduleDestroy (&SimulatorTests::bar0c, this); Simulator::ScheduleDestroy (&SimulatorTests::bar1c, this, 0); Simulator::ScheduleDestroy (&SimulatorTests::bar2c, this, 0, 0); @@ -841,12 +841,12 @@ SimulatorTests::RunTestsConst (void) const Simulator::ScheduleDestroy (&SimulatorTests::cbaz3c, this, 0, 0, 0); Simulator::ScheduleDestroy (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0); Simulator::ScheduleDestroy (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0); - Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr (this)); - Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr (this), 0); - Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr (this), 0, 0); - Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr (this), 0, 0, 0); - Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); - Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr (this)); + Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr (this), 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr (this), 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr (this), 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr (this), 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr (this), 0, 0, 0, 0, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1c, this, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2c, this, 0, 0); Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3c, this, 0, 0, 0); From 391b3eef1195f57b643855b5cb2bdb46a3e470a6 Mon Sep 17 00:00:00 2001 From: George Riley Date: Fri, 24 Aug 2007 11:44:11 -0400 Subject: [PATCH 266/278] Change the protocol stack processing to pass packets by non-const reference, rather than const reference and value as was previously done. Also change the queue semantics to return the packet on a deque, rather than requiring a packet as a parameter. The problem with the original approach was that packet UID's were getting skipped. The fix handles the uid properly, and we get sequential packet uid's on the trace file. --- examples/wscript | 4 ++ samples/main-simple.cc | 3 +- src/applications/onoff-application.cc | 3 +- src/devices/csma/csma-net-device.cc | 60 ++++++++----------- src/devices/csma/csma-net-device.h | 4 +- .../point-to-point-net-device.cc | 27 ++++----- .../point-to-point-net-device.h | 2 +- src/internet-node/arp-l3-protocol.cc | 5 +- src/internet-node/arp-l3-protocol.h | 2 +- src/internet-node/ipv4-end-point.cc | 4 +- src/internet-node/ipv4-end-point.h | 6 +- src/internet-node/ipv4-l3-protocol.cc | 29 ++++----- src/internet-node/ipv4-l3-protocol.h | 12 ++-- src/internet-node/ipv4-static-routing.cc | 2 +- src/internet-node/ipv4-static-routing.h | 2 +- src/internet-node/udp-l4-protocol.cc | 2 +- src/internet-node/udp-l4-protocol.h | 2 +- src/internet-node/udp-socket.cc | 13 ++-- src/internet-node/udp-socket.h | 10 ++-- src/node/drop-tail-queue.cc | 35 ++++------- src/node/drop-tail-queue.h | 4 +- src/node/ipv4.h | 6 +- src/node/net-device.cc | 4 +- src/node/net-device.h | 8 +-- src/node/node.cc | 2 +- src/node/node.h | 4 +- src/node/packet-socket.cc | 10 ++-- src/node/packet-socket.h | 6 +- src/node/queue.cc | 42 +++++++------ src/node/queue.h | 14 +++-- src/node/socket.h | 4 +- 31 files changed, 152 insertions(+), 179 deletions(-) diff --git a/examples/wscript b/examples/wscript index e5e771555..cb0af9530 100644 --- a/examples/wscript +++ b/examples/wscript @@ -10,6 +10,10 @@ def build(bld): ['point-to-point', 'internet-node']) obj.source = 'simple-point-to-point.cc' + obj = bld.create_ns3_program('really-simple-point-to-point', + ['point-to-point', 'internet-node']) + obj.source = 'really-simple-point-to-point.cc' + obj = bld.create_ns3_program('csma-one-subnet', ['csma', 'internet-node']) obj.source = 'csma-one-subnet.cc' diff --git a/samples/main-simple.cc b/samples/main-simple.cc index 7285f4946..2039a55c3 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -14,7 +14,8 @@ static void GenerateTraffic (Ptr socket, uint32_t size) { std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl; - socket->Send (Packet (size)); + Packet p(size); + socket->Send (p); if (size > 0) { Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); diff --git a/src/applications/onoff-application.cc b/src/applications/onoff-application.cc index 32bcd7564..512c454f3 100644 --- a/src/applications/onoff-application.cc +++ b/src/applications/onoff-application.cc @@ -206,7 +206,8 @@ void OnOffApplication::ScheduleStopEvent() void OnOffApplication::SendPacket() { NS_ASSERT (m_sendEvent.IsExpired ()); - m_socket->Send(Packet (m_pktSize)); + Packet p(m_pktSize); + m_socket->Send(p); m_totBytes += m_pktSize; m_lastStartTime = Simulator::Now(); m_residualBits = 0; diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index 531bf7314..610ec9b6c 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -274,13 +274,12 @@ CsmaNetDevice::DoNeedsArp (void) const bool CsmaNetDevice::SendTo ( - const Packet& packet, + Packet& packet, const Address& dest, uint16_t protocolNumber) { - Packet p = packet; - NS_DEBUG ("CsmaNetDevice::SendTo (" << &p << ")"); - NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << p.GetUid () << ")"); + NS_DEBUG ("CsmaNetDevice::SendTo (" << &packet << ")"); + NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << packet.GetUid () << ")"); NS_ASSERT (IsLinkUp ()); @@ -289,10 +288,10 @@ CsmaNetDevice::SendTo ( return false; Eui48Address destination = Eui48Address::ConvertFrom (dest); - AddHeader(p, destination, protocolNumber); + AddHeader(packet, destination, protocolNumber); // Place the packet to be sent on the send queue - if (m_queue->Enqueue(p) == false ) + if (m_queue->Enqueue(packet) == false ) { return false; } @@ -301,11 +300,10 @@ CsmaNetDevice::SendTo ( // transmission (see TransmitCompleteEvent) if (m_txMachineState == READY) { + if (m_queue->IsEmpty()) return true; // Nothing else to do // Store the next packet to be transmitted - if (m_queue->Dequeue (m_currentPkt)) - { - TransmitStart(); - } + m_currentPkt = m_queue->Dequeue(); + TransmitStart(); } return true; } @@ -389,9 +387,8 @@ CsmaNetDevice::TransmitAbort (void) m_currentPkt.GetUid () << ")"); // Try to transmit a new packet - bool found; - found = m_queue->Dequeue (m_currentPkt); - NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); + if (m_queue->IsEmpty()) return; //No packet to transmit + m_currentPkt = m_queue->Dequeue (); m_backoff.ResetBackoffTime(); m_txMachineState = READY; TransmitStart (); @@ -438,18 +435,10 @@ CsmaNetDevice::TransmitReadyEvent (void) NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); m_txMachineState = READY; + if (m_queue->IsEmpty()) return; // No more to transmit, remain ready // Get the next packet from the queue for transmitting - if (m_queue->IsEmpty()) - { - return; - } - else - { - bool found; - found = m_queue->Dequeue (m_currentPkt); - NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); - TransmitStart (); - } + m_currentPkt = m_queue->Dequeue (); + TransmitStart (); } TraceResolver * @@ -495,32 +484,31 @@ CsmaNetDevice::AddQueue (Ptr q) } void -CsmaNetDevice::Receive (const Packet& packet) +CsmaNetDevice::Receive (Packet& packet) { EthernetHeader header (false); EthernetTrailer trailer; Eui48Address broadcast; Eui48Address destination; - Packet p = packet; - NS_DEBUG ("CsmaNetDevice::Receive UID is (" << p.GetUid() << ")"); + NS_DEBUG ("CsmaNetDevice::Receive UID is (" << packet.GetUid() << ")"); // Only receive if send side of net device is enabled if (!IsReceiveEnabled()) { - m_dropTrace (p); + m_dropTrace (packet); return; } if (m_encapMode == RAW) { ForwardUp (packet, 0, GetBroadcast ()); - m_dropTrace (p); + //m_dropTrace (packet); return; } - p.RemoveTrailer(trailer); - trailer.CheckFcs(p); - p.RemoveHeader(header); + packet.RemoveTrailer(trailer); + trailer.CheckFcs(packet); + packet.RemoveHeader(header); broadcast = Eui48Address::ConvertFrom (GetBroadcast ()); destination = Eui48Address::ConvertFrom (GetAddress ()); @@ -528,11 +516,11 @@ CsmaNetDevice::Receive (const Packet& packet) (header.GetDestination() != destination)) { // not for us. - m_dropTrace (p); + m_dropTrace (packet); return; } - m_rxTrace (p); + m_rxTrace (packet); // // protocol must be initialized to avoid a compiler warning in the RAW // case that breaks the optimized build. @@ -547,7 +535,7 @@ CsmaNetDevice::Receive (const Packet& packet) break; case LLC: { LlcSnapHeader llc; - p.RemoveHeader (llc); + packet.RemoveHeader (llc); protocol = llc.GetType (); } break; case RAW: @@ -555,7 +543,7 @@ CsmaNetDevice::Receive (const Packet& packet) break; } - ForwardUp (p, protocol, header.GetSource ()); + ForwardUp (packet, protocol, header.GetSource ()); return; } diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 441ea04cd..95b89e9fc 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -195,7 +195,7 @@ enum CsmaEncapsulationMode { * @see CsmaChannel * \param p a reference to the received packet */ - void Receive (const Packet& p); + void Receive (Packet& p); bool IsSendEnabled (void); bool IsReceiveEnabled (void); @@ -270,7 +270,7 @@ private: * \param protocolNumber -- this parameter is not used here * \return true if success, false on failure */ - virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber); + virtual bool SendTo (Packet& p, const Address& dest, uint16_t protocolNumber); /** * Start Sending a Packet Down the Wire. diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index a071f9246..2cb026062 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -117,18 +117,17 @@ void PointToPointNetDevice::SetInterframeGap(const Time& t) m_tInterframeGap = t; } -bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest, +bool PointToPointNetDevice::SendTo (Packet& packet, const Address& dest, uint16_t protocolNumber) { - Packet p = packet; - NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); - NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); + NS_DEBUG ("PointToPointNetDevice::SendTo (" << &packet << ", " << &dest << ")"); + NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << packet.GetUid () << ")"); // GFR Comment. Why is this an assertion? Can't a link legitimately // "go down" during the simulation? Shouldn't we just wait for it // to come back up? NS_ASSERT (IsLinkUp ()); - AddHeader(p, protocolNumber); + AddHeader(packet, protocolNumber); // // This class simulates a point to point device. In the case of a serial @@ -139,16 +138,16 @@ bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest, // trnsmission; otherwise we send it now. if (m_txMachineState == READY) { - return TransmitStart (p); + return TransmitStart (packet); } else { - return m_queue->Enqueue(p); + return m_queue->Enqueue(packet); } } bool -PointToPointNetDevice::TransmitStart (Packet &p) +PointToPointNetDevice::TransmitStart (Packet& p) { NS_DEBUG ("PointToPointNetDevice::TransmitStart (" << &p << ")"); NS_DEBUG ( @@ -184,8 +183,8 @@ void PointToPointNetDevice::TransmitComplete (void) // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); m_txMachineState = READY; - Packet p; - if (!m_queue->Dequeue(p)) return; // Nothing to do at this point + if (m_queue->IsEmpty()) return; // Nothing to do at this point + Packet p = m_queue->Dequeue(); TransmitStart(p); } @@ -236,11 +235,9 @@ void PointToPointNetDevice::Receive (Packet& p) { NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); uint16_t protocol = 0; - Packet packet = p; - - m_rxTrace (packet); - ProcessHeader(packet, protocol); - ForwardUp (packet, protocol, GetBroadcast ()); + m_rxTrace (p); + ProcessHeader(p, protocol); + ForwardUp (p, protocol, GetBroadcast ()); } Ptr PointToPointNetDevice::GetQueue(void) const diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index d8d8d3242..e985b76cd 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -211,7 +211,7 @@ private: * @param protocolNumber Protocol Number used to find protocol touse * @returns true if success, false on failure */ - virtual bool SendTo (const Packet& p, const Address& dest, + virtual bool SendTo (Packet& p, const Address& dest, uint16_t protocolNumber); /** * Start Sending a Packet Down the Wire. diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index 100f1df88..041c50e14 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -84,12 +84,11 @@ ArpL3Protocol::FindCache (Ptr device) } void -ArpL3Protocol::Receive(Ptr device, const Packet& p, uint16_t protocol, const Address &from) +ArpL3Protocol::Receive(Ptr device, Packet& p, uint16_t protocol, const Address &from) { ArpCache *cache = FindCache (device); ArpHeader arp; - Packet packet = p; - packet.RemoveHeader (arp); + p.RemoveHeader (arp); NS_DEBUG ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") << " node="<GetId ()<<", got request from " << diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index a2ea8227e..82d8dd29e 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -53,7 +53,7 @@ public: /** * \brief Recieve a packet */ - void Receive(Ptr device, const Packet& p, uint16_t protocol, const Address &from); + void Receive(Ptr device, Packet& p, uint16_t protocol, const Address &from); /** * \brief Perform an ARP lookup * \param p diff --git a/src/internet-node/ipv4-end-point.cc b/src/internet-node/ipv4-end-point.cc index 69faf523e..cdd78c303 100644 --- a/src/internet-node/ipv4-end-point.cc +++ b/src/internet-node/ipv4-end-point.cc @@ -65,7 +65,7 @@ Ipv4EndPoint::SetPeer (Ipv4Address address, uint16_t port) } void -Ipv4EndPoint::SetRxCallback (Callback callback) +Ipv4EndPoint::SetRxCallback (Callback callback) { m_rxCallback = callback; } @@ -77,7 +77,7 @@ Ipv4EndPoint::SetDestroyCallback (Callback callback) } void -Ipv4EndPoint::ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport) +Ipv4EndPoint::ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport) { if (!m_rxCallback.IsNull ()) { diff --git a/src/internet-node/ipv4-end-point.h b/src/internet-node/ipv4-end-point.h index f606aa63b..06192d500 100644 --- a/src/internet-node/ipv4-end-point.h +++ b/src/internet-node/ipv4-end-point.h @@ -43,17 +43,17 @@ public: void SetPeer (Ipv4Address address, uint16_t port); - void SetRxCallback (Callback callback); + void SetRxCallback (Callback callback); void SetDestroyCallback (Callback callback); - void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport); + void ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport); private: Ipv4Address m_localAddr; uint16_t m_localPort; Ipv4Address m_peerAddr; uint16_t m_peerPort; - Callback m_rxCallback; + Callback m_rxCallback; Callback m_destroyCallback; }; diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index be483dfa0..b44a0a013 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -221,7 +221,7 @@ Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop, void Ipv4L3Protocol::Lookup (Ipv4Header const &ipHeader, - Packet packet, + Packet& packet, Ipv4RoutingProtocol::RouteReplyCallback routeReply) { for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin (); @@ -310,7 +310,7 @@ Ipv4L3Protocol::FindInterfaceForDevice (Ptr device) } void -Ipv4L3Protocol::Receive( Ptr device, const Packet& p, uint16_t protocol, const Address &from) +Ipv4L3Protocol::Receive( Ptr device, Packet& p, uint16_t protocol, const Address &from) { uint32_t index = 0; for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) @@ -322,26 +322,25 @@ Ipv4L3Protocol::Receive( Ptr device, const Packet& p, uint16_t protoc } index++; } - Packet packet = p; Ipv4Header ipHeader; - packet.RemoveHeader (ipHeader); + p.RemoveHeader (ipHeader); if (!ipHeader.IsChecksumOk ()) { return; } - if (Forwarding (packet, ipHeader, device)) + if (Forwarding (p, ipHeader, device)) { return; } - ForwardUp (packet, ipHeader); + ForwardUp (p, ipHeader); } void -Ipv4L3Protocol::Send (Packet const &packet, +Ipv4L3Protocol::Send (Packet& packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol) @@ -365,12 +364,10 @@ Ipv4L3Protocol::Send (Packet const &packet, ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++) { Ipv4Interface *outInterface = *ifaceIter; - Packet packetCopy = packet; - - NS_ASSERT (packetCopy.GetSize () <= outInterface->GetMtu ()); - packetCopy.AddHeader (ipHeader); - m_txTrace (packetCopy, ifaceIndex); - outInterface->Send (packetCopy, destination); + NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ()); + packet.AddHeader (ipHeader); + m_txTrace (packet, ifaceIndex); + outInterface->Send (packet, destination); } } else @@ -391,7 +388,7 @@ Ipv4L3Protocol::Send (Packet const &packet, void Ipv4L3Protocol::SendRealOut (bool found, Ipv4Route const &route, - Packet packet, + Packet& packet, Ipv4Header const &ipHeader) { if (!found) @@ -416,7 +413,7 @@ Ipv4L3Protocol::SendRealOut (bool found, bool -Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr device) +Ipv4L3Protocol::Forwarding (Packet& packet, Ipv4Header &ipHeader, Ptr device) { for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) @@ -471,7 +468,7 @@ Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr demux = m_node->QueryInterface (Ipv4L4Demux::iid); Ptr protocol = demux->GetProtocol (ip.GetProtocol ()); diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index 2cce3efa3..8254f27e6 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -118,7 +118,7 @@ public: * - implement a per-NetDevice ARP cache * - send back arp replies on the right device */ - void Receive( Ptr device, const Packet& p, uint16_t protocol, const Address &from); + void Receive( Ptr device, Packet& p, uint16_t protocol, const Address &from); /** * \param packet packet to send @@ -129,7 +129,7 @@ public: * Higher-level layers call this method to send a packet * down the stack to the MAC and PHY layers. */ - void Send (Packet const &packet, Ipv4Address source, + void Send (Packet& packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol); @@ -151,7 +151,7 @@ public: uint32_t interface); void Lookup (Ipv4Header const &ipHeader, - Packet packet, + Packet& packet, Ipv4RoutingProtocol::RouteReplyCallback routeReply); uint32_t GetNRoutes (void); @@ -183,10 +183,10 @@ private: void SendRealOut (bool found, Ipv4Route const &route, - Packet packet, + Packet& packet, Ipv4Header const &ipHeader); - bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr device); - void ForwardUp (Packet p, Ipv4Header const&ip); + bool Forwarding (Packet& packet, Ipv4Header &ipHeader, Ptr device); + void ForwardUp (Packet& p, Ipv4Header const&ip); uint32_t AddIpv4Interface (Ipv4Interface *interface); void SetupLoopback (void); TraceResolver *InterfacesCreateTraceResolver (TraceContext const &context) const; diff --git a/src/internet-node/ipv4-static-routing.cc b/src/internet-node/ipv4-static-routing.cc index b70c1c1af..37e8a74df 100644 --- a/src/internet-node/ipv4-static-routing.cc +++ b/src/internet-node/ipv4-static-routing.cc @@ -210,7 +210,7 @@ Ipv4StaticRouting::RemoveRoute (uint32_t index) bool Ipv4StaticRouting::RequestRoute (Ipv4Header const &ipHeader, - Packet packet, + Packet& packet, RouteReplyCallback routeReply) { Ipv4Route *route = LookupStatic (ipHeader.GetDestination ()); diff --git a/src/internet-node/ipv4-static-routing.h b/src/internet-node/ipv4-static-routing.h index 8462f55a7..439af8cf7 100644 --- a/src/internet-node/ipv4-static-routing.h +++ b/src/internet-node/ipv4-static-routing.h @@ -52,7 +52,7 @@ public: Ipv4StaticRouting () : m_defaultRoute (0) {} virtual bool RequestRoute (Ipv4Header const &ipHeader, - Packet packet, + Packet& packet, RouteReplyCallback routeReply); diff --git a/src/internet-node/udp-l4-protocol.cc b/src/internet-node/udp-l4-protocol.cc index f0ef8569b..9dacbf961 100644 --- a/src/internet-node/udp-l4-protocol.cc +++ b/src/internet-node/udp-l4-protocol.cc @@ -122,7 +122,7 @@ UdpL4Protocol::Receive(Packet& packet, } void -UdpL4Protocol::Send (Packet packet, +UdpL4Protocol::Send (Packet& packet, Ipv4Address saddr, Ipv4Address daddr, uint16_t sport, uint16_t dport) { diff --git a/src/internet-node/udp-l4-protocol.h b/src/internet-node/udp-l4-protocol.h index 4d7a082d4..70e2b0ccc 100644 --- a/src/internet-node/udp-l4-protocol.h +++ b/src/internet-node/udp-l4-protocol.h @@ -74,7 +74,7 @@ public: * \param sport The source port number * \param dport The destination port number */ - void Send (Packet packet, + void Send (Packet& packet, Ipv4Address saddr, Ipv4Address daddr, uint16_t sport, uint16_t dport); /** diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index a2bde3224..45b8b82b6 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -155,7 +155,7 @@ UdpSocket::Connect(const Address & address) return 0; } int -UdpSocket::Send (const Packet &p) +UdpSocket::Send (Packet &p) { if (!m_connected) { @@ -165,7 +165,7 @@ UdpSocket::Send (const Packet &p) return DoSendTo (p, m_defaultAddress, m_defaultPort); } int -UdpSocket::DoSendTo (const Packet &p, const Address &address) +UdpSocket::DoSendTo (Packet &p, const Address &address) { InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); @@ -173,7 +173,7 @@ UdpSocket::DoSendTo (const Packet &p, const Address &address) return DoSendTo (p, ipv4, port); } int -UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port) +UdpSocket::DoSendTo (Packet& p, Ipv4Address ipv4, uint16_t port) { if (m_endPoint == 0) { @@ -195,7 +195,7 @@ UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port) return 0; } int -UdpSocket::SendTo(const Address &address, const Packet &p) +UdpSocket::SendTo(const Address &address, Packet &p) { if (m_connected) { @@ -209,7 +209,7 @@ UdpSocket::SendTo(const Address &address, const Packet &p) } void -UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) +UdpSocket::ForwardUp (Packet &packet, Ipv4Address ipv4, uint16_t port) { if (m_shutdownRecv) { @@ -217,8 +217,7 @@ UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) } Address address = InetSocketAddress (ipv4, port); - Packet p = packet; - NotifyDataReceived (p, address); + NotifyDataReceived (packet, address); } }//namespace ns3 diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket.h index b3674f7ef..9ceec713f 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket.h @@ -51,8 +51,8 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (const Packet &p); - virtual int SendTo(const Address &address,const Packet &p); + virtual int Send (Packet &p); + virtual int SendTo(const Address &address,Packet &p); private: @@ -60,10 +60,10 @@ private: friend class Udp; // invoked by Udp class int FinishBind (void); - void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port); + void ForwardUp (Packet &p, Ipv4Address ipv4, uint16_t port); void Destroy (void); - int DoSendTo (const Packet &p, const Address &daddr); - int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport); + int DoSendTo (Packet &p, const Address &daddr); + int DoSendTo (Packet &p, Ipv4Address daddr, uint16_t dport); Ipv4EndPoint *m_endPoint; Ptr m_node; diff --git a/src/node/drop-tail-queue.cc b/src/node/drop-tail-queue.cc index 74c8fde17..5b802acec 100644 --- a/src/node/drop-tail-queue.cc +++ b/src/node/drop-tail-queue.cc @@ -73,39 +73,26 @@ DropTailQueue::DoEnqueue (const Packet& p) return true; } -bool -DropTailQueue::DoDequeue (Packet& p) +Packet +DropTailQueue::DoDequeue () { - NS_DEBUG("DropTailQueue::DoDequeue (" << &p << ")"); - - if (m_packets.empty()) - { - NS_DEBUG("DropTailQueue::DoDequeue (): Queue empty"); - return false; - } - - p = m_packets.front (); + NS_DEBUG("DropTailQueue::DoDequeue ( )"); + NS_ASSERT(!IsEmpty()); + Packet p = m_packets.front (); m_packets.pop (); NS_DEBUG("DropTailQueue::DoDequeue (): Popped " << &p << " <= true"); - return true; + return p; } -bool -DropTailQueue::DoPeek (Packet& p) +Packet +DropTailQueue::DoPeek () { - NS_DEBUG("DropTailQueue::DoPeek (" << &p << ")"); + NS_DEBUG("DropTailQueue::DoPeek ( )"); + NS_ASSERT(!IsEmpty()); - if (m_packets.empty()) - { - NS_DEBUG("DropTailQueue::DoPeek (): Queue empty"); - return false; - } - - p = m_packets.front (); - - return true; + return m_packets.front (); } }; // namespace ns3 diff --git a/src/node/drop-tail-queue.h b/src/node/drop-tail-queue.h index 2e4c76461..6febe0eab 100644 --- a/src/node/drop-tail-queue.h +++ b/src/node/drop-tail-queue.h @@ -58,8 +58,8 @@ public: private: virtual bool DoEnqueue (const Packet& p); - virtual bool DoDequeue (Packet &p); - virtual bool DoPeek (Packet &p); + virtual Packet DoDequeue (); + virtual Packet DoPeek (); private: std::queue m_packets; diff --git a/src/node/ipv4.h b/src/node/ipv4.h index 76d88faea..b4d22c520 100644 --- a/src/node/ipv4.h +++ b/src/node/ipv4.h @@ -46,7 +46,7 @@ class Ipv4Header; // FIXME: ipv4-header.h needs to move from module class Ipv4RoutingProtocol : public Object { public: - // void (*RouteReply) (bool found, Ipv4Route route, Packet packet, Ipv4Header const &ipHeader); + // void (*RouteReply) (bool found, Ipv4Route route, Packet& packet, Ipv4Header const &ipHeader); /** @@ -65,7 +65,7 @@ public: * inserted and consequently the protocol type has to change). * */ - typedef Callback RouteReplyCallback; + typedef Callback RouteReplyCallback; /** * \brief Asynchronously requests a route for a given packet and IP header @@ -100,7 +100,7 @@ public: * insert any extra header. */ virtual bool RequestRoute (const Ipv4Header &ipHeader, - Packet packet, + Packet& packet, RouteReplyCallback routeReply) = 0; }; diff --git a/src/node/net-device.cc b/src/node/net-device.cc index 1ffe6d4b1..965bf78b8 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -171,7 +171,7 @@ NetDevice::DisablePointToPoint (void) // Receive packet from above bool -NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber) +NetDevice::Send(Packet& p, const Address& dest, uint16_t protocolNumber) { if (m_isUp) { @@ -197,7 +197,7 @@ NetDevice::GetChannel (void) const // Receive packets from below bool -NetDevice::ForwardUp(const Packet& p, uint32_t param, const Address &from) +NetDevice::ForwardUp( Packet& p, uint32_t param, const Address &from) { bool retval = false; diff --git a/src/node/net-device.h b/src/node/net-device.h index 315f16033..0fb21e0fb 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -158,7 +158,7 @@ public: * * \return whether the Send operation succeeded */ - bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber); + bool Send(Packet& p, const Address& dest, uint16_t protocolNumber); /** * \returns the node base class which contains this network * interface. @@ -187,7 +187,7 @@ public: * \returns true if the callback could handle the packet successfully, false * otherwise. */ - typedef Callback,const Packet &,uint16_t,const Address &> ReceiveCallback; + typedef Callback,Packet &,uint16_t,const Address &> ReceiveCallback; /** * \param cb callback to invoke whenever a packet has been received and must @@ -251,7 +251,7 @@ public: * forwards it to the higher layers by calling this method * which is responsible for passing it up to the Rx callback. */ - bool ForwardUp (const Packet& p, uint32_t param, const Address &address); + bool ForwardUp (Packet& p, uint32_t param, const Address &address); /** @@ -274,7 +274,7 @@ public: * method. When the link is Up, this method is invoked to ask * subclasses to forward packets. Subclasses MUST override this method. */ - virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0; + virtual bool SendTo (Packet& p, const Address &dest, uint16_t protocolNumber) = 0; /** * \returns true if this NetDevice needs the higher-layers * to perform ARP over it, false otherwise. diff --git a/src/node/node.cc b/src/node/node.cc index ee83e8588..5fdd50bb8 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -213,7 +213,7 @@ Node::UnregisterProtocolHandler (ProtocolHandler handler) } bool -Node::ReceiveFromDevice (Ptr device, const Packet &packet, +Node::ReceiveFromDevice (Ptr device, Packet &packet, uint16_t protocol, const Address &from) { bool found = false; diff --git a/src/node/node.h b/src/node/node.h index f4d898f53..1538350be 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -158,7 +158,7 @@ public: /** * A protocol handler */ - typedef Callback, const Packet &,uint16_t,const Address &> ProtocolHandler; + typedef Callback, Packet &,uint16_t,const Address &> ProtocolHandler; /** * \param handler the handler to register * \param protocolType the type of protocol this handler is @@ -210,7 +210,7 @@ private: */ virtual void NotifyDeviceAdded (Ptr device); - bool ReceiveFromDevice (Ptr device, const Packet &packet, + bool ReceiveFromDevice (Ptr device, Packet &packet, uint16_t protocol, const Address &from); void Construct (void); TraceResolver *CreateDevicesTraceResolver (const TraceContext &context); diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index f642eee9e..7e0095d79 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -186,7 +186,7 @@ PacketSocket::Connect(const Address &ad) } int -PacketSocket::Send (const Packet &p) +PacketSocket::Send (Packet &p) { if (m_state == STATE_OPEN || m_state == STATE_BOUND) @@ -198,7 +198,7 @@ PacketSocket::Send (const Packet &p) } int -PacketSocket::SendTo(const Address &address, const Packet &p) +PacketSocket::SendTo(const Address &address, Packet &p) { PacketSocketAddress ad; if (m_state == STATE_CLOSED) @@ -262,7 +262,7 @@ PacketSocket::SendTo(const Address &address, const Packet &p) } void -PacketSocket::ForwardUp (Ptr device, const Packet &packet, +PacketSocket::ForwardUp (Ptr device, Packet &packet, uint16_t protocol, const Address &from) { if (m_shutdownRecv) @@ -270,7 +270,7 @@ PacketSocket::ForwardUp (Ptr device, const Packet &packet, return; } - Packet p = packet; + //Packet p = packet; ? PacketSocketAddress address; address.SetPhysicalAddress (from); @@ -279,7 +279,7 @@ PacketSocket::ForwardUp (Ptr device, const Packet &packet, NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid() << " PacketSocket " << this); - NotifyDataReceived (p, address); + NotifyDataReceived (packet, address); } }//namespace ns3 diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index 8dc1b9e62..be4ade908 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -82,15 +82,15 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (const Packet &p); - virtual int SendTo(const Address &address,const Packet &p); + virtual int Send (Packet &p); + virtual int SendTo(const Address &address,Packet &p); private: private: void Init (void); - void ForwardUp (Ptr device, const Packet &packet, + void ForwardUp (Ptr device, Packet &packet, uint16_t protocol, const Address &from); int DoBind (const PacketSocketAddress &address); virtual void DoDispose (void); diff --git a/src/node/queue.cc b/src/node/queue.cc index 72eafed69..ad79109c0 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -49,7 +49,7 @@ QueueTraceType::IsEnqueue (void) const { return m_type == ENQUEUE; } -bool +bool QueueTraceType::IsDequeue (void) const { return m_type == DEQUEUE; @@ -122,28 +122,25 @@ Queue::Enqueue (const Packet& p) return retval; } -bool -Queue::Dequeue (Packet &p) +Packet +Queue::Dequeue () { - NS_DEBUG("Queue::Dequeue (" << &p << ")"); + NS_ASSERT(!IsEmpty()); + NS_DEBUG("Queue::Dequeue ( )"); - bool retval = DoDequeue (p); + Packet p = DoDequeue (); - if (retval) - { - m_nBytes -= p.GetSize (); - m_nPackets--; + m_nBytes -= p.GetSize (); + m_nPackets--; + + NS_ASSERT (m_nBytes >= 0); + NS_ASSERT (m_nPackets >= 0); + + NS_DEBUG("Queue::Dequeue (): m_traceDequeue (p)"); - NS_ASSERT (m_nBytes >= 0); - NS_ASSERT (m_nPackets >= 0); + m_traceDequeue (p); - NS_DEBUG("Queue::Dequeue (): m_traceDequeue (p)"); - - const Packet packet = p; - m_traceDequeue (packet); - } - - return retval; + return p; } void @@ -154,12 +151,13 @@ Queue::DequeueAll (void) NS_ASSERT (!"Don't know what to do with dequeued packets!"); } -bool -Queue::Peek (Packet &p) +Packet +Queue::Peek () { - NS_DEBUG("Queue::Peek (" << &p << ")"); + NS_ASSERT(!IsEmpty()); + NS_DEBUG("Queue::Peek ( )"); - return DoPeek (p); + return DoPeek (); } diff --git a/src/node/queue.h b/src/node/queue.h index d135fff68..915642f09 100644 --- a/src/node/queue.h +++ b/src/node/queue.h @@ -83,14 +83,16 @@ public: bool Enqueue (const Packet& p); /** * Remove a packet from the front of the Queue - * \return True if the operation was successful; false otherwise + * Must not be called on an empty queue. + * \return The packet removed from the queue */ - bool Dequeue (Packet &p); + Packet Dequeue (); /** * Get a copy of the item at the front of the queue without removing it - * \return True if the operation was successful; false otherwise + * Must NOT be called on an empty queue + * \return The packet at the head of the queue. */ - bool Peek (Packet &p); + Packet Peek (); /** * XXX Doesn't do anything right now, think its supposed to flush the queue @@ -163,8 +165,8 @@ public: private: virtual bool DoEnqueue (const Packet& p) = 0; - virtual bool DoDequeue (Packet &p) = 0; - virtual bool DoPeek (Packet &p) = 0; + virtual Packet DoDequeue () = 0; + virtual Packet DoPeek () = 0; protected: // called by subclasses to notify parent of packet drops. diff --git a/src/node/socket.h b/src/node/socket.h index c717ec0a5..1a28bd71d 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -173,7 +173,7 @@ public: * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int Send (const Packet &p) = 0; + virtual int Send (Packet &p) = 0; /** * \brief Send data to a specified peer. @@ -182,7 +182,7 @@ public: * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int SendTo(const Address &address,const Packet &p) = 0; + virtual int SendTo(const Address &address,Packet &p) = 0; protected: void NotifyCloseCompleted (void); From 027cd21aa1b9fc9492a2f0c533f07e99257e9d3b Mon Sep 17 00:00:00 2001 From: Raj Bhattacharjea Date: Fri, 24 Aug 2007 13:21:33 -0400 Subject: [PATCH 267/278] Added GPL and emacs modeline to inet-socket-address.h/cc --- src/node/inet-socket-address.cc | 21 +++++++++++++++++++++ src/node/inet-socket-address.h | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/node/inet-socket-address.cc b/src/node/inet-socket-address.cc index 58b589586..d4b7453a9 100644 --- a/src/node/inet-socket-address.cc +++ b/src/node/inet-socket-address.cc @@ -1,3 +1,24 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + #include "inet-socket-address.h" #include "ns3/assert.h" diff --git a/src/node/inet-socket-address.h b/src/node/inet-socket-address.h index 0a00172ba..ec3782393 100644 --- a/src/node/inet-socket-address.h +++ b/src/node/inet-socket-address.h @@ -1,3 +1,24 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + #ifndef IPV4_TRANSPORT_ADDRESS_H #define IPV4_TRANSPORT_ADDRESS_H From 9bf17256fbf13f34ee1eab6b34d290225a980f95 Mon Sep 17 00:00:00 2001 From: Raj Bhattacharjea Date: Fri, 24 Aug 2007 14:00:52 -0400 Subject: [PATCH 268/278] Fixed inet-socket-address's opening IFDEF to be consistent with the filename --- src/node/inet-socket-address.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/inet-socket-address.h b/src/node/inet-socket-address.h index ec3782393..d6727342f 100644 --- a/src/node/inet-socket-address.h +++ b/src/node/inet-socket-address.h @@ -19,8 +19,8 @@ * Author: Mathieu Lacage */ -#ifndef IPV4_TRANSPORT_ADDRESS_H -#define IPV4_TRANSPORT_ADDRESS_H +#ifndef INET_SOCKET_ADDRESS_H +#define INET_SOCKET_ADDRESS_H #include "address.h" #include "ipv4-address.h" @@ -114,4 +114,4 @@ private: } // namespace ns3 -#endif /* IPV4_TRANSPORT_ADDRESS_H */ +#endif /* INET_SOCKET_ADDRESS_H */ From bce75ae3a880748b1f14adaa7de03af8d0994645 Mon Sep 17 00:00:00 2001 From: Raj Bhattacharjea Date: Fri, 24 Aug 2007 16:05:17 -0400 Subject: [PATCH 269/278] Removed SConstruct file --- SConstruct | 521 ----------------------------------------------------- 1 file changed, 521 deletions(-) delete mode 100644 SConstruct diff --git a/SConstruct b/SConstruct deleted file mode 100644 index 9c9a2567c..000000000 --- a/SConstruct +++ /dev/null @@ -1,521 +0,0 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -import os.path -import build - -version_file = open ('VERSION', 'r') -version = version_file.readline () -version_file.close () -version = version.strip () - -ns3 = build.Ns3() -ns3.build_dir = 'build-dir' -ns3.version = version -ns3.name = 'ns3' -ns3.distname = 'ns' -ns3.doxygen_config = os.path.join('doc', 'doxygen.conf') -ns3.add_extra_dist(os.path.join('doc', 'main.txt')) -ns3.add_extra_dist ('doc/architecture.pdf') -ns3.add_extra_dist ('doc/contributing.txt') -ns3.add_extra_dist ('doc/build.txt') -ns3.add_extra_dist ('doc/codingstd.txt') -ns3.add_extra_dist ('doc/mercurial.txt') -ns3.add_extra_dist ('README') -ns3.add_extra_dist ('RELEASE_NOTES') -ns3.add_extra_dist ('AUTHORS') -ns3.add_extra_dist ('VERSION') - -ns3.add_extra_dist('doc/build-waf.txt') -ns3.add_extra_dist('ns3/_placeholder_') -for wscript in [ - "src/core/wscript", - "src/node/wscript", - "src/devices/p2p/wscript", - "src/common/wscript", - "src/applications/wscript", - "src/simulator/wscript", - "src/internet-node/wscript", - "src/wscript", - "utils/wscript", - "samples/wscript", - "examples/wscript", - "wscript", - ]: - ns3.add_extra_dist(wscript) -ns3.add_extra_dist('waf') -ns3.add_extra_dist('waf.bat') - -# -# The Core module -# -core = build.Ns3Module('core', 'src/core') -ns3.add(core) -core.add_sources([ - 'callback-test.cc', - 'debug.cc', - 'assert.cc', - 'ptr.cc', - 'object.cc', - 'test.cc', - 'random-variable.cc', - 'rng-stream.cc', - 'uid-manager.cc', - 'default-value.cc', - 'command-line.cc', - 'type-name.cc', - 'component-manager.cc', - ]) -env = Environment() -if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin': - core.add_external_dep('pthread') - core.add_sources([ - 'unix-system-wall-clock-ms.cc', - ]) -elif env['PLATFORM'] == 'win32': - core.add_sources([ - 'win32-system-wall-clock-ms.cc', - ]) -core.add_headers ([ - 'uid-manager.h', - 'singleton.h', -]) -core.add_inst_headers([ - 'system-wall-clock-ms.h', - 'empty.h', - 'callback.h', - 'ptr.h', - 'object.h', - 'debug.h', - 'assert.h', - 'fatal-error.h', - 'test.h', - 'random-variable.h', - 'rng-stream.h', - 'default-value.h', - 'command-line.h', - 'type-name.h', - 'component-manager.h', - ]) - -def config_core (env, config): - retval = [] - # XXX This check is primitive but it should be - # good enough for now. - if config.CheckCHeader ('stdlib.h') == 1: - retval.append ('#define HAVE_STDLIB_H 1') - retval.append ('#define HAVE_GETENV 1') - else: - retval.append ('#undef HAVE_STDLIB_H') - retval.append ('#undef HAVE_GETENV') - return retval -core.add_config (config_core) - -# -# The Simulator module -# -simu = build.Ns3Module('simulator', 'src/simulator') -ns3.add(simu) -simu.add_dep('core') -simu.add_external_dep('m') -simu.add_sources([ - 'high-precision.cc', - 'time.cc', - 'event-id.cc', - 'scheduler.cc', - 'scheduler-factory.cc', - 'scheduler-list.cc', - 'scheduler-heap.cc', - 'scheduler-map.cc', - 'event-impl.cc', - 'simulator.cc', - ]) -simu.add_headers([ - 'scheduler-heap.h', - 'scheduler-map.h', - 'scheduler-list.h' - ]) -simu.add_inst_headers([ - 'high-precision.h', - 'nstime.h', - 'event-id.h', - 'event-impl.h', - 'simulator.h', - 'scheduler.h', - 'scheduler-factory.h', - 'simulation-singleton.h', - ]) -high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n') -if high_precision_as_double == 'y': - simu.add_inst_header ('high-precision-double.h') - simu.add_source ('high-precision-double.cc') -else: - simu.add_inst_headers ([ - 'high-precision-128.h', - 'cairo-wideint-private.h' - ]) - simu.add_sources ([ - 'high-precision-128.cc', - 'cairo-wideint.c', - ]) - -def config_simulator (env, config): - retval = [] - high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n') - if high_precision_as_double == 'y': - retval.append ('#define USE_HIGH_PRECISION_DOUBLE 1') - else: - retval.append ('#undef USE_HIGH_PRECISION_DOUBLE') - if config.CheckCHeader ('stdint.h') == 1: - retval.append ('#define HAVE_STDINT_H 1') - elif config.CheckCHeader ('inttypes.h') == 1: - retval.append ('#define HAVE_INTTYPES_H 1') - elif config.CheckCHeader ('sys/inttypes.h') == 1: - retval.append ('#define HAVE_SYS_INT_TYPES_H 1') - return retval -simu.add_config (config_simulator) - -# -# The Common module -# -common = build.Ns3Module('common', 'src/common') -common.add_deps(['core', 'simulator']) -ns3.add(common) -common.add_sources([ - 'buffer.cc', - 'chunk.cc', - 'header.cc', - 'trailer.cc', - 'packet-printer.cc', - 'packet-metadata.cc', - 'packet.cc', - 'tags.cc', - 'pcap-writer.cc', - 'variable-tracer-test.cc', - 'trace-context.cc', - 'trace-resolver.cc', - 'callback-trace-source.cc', - 'empty-trace-resolver.cc', - 'composite-trace-resolver.cc', - 'trace-root.cc', - 'data-rate.cc', - ]) -common.add_headers ([ - ]) -common.add_inst_headers([ - 'buffer.h', - 'chunk.h', - 'header.h', - 'trailer.h', - 'tags.h', - 'packet.h', - 'packet-printer.h', - 'packet-metadata.h', - 'uv-trace-source.h', - 'sv-trace-source.h', - 'fv-trace-source.h', - 'pcap-writer.h', - 'callback-trace-source.h', - 'trace-context.h', - 'trace-resolver.h', - 'empty-trace-resolver.h', - 'composite-trace-resolver.h', - 'array-trace-resolver.h', - 'trace-root.h', - 'terminal-trace-resolver.h', - 'data-rate.h', - ]) - -# -# The Node module -# -node = build.Ns3Module ('node', 'src/node') -ns3.add (node) -node.add_deps (['core', 'common', 'simulator']) -node.add_sources ([ - 'node.cc', - 'ipv4-address.cc', - 'net-device.cc', - 'mac-address.cc', - 'llc-snap-header.cc', - 'ipv4-route.cc', - 'queue.cc', - 'drop-tail-queue.cc', - 'channel.cc', - 'node-list.cc', - 'socket.cc', - 'socket-factory.cc', - 'udp.cc', - 'ipv4.cc', - 'application.cc', - ]) -node.add_inst_headers ([ - 'node.h', - 'ipv4-address.h', - 'net-device.h', - 'mac-address.h', - 'ipv4-route.h', - 'queue.h', - 'drop-tail-queue.h', - 'llc-snap-header.h', - 'channel.h', - 'node-list.h', - 'socket.h', - 'socket-factory.h', - 'udp.h', - 'ipv4.h', - 'application.h', - ]) - -# -# The Applications module -# -applications = build.Ns3Module ('applications', 'src/applications') -ns3.add (applications) -applications.add_deps (['node']) -applications.add_sources ([ - 'onoff-application.cc', -]) -applications.add_inst_headers ([ - 'onoff-application.h', -]) - -# -# The Internet Node module -# -inode = build.Ns3Module ('internet-node', 'src/internet-node') -ns3.add (inode) -inode.add_deps (['node', 'routing']) -inode.add_sources ([ - 'internet-node.cc', - 'l3-demux.cc', - 'l3-protocol.cc', - 'ipv4-l4-demux.cc', - 'ipv4-l4-protocol.cc', - 'ipv4-header.cc', - 'udp-header.cc', - 'ipv4-checksum.cc', - 'ipv4-interface.cc', - 'ipv4-l3-protocol.cc', - 'ipv4-end-point.cc', - 'udp-l4-protocol.cc', - 'arp-header.cc', - 'arp-cache.cc', - 'arp-ipv4-interface.cc', - 'arp-l3-protocol.cc', - 'ipv4-loopback-interface.cc', - 'header-utils.cc', - 'udp-socket.cc', - 'ipv4-end-point-demux.cc', - 'arp-private.cc', - 'ipv4-impl.cc', - 'ipv4-private.cc', - 'ascii-trace.cc', - 'pcap-trace.cc', - 'udp-impl.cc', -]) -inode.add_headers ([ - 'ipv4-checksum.h', - 'arp-header.h', - 'arp-cache.h', - 'arp-l3-protocol.h', - 'ipv4-loopback-interface.h', - 'l3-demux.h', - 'header-utils.h', - 'arp-ipv4-interface.h', - 'udp-socket.h', - 'udp-l4-protocol.h', - 'arp-private.h', - 'ipv4-impl.h', - 'ipv4-private.h', - 'ipv4-l3-protocol.h', - 'l3-protocol.h', - 'ipv4-l4-protocol.h', - 'ipv4-l4-demux.h', - 'ipv4-end-point-demux.h', - 'ipv4-end-point.h', - 'ipv4-header.h', - 'ipv4-interface.h', - 'udp-header.h', - 'sgi-hashmap.h', - 'udp-impl.h', -]) -inode.add_inst_headers ([ - 'internet-node.h', - 'ascii-trace.h', - 'pcap-trace.h', - 'ipv4-header.h', - 'udp-header.h', -]) - -# -# The Point-to-point module -# -p2p = build.Ns3Module ('p2p', 'src/devices/p2p') -ns3.add (p2p) -p2p.add_deps (['node']) -p2p.add_sources ([ - 'p2p-net-device.cc', - 'p2p-channel.cc', - 'p2p-topology.cc', - ]) -p2p.add_inst_headers ([ - 'p2p-net-device.h', - 'p2p-channel.h', - 'p2p-topology.h', - ]) - -# -# The Routing module -# -routing = build.Ns3Module('routing', 'src/routing') -routing.add_deps(['core', 'node']) -ns3.add(routing) -routing.add_sources([ - 'routing-environment.cc', - 'static-router.cc', - 'static-route-manager.cc', - 'static-route-manager-impl.cc', - 'candidate-queue.cc', - ]) -routing.add_headers ([ - 'candidate-queue.h', - 'static-route-manager-impl.h', - ]) -routing.add_inst_headers([ - 'routing-environment.h', - 'static-router.h', - 'static-route-manager.h', - ]) - -# utils -run_tests = build.Ns3Module('run-tests', 'utils') -ns3.add(run_tests) -run_tests.set_executable() -run_tests.add_deps(['core', 'simulator', 'common', 'routing']) -run_tests.add_source('run-tests.cc') - -bench_object = build.Ns3Module('bench-object', 'utils') -ns3.add(bench_object) -bench_object.set_executable() -bench_object.add_deps(['core']) -bench_object.add_source('bench-object.cc') - -bench_packets = build.Ns3Module('bench-packets', 'utils') -ns3.add(bench_packets) -bench_packets.set_executable() -bench_packets.add_deps (['core', 'common']) -bench_packets.add_source('bench-packets.cc') - -bench_simu = build.Ns3Module('bench-simulator', 'utils') -ns3.add(bench_simu) -bench_simu.set_executable() -bench_simu.add_dep('simulator') -bench_simu.add_source('bench-simulator.cc') - -replay_simu = build.Ns3Module('replay-simulation', 'utils') -ns3.add(replay_simu) -replay_simu.set_executable() -replay_simu.add_dep('simulator') -replay_simu.add_source('replay-simulation.cc') - - -# samples -sample_debug = build.Ns3Module('sample-debug', 'samples') -sample_debug.set_executable() -ns3.add(sample_debug) -sample_debug.add_dep('core') -sample_debug.add_source('main-debug.cc') -sample_debug.add_source('main-debug-other.cc') - -sample_packet_printer = build.Ns3Module('sample-packet-printer', 'samples') -sample_packet_printer.set_executable() -ns3.add(sample_packet_printer) -sample_packet_printer.add_deps (['common', 'internet-node']) -sample_packet_printer.add_source('main-packet-printer.cc') - -sample_callback = build.Ns3Module('sample-callback', 'samples') -sample_callback.set_executable() -ns3.add(sample_callback) -sample_callback.add_dep('core') -sample_callback.add_source('main-callback.cc') - -sample_ptr = build.Ns3Module('sample-ptr', 'samples') -sample_ptr.set_executable() -ns3.add(sample_ptr) -sample_ptr.add_dep('core') -sample_ptr.add_source('main-ptr.cc') - -sample_trace = build.Ns3Module('sample-trace', 'samples') -#ns3.add(sample_trace) -sample_trace.add_dep('common') -sample_trace.set_executable() -sample_trace.add_source('main-trace.cc') - -sample_query_interface = build.Ns3Module('sample-query-interface', 'samples') -ns3.add(sample_query_interface) -sample_query_interface.add_dep('common') -sample_query_interface.set_executable() -sample_query_interface.add_source('main-query-interface.cc') - -sample_simu = build.Ns3Module('sample-simulator', 'samples') -ns3.add(sample_simu) -sample_simu.set_executable() -sample_simu.add_dep('simulator') -sample_simu.add_source('main-simulator.cc') - -sample_packet = build.Ns3Module('sample-packet', 'samples') -ns3.add(sample_packet) -sample_packet.set_executable() -sample_packet.add_dep('common') -sample_packet.add_source('main-packet.cc') - -sample_test = build.Ns3Module('sample-test', 'samples') -sample_test.set_executable() -ns3.add(sample_test) -sample_test.add_dep('core') -sample_test.add_source('main-test.cc') - -sample_simple = build.Ns3Module('sample-simple', 'samples') -sample_simple.set_executable() -ns3.add(sample_simple) -sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node', 'routing']) -sample_simple.add_source('main-simple.cc') - -sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples') -sample_sp2p.set_executable() -#n3.add(sample_sp2p) -sample_sp2p.add_deps(['core', 'simulator', 'node', 'internet-node', 'p2p']) -sample_sp2p.add_source('main-simple-p2p.cc') - -sample_default_value = build.Ns3Module('sample-default-value', 'samples') -sample_default_value.set_executable() -ns3.add(sample_default_value) -sample_default_value.add_deps(['core', 'simulator', 'node', 'p2p']) -sample_default_value.add_source('main-default-value.cc') - -sample_object = build.Ns3Module('sample-object', 'samples') -sample_object.set_executable() -ns3.add(sample_object) -sample_object.add_deps(['core']) -sample_object.add_source('main-object.cc') - -sample_component_manager = build.Ns3Module('sample-component-manager', 'samples') -sample_component_manager.set_executable() -ns3.add(sample_component_manager) -sample_component_manager.add_deps(['core']) -sample_component_manager.add_source('main-component-manager.cc') - -# examples -example_simple_p2p = build.Ns3Module('simple-p2p', 'examples') -example_simple_p2p.set_executable() -ns3.add(example_simple_p2p) -example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications', 'routing']) -example_simple_p2p.add_source('simple-p2p.cc') - -example_static_routing = build.Ns3Module('simple-static-routing', 'examples') -example_static_routing.set_executable() -ns3.add(example_static_routing) -example_static_routing.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications', 'routing']) -example_static_routing.add_source('simple-static-routing.cc') - -ns3.generate_dependencies() From cc6d4c0c06535a332590b8aa8e78d00b2404ea1d Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 28 Aug 2007 13:03:08 +0200 Subject: [PATCH 270/278] constify --- src/devices/csma/csma-net-device.h | 4 ++-- src/devices/point-to-point/point-to-point-net-device.h | 2 +- src/internet-node/ascii-trace.cc | 2 +- src/internet-node/ascii-trace.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 441ea04cd..62bbceab5 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -421,8 +421,8 @@ private: * @see class CallBackTraceSource * @see class TraceResolver */ - CallbackTraceSource m_rxTrace; - CallbackTraceSource m_dropTrace; + CallbackTraceSource m_rxTrace; + CallbackTraceSource m_dropTrace; }; diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index d8d8d3242..fa3d3b838 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -290,7 +290,7 @@ private: * @see class CallBackTraceSource * @see class TraceResolver */ - CallbackTraceSource m_rxTrace; + CallbackTraceSource m_rxTrace; /** * Default data rate. Used for all newly created p2p net devices */ diff --git a/src/internet-node/ascii-trace.cc b/src/internet-node/ascii-trace.cc index 0331bb5fd..961edd709 100644 --- a/src/internet-node/ascii-trace.cc +++ b/src/internet-node/ascii-trace.cc @@ -92,7 +92,7 @@ AsciiTrace::LogDevQueueDrop (TraceContext const &context, m_os << std::endl; } void -AsciiTrace::LogDevRx (TraceContext const &context, Packet &p) +AsciiTrace::LogDevRx (TraceContext const &context, const Packet &p) { m_os << "r " << Simulator::Now ().GetSeconds () << " "; context.Print (m_os); diff --git a/src/internet-node/ascii-trace.h b/src/internet-node/ascii-trace.h index e219afc41..084f82830 100644 --- a/src/internet-node/ascii-trace.h +++ b/src/internet-node/ascii-trace.h @@ -40,7 +40,7 @@ private: void LogDevQueueEnqueue (TraceContext const &context, const Packet &p); void LogDevQueueDequeue (TraceContext const &context, const Packet &p); void LogDevQueueDrop (TraceContext const &context, const Packet &p); - void LogDevRx (TraceContext const &context, Packet &p); + void LogDevRx (TraceContext const &context, const Packet &p); std::ofstream m_os; }; From 9f6f56f3ff63bd62790080845f5431b850361844 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 28 Aug 2007 14:09:52 +0200 Subject: [PATCH 271/278] use the NodeList::Iterator type --- src/routing/global-routing/global-route-manager-impl.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 9ede0a134..9fd73c680 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -337,8 +337,7 @@ GlobalRouteManagerImpl::SelectRouterNodes () { NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes ()"); - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++) { Ptr node = *i; NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes (): " @@ -366,8 +365,7 @@ GlobalRouteManagerImpl::BuildGlobalRoutingDatabase () // // Walk the list of nodes looking for the GlobalRouter Interface. // - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++) { Ptr node = *i; @@ -448,8 +446,7 @@ GlobalRouteManagerImpl::InitializeRoutes () // // Walk the list of nodes in the system. // - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++) { Ptr node = *i; // From 722fb6424514f752081a1e1466d836b9b2da16fe Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 28 Aug 2007 14:31:53 +0200 Subject: [PATCH 272/278] use more NodeList::Iterator types --- src/routing/global-routing/global-route-manager-impl.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 9fd73c680..42c63b9b9 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -1110,7 +1110,7 @@ GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) // the node at the root of the SPF tree. This is the node for which we are // building the routing table. // - std::vector >::iterator i = NodeList::Begin (); + NodeList::Iterator i = NodeList::Begin (); for (; i != NodeList::End (); i++) { Ptr node = *i; @@ -1183,7 +1183,7 @@ GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask) // the node at the root of the SPF tree. This is the node for which we are // building the routing table. // - std::vector >::iterator i = NodeList::Begin (); + NodeList::Iterator i = NodeList::Begin (); for (; i != NodeList::End (); i++) { Ptr node = *i; @@ -1274,7 +1274,7 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) // ID corresponding to the root vertex. This is the one we're going to write // the routing information to. // - std::vector >::iterator i = NodeList::Begin (); + NodeList::Iterator i = NodeList::Begin (); for (; i != NodeList::End (); i++) { Ptr node = *i; @@ -1395,7 +1395,7 @@ GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v) // ID corresponding to the root vertex. This is the one we're going to write // the routing information to. // - std::vector >::iterator i = NodeList::Begin (); + NodeList::Iterator i = NodeList::Begin (); for (; i != NodeList::End (); i++) { Ptr node = *i; From 74f9163b2451a2ac57345e858022db0ab3ec8a20 Mon Sep 17 00:00:00 2001 From: Raj Bhattacharjea Date: Tue, 28 Aug 2007 10:20:13 -0400 Subject: [PATCH 273/278] Remove references to really-simple-point-to-point, fix build --- examples/wscript | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/wscript b/examples/wscript index cb0af9530..e5e771555 100644 --- a/examples/wscript +++ b/examples/wscript @@ -10,10 +10,6 @@ def build(bld): ['point-to-point', 'internet-node']) obj.source = 'simple-point-to-point.cc' - obj = bld.create_ns3_program('really-simple-point-to-point', - ['point-to-point', 'internet-node']) - obj.source = 'really-simple-point-to-point.cc' - obj = bld.create_ns3_program('csma-one-subnet', ['csma', 'internet-node']) obj.source = 'csma-one-subnet.cc' From afbb95d98712c9b5b68a882f654119ef78bea2a2 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 28 Aug 2007 16:53:01 +0100 Subject: [PATCH 274/278] Build the ns3 library in the build/ root, not in build//src. --- src/wscript | 14 +++----------- wscript | 5 +++++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/wscript b/src/wscript index 1e20fb75c..859021e66 100644 --- a/src/wscript +++ b/src/wscript @@ -39,11 +39,9 @@ def configure(conf): conf.sub_config('simulator') blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant())) - conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir, 'src')] - for module in all_modules: - module_path = os.path.join(blddir, 'src', module) - if Params.g_options.enable_rpath: - conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (module_path,)) + conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir)] + if Params.g_options.enable_rpath: + conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),)) ## Used to link the 'run-tests' program with all of ns-3 code conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules] @@ -64,12 +62,6 @@ def build(bld): bld.add_subdirs(list(all_modules)) - ## Create a single ns3 library containing all modules - lib = bld.create_obj('cpp', 'shlib') - lib.name = 'ns3' - lib.target = 'ns3' - lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES']) - class Ns3Header(Object.genobj): """A set of NS-3 header files""" diff --git a/wscript b/wscript index 48b731729..6c1ca5339 100644 --- a/wscript +++ b/wscript @@ -165,6 +165,11 @@ def build(bld): bld.add_subdirs('src') bld.add_subdirs('samples utils examples') + ## Create a single ns3 library containing all modules + lib = bld.create_obj('cpp', 'shlib') + lib.name = 'ns3' + lib.target = 'ns3' + lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES']) def shutdown(): #import UnitTest From a88243575793143bcf4b13a00961f37273496410 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Tue, 28 Aug 2007 16:54:07 +0100 Subject: [PATCH 275/278] Add some tweaks to enable building under emacs. --- wscript | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wscript b/wscript index 6c1ca5339..c72b75e1e 100644 --- a/wscript +++ b/wscript @@ -145,6 +145,9 @@ def create_ns3_program(bld, name, dependencies=('simulator',)): def build(bld): + print "Entering directory `%s/build'" % Params.g_build.m_curdirnode.abspath() + Params.g_cwd_launch = Params.g_build.m_curdirnode.abspath() + bld.create_ns3_program = types.MethodType(create_ns3_program, bld) variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT'] From e20b40ee6196fa1ad955b93ca766b1eae451c11e Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 29 Aug 2007 09:35:53 +0200 Subject: [PATCH 276/278] backout 9856d1175cbb:642d6798feaa:27dd3e15308a --- samples/main-simple.cc | 3 +- src/applications/onoff-application.cc | 3 +- src/devices/csma/csma-net-device.cc | 60 +++++++++++-------- src/devices/csma/csma-net-device.h | 4 +- .../point-to-point-net-device.cc | 27 +++++---- .../point-to-point-net-device.h | 2 +- src/internet-node/arp-l3-protocol.cc | 5 +- src/internet-node/arp-l3-protocol.h | 2 +- src/internet-node/ipv4-end-point.cc | 4 +- src/internet-node/ipv4-end-point.h | 6 +- src/internet-node/ipv4-l3-protocol.cc | 29 +++++---- src/internet-node/ipv4-l3-protocol.h | 12 ++-- src/internet-node/ipv4-static-routing.cc | 2 +- src/internet-node/ipv4-static-routing.h | 2 +- src/internet-node/udp-l4-protocol.cc | 2 +- src/internet-node/udp-l4-protocol.h | 2 +- src/internet-node/udp-socket.cc | 13 ++-- src/internet-node/udp-socket.h | 10 ++-- src/node/drop-tail-queue.cc | 35 +++++++---- src/node/drop-tail-queue.h | 4 +- src/node/ipv4.h | 6 +- src/node/net-device.cc | 4 +- src/node/net-device.h | 8 +-- src/node/node.cc | 2 +- src/node/node.h | 4 +- src/node/packet-socket.cc | 10 ++-- src/node/packet-socket.h | 6 +- src/node/queue.cc | 42 ++++++------- src/node/queue.h | 14 ++--- src/node/socket.h | 4 +- 30 files changed, 179 insertions(+), 148 deletions(-) diff --git a/samples/main-simple.cc b/samples/main-simple.cc index 2039a55c3..7285f4946 100644 --- a/samples/main-simple.cc +++ b/samples/main-simple.cc @@ -14,8 +14,7 @@ static void GenerateTraffic (Ptr socket, uint32_t size) { std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl; - Packet p(size); - socket->Send (p); + socket->Send (Packet (size)); if (size > 0) { Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50); diff --git a/src/applications/onoff-application.cc b/src/applications/onoff-application.cc index 512c454f3..32bcd7564 100644 --- a/src/applications/onoff-application.cc +++ b/src/applications/onoff-application.cc @@ -206,8 +206,7 @@ void OnOffApplication::ScheduleStopEvent() void OnOffApplication::SendPacket() { NS_ASSERT (m_sendEvent.IsExpired ()); - Packet p(m_pktSize); - m_socket->Send(p); + m_socket->Send(Packet (m_pktSize)); m_totBytes += m_pktSize; m_lastStartTime = Simulator::Now(); m_residualBits = 0; diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index 610ec9b6c..531bf7314 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -274,12 +274,13 @@ CsmaNetDevice::DoNeedsArp (void) const bool CsmaNetDevice::SendTo ( - Packet& packet, + const Packet& packet, const Address& dest, uint16_t protocolNumber) { - NS_DEBUG ("CsmaNetDevice::SendTo (" << &packet << ")"); - NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << packet.GetUid () << ")"); + Packet p = packet; + NS_DEBUG ("CsmaNetDevice::SendTo (" << &p << ")"); + NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << p.GetUid () << ")"); NS_ASSERT (IsLinkUp ()); @@ -288,10 +289,10 @@ CsmaNetDevice::SendTo ( return false; Eui48Address destination = Eui48Address::ConvertFrom (dest); - AddHeader(packet, destination, protocolNumber); + AddHeader(p, destination, protocolNumber); // Place the packet to be sent on the send queue - if (m_queue->Enqueue(packet) == false ) + if (m_queue->Enqueue(p) == false ) { return false; } @@ -300,10 +301,11 @@ CsmaNetDevice::SendTo ( // transmission (see TransmitCompleteEvent) if (m_txMachineState == READY) { - if (m_queue->IsEmpty()) return true; // Nothing else to do // Store the next packet to be transmitted - m_currentPkt = m_queue->Dequeue(); - TransmitStart(); + if (m_queue->Dequeue (m_currentPkt)) + { + TransmitStart(); + } } return true; } @@ -387,8 +389,9 @@ CsmaNetDevice::TransmitAbort (void) m_currentPkt.GetUid () << ")"); // Try to transmit a new packet - if (m_queue->IsEmpty()) return; //No packet to transmit - m_currentPkt = m_queue->Dequeue (); + bool found; + found = m_queue->Dequeue (m_currentPkt); + NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); m_backoff.ResetBackoffTime(); m_txMachineState = READY; TransmitStart (); @@ -435,10 +438,18 @@ CsmaNetDevice::TransmitReadyEvent (void) NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); m_txMachineState = READY; - if (m_queue->IsEmpty()) return; // No more to transmit, remain ready // Get the next packet from the queue for transmitting - m_currentPkt = m_queue->Dequeue (); - TransmitStart (); + if (m_queue->IsEmpty()) + { + return; + } + else + { + bool found; + found = m_queue->Dequeue (m_currentPkt); + NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); + TransmitStart (); + } } TraceResolver * @@ -484,31 +495,32 @@ CsmaNetDevice::AddQueue (Ptr q) } void -CsmaNetDevice::Receive (Packet& packet) +CsmaNetDevice::Receive (const Packet& packet) { EthernetHeader header (false); EthernetTrailer trailer; Eui48Address broadcast; Eui48Address destination; + Packet p = packet; - NS_DEBUG ("CsmaNetDevice::Receive UID is (" << packet.GetUid() << ")"); + NS_DEBUG ("CsmaNetDevice::Receive UID is (" << p.GetUid() << ")"); // Only receive if send side of net device is enabled if (!IsReceiveEnabled()) { - m_dropTrace (packet); + m_dropTrace (p); return; } if (m_encapMode == RAW) { ForwardUp (packet, 0, GetBroadcast ()); - //m_dropTrace (packet); + m_dropTrace (p); return; } - packet.RemoveTrailer(trailer); - trailer.CheckFcs(packet); - packet.RemoveHeader(header); + p.RemoveTrailer(trailer); + trailer.CheckFcs(p); + p.RemoveHeader(header); broadcast = Eui48Address::ConvertFrom (GetBroadcast ()); destination = Eui48Address::ConvertFrom (GetAddress ()); @@ -516,11 +528,11 @@ CsmaNetDevice::Receive (Packet& packet) (header.GetDestination() != destination)) { // not for us. - m_dropTrace (packet); + m_dropTrace (p); return; } - m_rxTrace (packet); + m_rxTrace (p); // // protocol must be initialized to avoid a compiler warning in the RAW // case that breaks the optimized build. @@ -535,7 +547,7 @@ CsmaNetDevice::Receive (Packet& packet) break; case LLC: { LlcSnapHeader llc; - packet.RemoveHeader (llc); + p.RemoveHeader (llc); protocol = llc.GetType (); } break; case RAW: @@ -543,7 +555,7 @@ CsmaNetDevice::Receive (Packet& packet) break; } - ForwardUp (packet, protocol, header.GetSource ()); + ForwardUp (p, protocol, header.GetSource ()); return; } diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 0650b111a..62bbceab5 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -195,7 +195,7 @@ enum CsmaEncapsulationMode { * @see CsmaChannel * \param p a reference to the received packet */ - void Receive (Packet& p); + void Receive (const Packet& p); bool IsSendEnabled (void); bool IsReceiveEnabled (void); @@ -270,7 +270,7 @@ private: * \param protocolNumber -- this parameter is not used here * \return true if success, false on failure */ - virtual bool SendTo (Packet& p, const Address& dest, uint16_t protocolNumber); + virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber); /** * Start Sending a Packet Down the Wire. diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index 2cb026062..a071f9246 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -117,17 +117,18 @@ void PointToPointNetDevice::SetInterframeGap(const Time& t) m_tInterframeGap = t; } -bool PointToPointNetDevice::SendTo (Packet& packet, const Address& dest, +bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest, uint16_t protocolNumber) { - NS_DEBUG ("PointToPointNetDevice::SendTo (" << &packet << ", " << &dest << ")"); - NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << packet.GetUid () << ")"); + Packet p = packet; + NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); + NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); // GFR Comment. Why is this an assertion? Can't a link legitimately // "go down" during the simulation? Shouldn't we just wait for it // to come back up? NS_ASSERT (IsLinkUp ()); - AddHeader(packet, protocolNumber); + AddHeader(p, protocolNumber); // // This class simulates a point to point device. In the case of a serial @@ -138,16 +139,16 @@ bool PointToPointNetDevice::SendTo (Packet& packet, const Address& dest, // trnsmission; otherwise we send it now. if (m_txMachineState == READY) { - return TransmitStart (packet); + return TransmitStart (p); } else { - return m_queue->Enqueue(packet); + return m_queue->Enqueue(p); } } bool -PointToPointNetDevice::TransmitStart (Packet& p) +PointToPointNetDevice::TransmitStart (Packet &p) { NS_DEBUG ("PointToPointNetDevice::TransmitStart (" << &p << ")"); NS_DEBUG ( @@ -183,8 +184,8 @@ void PointToPointNetDevice::TransmitComplete (void) // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); m_txMachineState = READY; - if (m_queue->IsEmpty()) return; // Nothing to do at this point - Packet p = m_queue->Dequeue(); + Packet p; + if (!m_queue->Dequeue(p)) return; // Nothing to do at this point TransmitStart(p); } @@ -235,9 +236,11 @@ void PointToPointNetDevice::Receive (Packet& p) { NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); uint16_t protocol = 0; - m_rxTrace (p); - ProcessHeader(p, protocol); - ForwardUp (p, protocol, GetBroadcast ()); + Packet packet = p; + + m_rxTrace (packet); + ProcessHeader(packet, protocol); + ForwardUp (packet, protocol, GetBroadcast ()); } Ptr PointToPointNetDevice::GetQueue(void) const diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index a2c86e93a..fa3d3b838 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -211,7 +211,7 @@ private: * @param protocolNumber Protocol Number used to find protocol touse * @returns true if success, false on failure */ - virtual bool SendTo (Packet& p, const Address& dest, + virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber); /** * Start Sending a Packet Down the Wire. diff --git a/src/internet-node/arp-l3-protocol.cc b/src/internet-node/arp-l3-protocol.cc index 041c50e14..100f1df88 100644 --- a/src/internet-node/arp-l3-protocol.cc +++ b/src/internet-node/arp-l3-protocol.cc @@ -84,11 +84,12 @@ ArpL3Protocol::FindCache (Ptr device) } void -ArpL3Protocol::Receive(Ptr device, Packet& p, uint16_t protocol, const Address &from) +ArpL3Protocol::Receive(Ptr device, const Packet& p, uint16_t protocol, const Address &from) { ArpCache *cache = FindCache (device); ArpHeader arp; - p.RemoveHeader (arp); + Packet packet = p; + packet.RemoveHeader (arp); NS_DEBUG ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") << " node="<GetId ()<<", got request from " << diff --git a/src/internet-node/arp-l3-protocol.h b/src/internet-node/arp-l3-protocol.h index 82d8dd29e..a2ea8227e 100644 --- a/src/internet-node/arp-l3-protocol.h +++ b/src/internet-node/arp-l3-protocol.h @@ -53,7 +53,7 @@ public: /** * \brief Recieve a packet */ - void Receive(Ptr device, Packet& p, uint16_t protocol, const Address &from); + void Receive(Ptr device, const Packet& p, uint16_t protocol, const Address &from); /** * \brief Perform an ARP lookup * \param p diff --git a/src/internet-node/ipv4-end-point.cc b/src/internet-node/ipv4-end-point.cc index cdd78c303..69faf523e 100644 --- a/src/internet-node/ipv4-end-point.cc +++ b/src/internet-node/ipv4-end-point.cc @@ -65,7 +65,7 @@ Ipv4EndPoint::SetPeer (Ipv4Address address, uint16_t port) } void -Ipv4EndPoint::SetRxCallback (Callback callback) +Ipv4EndPoint::SetRxCallback (Callback callback) { m_rxCallback = callback; } @@ -77,7 +77,7 @@ Ipv4EndPoint::SetDestroyCallback (Callback callback) } void -Ipv4EndPoint::ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport) +Ipv4EndPoint::ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport) { if (!m_rxCallback.IsNull ()) { diff --git a/src/internet-node/ipv4-end-point.h b/src/internet-node/ipv4-end-point.h index 06192d500..f606aa63b 100644 --- a/src/internet-node/ipv4-end-point.h +++ b/src/internet-node/ipv4-end-point.h @@ -43,17 +43,17 @@ public: void SetPeer (Ipv4Address address, uint16_t port); - void SetRxCallback (Callback callback); + void SetRxCallback (Callback callback); void SetDestroyCallback (Callback callback); - void ForwardUp (Packet &p, Ipv4Address saddr, uint16_t sport); + void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport); private: Ipv4Address m_localAddr; uint16_t m_localPort; Ipv4Address m_peerAddr; uint16_t m_peerPort; - Callback m_rxCallback; + Callback m_rxCallback; Callback m_destroyCallback; }; diff --git a/src/internet-node/ipv4-l3-protocol.cc b/src/internet-node/ipv4-l3-protocol.cc index b44a0a013..be483dfa0 100644 --- a/src/internet-node/ipv4-l3-protocol.cc +++ b/src/internet-node/ipv4-l3-protocol.cc @@ -221,7 +221,7 @@ Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop, void Ipv4L3Protocol::Lookup (Ipv4Header const &ipHeader, - Packet& packet, + Packet packet, Ipv4RoutingProtocol::RouteReplyCallback routeReply) { for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin (); @@ -310,7 +310,7 @@ Ipv4L3Protocol::FindInterfaceForDevice (Ptr device) } void -Ipv4L3Protocol::Receive( Ptr device, Packet& p, uint16_t protocol, const Address &from) +Ipv4L3Protocol::Receive( Ptr device, const Packet& p, uint16_t protocol, const Address &from) { uint32_t index = 0; for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) @@ -322,25 +322,26 @@ Ipv4L3Protocol::Receive( Ptr device, Packet& p, uint16_t protocol, co } index++; } + Packet packet = p; Ipv4Header ipHeader; - p.RemoveHeader (ipHeader); + packet.RemoveHeader (ipHeader); if (!ipHeader.IsChecksumOk ()) { return; } - if (Forwarding (p, ipHeader, device)) + if (Forwarding (packet, ipHeader, device)) { return; } - ForwardUp (p, ipHeader); + ForwardUp (packet, ipHeader); } void -Ipv4L3Protocol::Send (Packet& packet, +Ipv4L3Protocol::Send (Packet const &packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol) @@ -364,10 +365,12 @@ Ipv4L3Protocol::Send (Packet& packet, ifaceIter != m_interfaces.end (); ifaceIter++, ifaceIndex++) { Ipv4Interface *outInterface = *ifaceIter; - NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ()); - packet.AddHeader (ipHeader); - m_txTrace (packet, ifaceIndex); - outInterface->Send (packet, destination); + Packet packetCopy = packet; + + NS_ASSERT (packetCopy.GetSize () <= outInterface->GetMtu ()); + packetCopy.AddHeader (ipHeader); + m_txTrace (packetCopy, ifaceIndex); + outInterface->Send (packetCopy, destination); } } else @@ -388,7 +391,7 @@ Ipv4L3Protocol::Send (Packet& packet, void Ipv4L3Protocol::SendRealOut (bool found, Ipv4Route const &route, - Packet& packet, + Packet packet, Ipv4Header const &ipHeader) { if (!found) @@ -413,7 +416,7 @@ Ipv4L3Protocol::SendRealOut (bool found, bool -Ipv4L3Protocol::Forwarding (Packet& packet, Ipv4Header &ipHeader, Ptr device) +Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr device) { for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++) @@ -468,7 +471,7 @@ Ipv4L3Protocol::Forwarding (Packet& packet, Ipv4Header &ipHeader, Ptr void -Ipv4L3Protocol::ForwardUp (Packet& p, Ipv4Header const&ip) +Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip) { Ptr demux = m_node->QueryInterface (Ipv4L4Demux::iid); Ptr protocol = demux->GetProtocol (ip.GetProtocol ()); diff --git a/src/internet-node/ipv4-l3-protocol.h b/src/internet-node/ipv4-l3-protocol.h index 8254f27e6..2cce3efa3 100644 --- a/src/internet-node/ipv4-l3-protocol.h +++ b/src/internet-node/ipv4-l3-protocol.h @@ -118,7 +118,7 @@ public: * - implement a per-NetDevice ARP cache * - send back arp replies on the right device */ - void Receive( Ptr device, Packet& p, uint16_t protocol, const Address &from); + void Receive( Ptr device, const Packet& p, uint16_t protocol, const Address &from); /** * \param packet packet to send @@ -129,7 +129,7 @@ public: * Higher-level layers call this method to send a packet * down the stack to the MAC and PHY layers. */ - void Send (Packet& packet, Ipv4Address source, + void Send (Packet const &packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol); @@ -151,7 +151,7 @@ public: uint32_t interface); void Lookup (Ipv4Header const &ipHeader, - Packet& packet, + Packet packet, Ipv4RoutingProtocol::RouteReplyCallback routeReply); uint32_t GetNRoutes (void); @@ -183,10 +183,10 @@ private: void SendRealOut (bool found, Ipv4Route const &route, - Packet& packet, + Packet packet, Ipv4Header const &ipHeader); - bool Forwarding (Packet& packet, Ipv4Header &ipHeader, Ptr device); - void ForwardUp (Packet& p, Ipv4Header const&ip); + bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr device); + void ForwardUp (Packet p, Ipv4Header const&ip); uint32_t AddIpv4Interface (Ipv4Interface *interface); void SetupLoopback (void); TraceResolver *InterfacesCreateTraceResolver (TraceContext const &context) const; diff --git a/src/internet-node/ipv4-static-routing.cc b/src/internet-node/ipv4-static-routing.cc index 37e8a74df..b70c1c1af 100644 --- a/src/internet-node/ipv4-static-routing.cc +++ b/src/internet-node/ipv4-static-routing.cc @@ -210,7 +210,7 @@ Ipv4StaticRouting::RemoveRoute (uint32_t index) bool Ipv4StaticRouting::RequestRoute (Ipv4Header const &ipHeader, - Packet& packet, + Packet packet, RouteReplyCallback routeReply) { Ipv4Route *route = LookupStatic (ipHeader.GetDestination ()); diff --git a/src/internet-node/ipv4-static-routing.h b/src/internet-node/ipv4-static-routing.h index 439af8cf7..8462f55a7 100644 --- a/src/internet-node/ipv4-static-routing.h +++ b/src/internet-node/ipv4-static-routing.h @@ -52,7 +52,7 @@ public: Ipv4StaticRouting () : m_defaultRoute (0) {} virtual bool RequestRoute (Ipv4Header const &ipHeader, - Packet& packet, + Packet packet, RouteReplyCallback routeReply); diff --git a/src/internet-node/udp-l4-protocol.cc b/src/internet-node/udp-l4-protocol.cc index 9dacbf961..f0ef8569b 100644 --- a/src/internet-node/udp-l4-protocol.cc +++ b/src/internet-node/udp-l4-protocol.cc @@ -122,7 +122,7 @@ UdpL4Protocol::Receive(Packet& packet, } void -UdpL4Protocol::Send (Packet& packet, +UdpL4Protocol::Send (Packet packet, Ipv4Address saddr, Ipv4Address daddr, uint16_t sport, uint16_t dport) { diff --git a/src/internet-node/udp-l4-protocol.h b/src/internet-node/udp-l4-protocol.h index 70e2b0ccc..4d7a082d4 100644 --- a/src/internet-node/udp-l4-protocol.h +++ b/src/internet-node/udp-l4-protocol.h @@ -74,7 +74,7 @@ public: * \param sport The source port number * \param dport The destination port number */ - void Send (Packet& packet, + void Send (Packet packet, Ipv4Address saddr, Ipv4Address daddr, uint16_t sport, uint16_t dport); /** diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 45b8b82b6..a2bde3224 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -155,7 +155,7 @@ UdpSocket::Connect(const Address & address) return 0; } int -UdpSocket::Send (Packet &p) +UdpSocket::Send (const Packet &p) { if (!m_connected) { @@ -165,7 +165,7 @@ UdpSocket::Send (Packet &p) return DoSendTo (p, m_defaultAddress, m_defaultPort); } int -UdpSocket::DoSendTo (Packet &p, const Address &address) +UdpSocket::DoSendTo (const Packet &p, const Address &address) { InetSocketAddress transport = InetSocketAddress::ConvertFrom (address); Ipv4Address ipv4 = transport.GetIpv4 (); @@ -173,7 +173,7 @@ UdpSocket::DoSendTo (Packet &p, const Address &address) return DoSendTo (p, ipv4, port); } int -UdpSocket::DoSendTo (Packet& p, Ipv4Address ipv4, uint16_t port) +UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port) { if (m_endPoint == 0) { @@ -195,7 +195,7 @@ UdpSocket::DoSendTo (Packet& p, Ipv4Address ipv4, uint16_t port) return 0; } int -UdpSocket::SendTo(const Address &address, Packet &p) +UdpSocket::SendTo(const Address &address, const Packet &p) { if (m_connected) { @@ -209,7 +209,7 @@ UdpSocket::SendTo(const Address &address, Packet &p) } void -UdpSocket::ForwardUp (Packet &packet, Ipv4Address ipv4, uint16_t port) +UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port) { if (m_shutdownRecv) { @@ -217,7 +217,8 @@ UdpSocket::ForwardUp (Packet &packet, Ipv4Address ipv4, uint16_t port) } Address address = InetSocketAddress (ipv4, port); - NotifyDataReceived (packet, address); + Packet p = packet; + NotifyDataReceived (p, address); } }//namespace ns3 diff --git a/src/internet-node/udp-socket.h b/src/internet-node/udp-socket.h index 9ceec713f..b3674f7ef 100644 --- a/src/internet-node/udp-socket.h +++ b/src/internet-node/udp-socket.h @@ -51,8 +51,8 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (Packet &p); - virtual int SendTo(const Address &address,Packet &p); + virtual int Send (const Packet &p); + virtual int SendTo(const Address &address,const Packet &p); private: @@ -60,10 +60,10 @@ private: friend class Udp; // invoked by Udp class int FinishBind (void); - void ForwardUp (Packet &p, Ipv4Address ipv4, uint16_t port); + void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port); void Destroy (void); - int DoSendTo (Packet &p, const Address &daddr); - int DoSendTo (Packet &p, Ipv4Address daddr, uint16_t dport); + int DoSendTo (const Packet &p, const Address &daddr); + int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport); Ipv4EndPoint *m_endPoint; Ptr m_node; diff --git a/src/node/drop-tail-queue.cc b/src/node/drop-tail-queue.cc index 5b802acec..74c8fde17 100644 --- a/src/node/drop-tail-queue.cc +++ b/src/node/drop-tail-queue.cc @@ -73,26 +73,39 @@ DropTailQueue::DoEnqueue (const Packet& p) return true; } -Packet -DropTailQueue::DoDequeue () +bool +DropTailQueue::DoDequeue (Packet& p) { - NS_DEBUG("DropTailQueue::DoDequeue ( )"); - NS_ASSERT(!IsEmpty()); - Packet p = m_packets.front (); + NS_DEBUG("DropTailQueue::DoDequeue (" << &p << ")"); + + if (m_packets.empty()) + { + NS_DEBUG("DropTailQueue::DoDequeue (): Queue empty"); + return false; + } + + p = m_packets.front (); m_packets.pop (); NS_DEBUG("DropTailQueue::DoDequeue (): Popped " << &p << " <= true"); - return p; + return true; } -Packet -DropTailQueue::DoPeek () +bool +DropTailQueue::DoPeek (Packet& p) { - NS_DEBUG("DropTailQueue::DoPeek ( )"); - NS_ASSERT(!IsEmpty()); + NS_DEBUG("DropTailQueue::DoPeek (" << &p << ")"); - return m_packets.front (); + if (m_packets.empty()) + { + NS_DEBUG("DropTailQueue::DoPeek (): Queue empty"); + return false; + } + + p = m_packets.front (); + + return true; } }; // namespace ns3 diff --git a/src/node/drop-tail-queue.h b/src/node/drop-tail-queue.h index 6febe0eab..2e4c76461 100644 --- a/src/node/drop-tail-queue.h +++ b/src/node/drop-tail-queue.h @@ -58,8 +58,8 @@ public: private: virtual bool DoEnqueue (const Packet& p); - virtual Packet DoDequeue (); - virtual Packet DoPeek (); + virtual bool DoDequeue (Packet &p); + virtual bool DoPeek (Packet &p); private: std::queue m_packets; diff --git a/src/node/ipv4.h b/src/node/ipv4.h index b4d22c520..76d88faea 100644 --- a/src/node/ipv4.h +++ b/src/node/ipv4.h @@ -46,7 +46,7 @@ class Ipv4Header; // FIXME: ipv4-header.h needs to move from module class Ipv4RoutingProtocol : public Object { public: - // void (*RouteReply) (bool found, Ipv4Route route, Packet& packet, Ipv4Header const &ipHeader); + // void (*RouteReply) (bool found, Ipv4Route route, Packet packet, Ipv4Header const &ipHeader); /** @@ -65,7 +65,7 @@ public: * inserted and consequently the protocol type has to change). * */ - typedef Callback RouteReplyCallback; + typedef Callback RouteReplyCallback; /** * \brief Asynchronously requests a route for a given packet and IP header @@ -100,7 +100,7 @@ public: * insert any extra header. */ virtual bool RequestRoute (const Ipv4Header &ipHeader, - Packet& packet, + Packet packet, RouteReplyCallback routeReply) = 0; }; diff --git a/src/node/net-device.cc b/src/node/net-device.cc index 11566a028..e3b9537aa 100644 --- a/src/node/net-device.cc +++ b/src/node/net-device.cc @@ -171,7 +171,7 @@ NetDevice::DisablePointToPoint (void) // Receive packet from above bool -NetDevice::Send(Packet& p, const Address& dest, uint16_t protocolNumber) +NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber) { if (m_isUp) { @@ -197,7 +197,7 @@ NetDevice::GetChannel (void) const // Receive packets from below bool -NetDevice::ForwardUp(Packet& p, uint16_t param, const Address &from) +NetDevice::ForwardUp(const Packet& p, uint16_t param, const Address &from) { bool retval = false; diff --git a/src/node/net-device.h b/src/node/net-device.h index 061df3441..cc93e6420 100644 --- a/src/node/net-device.h +++ b/src/node/net-device.h @@ -158,7 +158,7 @@ public: * * \return whether the Send operation succeeded */ - bool Send(Packet& p, const Address& dest, uint16_t protocolNumber); + bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber); /** * \returns the node base class which contains this network * interface. @@ -187,7 +187,7 @@ public: * \returns true if the callback could handle the packet successfully, false * otherwise. */ - typedef Callback,Packet &,uint16_t,const Address &> ReceiveCallback; + typedef Callback,const Packet &,uint16_t,const Address &> ReceiveCallback; /** * \param cb callback to invoke whenever a packet has been received and must @@ -251,7 +251,7 @@ public: * forwards it to the higher layers by calling this method * which is responsible for passing it up to the Rx callback. */ - bool ForwardUp (Packet& p, uint16_t param, const Address &address); + bool ForwardUp (const Packet& p, uint16_t param, const Address &address); /** @@ -274,7 +274,7 @@ public: * method. When the link is Up, this method is invoked to ask * subclasses to forward packets. Subclasses MUST override this method. */ - virtual bool SendTo (Packet& p, const Address &dest, uint16_t protocolNumber) = 0; + virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0; /** * \returns true if this NetDevice needs the higher-layers * to perform ARP over it, false otherwise. diff --git a/src/node/node.cc b/src/node/node.cc index 5fdd50bb8..ee83e8588 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -213,7 +213,7 @@ Node::UnregisterProtocolHandler (ProtocolHandler handler) } bool -Node::ReceiveFromDevice (Ptr device, Packet &packet, +Node::ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol, const Address &from) { bool found = false; diff --git a/src/node/node.h b/src/node/node.h index 1538350be..f4d898f53 100644 --- a/src/node/node.h +++ b/src/node/node.h @@ -158,7 +158,7 @@ public: /** * A protocol handler */ - typedef Callback, Packet &,uint16_t,const Address &> ProtocolHandler; + typedef Callback, const Packet &,uint16_t,const Address &> ProtocolHandler; /** * \param handler the handler to register * \param protocolType the type of protocol this handler is @@ -210,7 +210,7 @@ private: */ virtual void NotifyDeviceAdded (Ptr device); - bool ReceiveFromDevice (Ptr device, Packet &packet, + bool ReceiveFromDevice (Ptr device, const Packet &packet, uint16_t protocol, const Address &from); void Construct (void); TraceResolver *CreateDevicesTraceResolver (const TraceContext &context); diff --git a/src/node/packet-socket.cc b/src/node/packet-socket.cc index 7e0095d79..f642eee9e 100644 --- a/src/node/packet-socket.cc +++ b/src/node/packet-socket.cc @@ -186,7 +186,7 @@ PacketSocket::Connect(const Address &ad) } int -PacketSocket::Send (Packet &p) +PacketSocket::Send (const Packet &p) { if (m_state == STATE_OPEN || m_state == STATE_BOUND) @@ -198,7 +198,7 @@ PacketSocket::Send (Packet &p) } int -PacketSocket::SendTo(const Address &address, Packet &p) +PacketSocket::SendTo(const Address &address, const Packet &p) { PacketSocketAddress ad; if (m_state == STATE_CLOSED) @@ -262,7 +262,7 @@ PacketSocket::SendTo(const Address &address, Packet &p) } void -PacketSocket::ForwardUp (Ptr device, Packet &packet, +PacketSocket::ForwardUp (Ptr device, const Packet &packet, uint16_t protocol, const Address &from) { if (m_shutdownRecv) @@ -270,7 +270,7 @@ PacketSocket::ForwardUp (Ptr device, Packet &packet, return; } - //Packet p = packet; ? + Packet p = packet; PacketSocketAddress address; address.SetPhysicalAddress (from); @@ -279,7 +279,7 @@ PacketSocket::ForwardUp (Ptr device, Packet &packet, NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid() << " PacketSocket " << this); - NotifyDataReceived (packet, address); + NotifyDataReceived (p, address); } }//namespace ns3 diff --git a/src/node/packet-socket.h b/src/node/packet-socket.h index be4ade908..8dc1b9e62 100644 --- a/src/node/packet-socket.h +++ b/src/node/packet-socket.h @@ -82,15 +82,15 @@ public: virtual int ShutdownSend (void); virtual int ShutdownRecv (void); virtual int Connect(const Address &address); - virtual int Send (Packet &p); - virtual int SendTo(const Address &address,Packet &p); + virtual int Send (const Packet &p); + virtual int SendTo(const Address &address,const Packet &p); private: private: void Init (void); - void ForwardUp (Ptr device, Packet &packet, + void ForwardUp (Ptr device, const Packet &packet, uint16_t protocol, const Address &from); int DoBind (const PacketSocketAddress &address); virtual void DoDispose (void); diff --git a/src/node/queue.cc b/src/node/queue.cc index ad79109c0..72eafed69 100644 --- a/src/node/queue.cc +++ b/src/node/queue.cc @@ -49,7 +49,7 @@ QueueTraceType::IsEnqueue (void) const { return m_type == ENQUEUE; } -bool +bool QueueTraceType::IsDequeue (void) const { return m_type == DEQUEUE; @@ -122,25 +122,28 @@ Queue::Enqueue (const Packet& p) return retval; } -Packet -Queue::Dequeue () +bool +Queue::Dequeue (Packet &p) { - NS_ASSERT(!IsEmpty()); - NS_DEBUG("Queue::Dequeue ( )"); + NS_DEBUG("Queue::Dequeue (" << &p << ")"); - Packet p = DoDequeue (); + bool retval = DoDequeue (p); - m_nBytes -= p.GetSize (); - m_nPackets--; - - NS_ASSERT (m_nBytes >= 0); - NS_ASSERT (m_nPackets >= 0); - - NS_DEBUG("Queue::Dequeue (): m_traceDequeue (p)"); + if (retval) + { + m_nBytes -= p.GetSize (); + m_nPackets--; - m_traceDequeue (p); + NS_ASSERT (m_nBytes >= 0); + NS_ASSERT (m_nPackets >= 0); - return p; + NS_DEBUG("Queue::Dequeue (): m_traceDequeue (p)"); + + const Packet packet = p; + m_traceDequeue (packet); + } + + return retval; } void @@ -151,13 +154,12 @@ Queue::DequeueAll (void) NS_ASSERT (!"Don't know what to do with dequeued packets!"); } -Packet -Queue::Peek () +bool +Queue::Peek (Packet &p) { - NS_ASSERT(!IsEmpty()); - NS_DEBUG("Queue::Peek ( )"); + NS_DEBUG("Queue::Peek (" << &p << ")"); - return DoPeek (); + return DoPeek (p); } diff --git a/src/node/queue.h b/src/node/queue.h index 915642f09..d135fff68 100644 --- a/src/node/queue.h +++ b/src/node/queue.h @@ -83,16 +83,14 @@ public: bool Enqueue (const Packet& p); /** * Remove a packet from the front of the Queue - * Must not be called on an empty queue. - * \return The packet removed from the queue + * \return True if the operation was successful; false otherwise */ - Packet Dequeue (); + bool Dequeue (Packet &p); /** * Get a copy of the item at the front of the queue without removing it - * Must NOT be called on an empty queue - * \return The packet at the head of the queue. + * \return True if the operation was successful; false otherwise */ - Packet Peek (); + bool Peek (Packet &p); /** * XXX Doesn't do anything right now, think its supposed to flush the queue @@ -165,8 +163,8 @@ public: private: virtual bool DoEnqueue (const Packet& p) = 0; - virtual Packet DoDequeue () = 0; - virtual Packet DoPeek () = 0; + virtual bool DoDequeue (Packet &p) = 0; + virtual bool DoPeek (Packet &p) = 0; protected: // called by subclasses to notify parent of packet drops. diff --git a/src/node/socket.h b/src/node/socket.h index 1a28bd71d..c717ec0a5 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -173,7 +173,7 @@ public: * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int Send (Packet &p) = 0; + virtual int Send (const Packet &p) = 0; /** * \brief Send data to a specified peer. @@ -182,7 +182,7 @@ public: * \returns -1 in case of error or the number of bytes copied in the * internal buffer and accepted for transmission. */ - virtual int SendTo(const Address &address,Packet &p) = 0; + virtual int SendTo(const Address &address,const Packet &p) = 0; protected: void NotifyCloseCompleted (void); From 0261a0b79557e809dd72b6b9bc367df0c17843c5 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Wed, 29 Aug 2007 12:31:17 +0100 Subject: [PATCH 277/278] New WAF, avoids the bright yellow color (hard to read on light background terminals) problem. --- waf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/waf b/waf index d4f80d72a..94a2a37a2 100755 --- a/waf +++ b/waf @@ -11,7 +11,7 @@ if 'PSYCOWAF' in os.environ: pass VERSION="1.1.1" -REVISION="1272724989" +REVISION="1420549696" INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local' cwd = os.getcwd() @@ -334,5 +334,5 @@ except KeyboardInterrupt: Params.fatal('build interrupted') #prof.runcall(Scripting.Main) #prof.close() # ===>BEGIN WOOF<=== -#6<\%_0gSqh;d"&i4hUq"'EA+4s8;Tjs8W-!s8W-!s8W+l!!!?/+s8Ri#QQOmTF;*7jW*^\\1'ZCz!!!!q-n#&q!!"DJF2"&p-aW8SQY$K"!EWV\h!&gY=W_6RV_sr\722cZ@k5kdqqg'$4*["='$#2".3/jH9s\UR>BX?ohY0*=H[;!kmGlsVII%EnT7)!(/U>#5gO6P<#sP`m!Um]ST#;0S]:$Hk8J3V550%G+n!@)?&(e/H?7rG4)HopHecsJV&*NLld/Hf'i_/tW]OXF=:('"e7,sVH,!!!'c"B6'9h=&$=^$;/b<7!LN[75n*Zqu06hetOCfNT/9Dgh)`hX=R2Efmj*fjoK.pmJmh!ZlhGA_fKbKkV"UYb%$WeaM<&g4,qXHU?d8^JOF*%JYrh=IR.4^RKF+eA55]5<0hXk9hhme9(rh6nrgMn6Nkn!3?hPcO46ZarrBDYD60?/F#=^#"+FY%MhCpYKIuY'4`L\G(EBC%lKlo_[gcA*S!'f@;scf6;#ph"9uKijR_*D0sg5$f:Wk<&O(2&%?WII<;NeC$o1g)ql6Ep?UE"Nr&N6G4/jfDnaO=GIt<\efO_Thd*tkIJ(4`BhH+Q#Q^mriANd<)9A\4n"42=kb]#^DkT=Q+gDA3H_e&T"!!)5_8bRSiDY<_tcb@q:I-rM#g:)F^8p<2]2gLe?Ch*\7]tNjs020r>=5RnDp%7PBoC![Th72o`a:#<,9:j0fl5oft]63B-8kZn]AUbg83'YpRHGrfg4g+/H\r+?>S>Dp@l24g/m%jC0ZVQ)bTehQ#4*Z0as)4J9k`J:5(m&jtEVkI2Cd(dA8ktHLJ>Oq"f]f[(ArhIYKc]5c[J4lPj>D'k5f4*NGO&PAu:]C+\NPC%]toII(/+.rjfDHbJ5>YJ"KR9b7j=!Wi@V5S+A-^`Z.ASs`%sVkPt8ct"&3+92BEVEkcF#RCJ7dh#E,Ua`\jeFbS3IT5tX)L@B"cl+_GW#>Xm!!!'e,X>9.":V:+!hL&PR0f"X"2lLC,L^ae2!71_m!MBDm!$Oo>7Ynt_-@c@Y'Z*!^lAs)Wb%=WB+[&Uq:JF)fo`,M!)?9a<-DDVJ5ThD;C,#pWnI_3hrA9lerC5s2rjl;?[PrL=C^1!mZZe!*tIsVMZ(`(aR.`!.f;1JL3$GX5;7lqq$d-4`p%rY43r4;oek6HHf2F7+PXA[5XV*Bupng8)TXXs/-lT#^Lr&'K\Qer#dXd]Cp9.mP/tTC5VP&D[`VCFf?)?KI(kK#j'?aArSC"kcMIcb*fhrE/IY4>tHlu3H)Ah!H-i1UBF'l\7*5d+pSd1QOXU,!m6;[+S$'LH\EG3'I_C+N!$1+S/Xm_TYp[$6OMM\6Lb6b*.a-p;-K&GIBY.2IRIl@iLl5p?iV9MI)>9,,>qBHsO9J<7OV9E@'%8]A1sm`T">r#7"I2AP!)c`-72/oZir6"9Mht@'bEYs>A0_+@O`e!+[VTQ,*mbQ@MkIV,ab5MJ;Rm1To+GYM@*`88=G8?VHB"STV@=D@OPt6W$J$fBOrV0-n:U?TqWGT)3R<'+G(dC#_jNq)Ib1,>+qU`+UFmB$"/oE,)@E]?m$q1UnJ'U.Z0+@Tr)7cTa@*BMCN#0R2R2uW%(AjLkp^6BkX<1+KC9kU5#VBVIGXKMJ/ENBh9S)#UtS0W!JK8Ob0EsOt%T2AdOWpL*EIOR"upf-A#uq,&+'S80FTSLkLp,)CV;9#(W'V-DcSHBLnA\MPLQHP"K1eAL_-r8j]2$VMZQGLhMrCWD*jo,`%84-5_l%R\YP4L4UiuKRtP68gn/"@=a;&Q6mHJMBWplV&>(7?mI-KAf;jaQ@pBZ,(`[L+fYkPMO&jYR"d$q#a,dfC8-<[TI;3\BHdMWBI6'7!2Z?]W$7BI?t"kI.&qkJ,"R<:+K-2M7Tro_AeJK$JqHOW+IZDhOb-D](mZ;<-<-ZfU4S,bUo&ho7ZjDj8qJI#TSaj!8.L7A5OGNrUM3&urTn]Eg-)cPD@SiIqMNSm/Slm3`R%],3Jk.=W&djAM@L?:RLm4k_,c%/s-n,4lV'ZOA8=EFKWgWKh9Z06^$?/C!";NW7[_\dIUgcrPJ=%OS,a+k"J;Aek8n+6X.OgL7@UUO:!\.rR$;uD+TI(j`A;DM1.12K;Jf./f6>2T-$4;Alj9`\$MOGf"Ad#,I."R2?ROKF/Q)\:")AWV`Q=L>+&V64AJfnSL5&_'@ps7.?K-IZV'a579&5jd\,u[c/!":Q"j'b"&p;H+ea78+=fPg%KR1ntUN6j/aV1a;%"NZ\#;YI8)[;g:(0\g+"[p4);+3hYV0!=_9X?R[7$95[9$sJT&HP3&O`LjtPbL`($qNep!s(e@ZS9oT&4EcH'b`9;!N7IPM5ckEL+%o_,%:ldL/=ONLl-_F&;C?3O['7>&u[4OVML)DU,&Si.L%#gU`lV.AccM9-jl=SR"f1($7$euLe:9K,%a`MMF:np8r8gB$C4SgU0o/fBVd,O&o*L!gnk--N=JCZZ!$m5S-jV+i$5eGP#_7SiU*,;(Weq-s,p=akM5?VL?m1pb&gaD$Th5lr=GR7j>"V8A&qq_>KHQoui<`0P6df7/R(:fIE;s9Rh\PANrmt=orCFh8'mg]"&D+6a)#:/O,i7]."+Kk[%NKSXO=J%mE@,6@Y(6bULL%6.d^;cXHK:qZJ:8KP!pG`23s2hRo84Zi5UdTim3('<_H)XgLVl\#513k/Q#3cl`d7h&Rj3TeY;1*>tbQaFbj#WruKf!VX19?TD=Br:$=O%N29X.*&1$`lL11)H)i?%XV@p[U;VQQ[[c4ZB@DaB4ipr+-jD.-ZO/16>8I.*S&6"o2s/jEoeFIh,FP[e8'qD$Z%eZgi@9Q,Q*'8IP&q-0H/-;4SUf7Ypi`gsZGHd@2-AcEZP_]+.kAe^[m&`i27$HZH@%)@*)OU!_`["OMM86CRjNHCdhIEdRTM(-S/9BL\Be31535IL<.-G$Tt3r>h];r+"U>WB7=tpLQo,6Q-SpD]>m4+f[Y-,`BJ?5dVXkj`A@2`I3^Ai[Dr&_^l5]IS)i(Tdtjts6;E,1G&HRr+4X3eFpm?pS!-J*Q7n.f'J`K]nEIh\_)%^3>8&k\;D1nO@h&3rbD-Xlcb5N\meD5/I>uqMHC2VRcV>oD\p0VCPTTUJ))f,tRL^i2q79mgDt2"2f10:,Y5"=-"Aknk*4;R=O%JHT7l8VEJ]X*k-4W_Q06+0X6E7d-f'/X(2gJlnLN/j:gCPo'R@5/@a==0`c>h&b,Z%ZaC(k*\iC<1-#*@G;1\T-!<"nfL./i2oOWt[p$lGa8q,\W]ZI!bloqU&Q(g]0d)=!X]4RP'nn+[AQER9o`,d2f,DJgI9hi(r>I_5BM@H]`E9ADm@F;O*9nh9!E_cea<66EK;j0YLDt.?#"Q5A.6$4qL0P)K:Hn"0E\V*hgdBoC@&$=^#(M$u]@U5A;L0nQ-'U`qjYlCPa-gborMSi;+MA4a./,B&%-;uZE'_%ib&79A#8oo55h69cr[.o!\/n"O&?W>*-YeOrH05(;R"qalZ2.[*EZK_ab&$WVWqI5AD^2j`\6CP_^Nc/sU$'-X!cbuoB>sn04b7PF0<@Bf+Vp2Pl6*d&!H&N1@Ppeu(:lRCbWI^ubgb^(Ob7YOENEE0#>ruLrrGL[b73^[>WO=8t88-15.=b>N-R^teA:n6%f1XolP4Q:8liPMXq9@"d\QosaAJ6b]*7PaDbOM8,[^:l>:7u:M\7t>k#96+r]aI@j4W+`^I3iOX9bk"S,4hQ,X_*No0jeZo*?=]'1XQddQE!q'\H;P%JHI"SCr[>d?W`^RMWqDeb)I9%pkXgAd)mc@hZda*MKqe?QZ]1tGN9HMuYXV.j%)!YY.85D9d>=H]%"B^=U!s)ZDO=0=WP^&EaiY'6-h:[^:b$qkK4c%B9iK?q+jGU#c!aohaW]HP3aF?;54mK/uX=Q;Hd@/$_E?JG3E[dX6&.:$nHlE"fO^NWXNa2m8BT\:rcR8GE5QP8^s%)u-Cf87lQu%06?+g.eJ/;sgIm,bE_W%jO]jONnI7g!8CUQN/-i"AGX%Jp4UmC7p1cpM=370Zml%qO3_-tUd25k_.@/Y">(HT\&3V7Q]DHZ'WDB$0n6b.ku"XWUVkT.n]BLo'^`*&`D#M)dMBBBLn2DcD!js/-:&@%!2dGrum&\J.HC2D5H:RH__So_Q@A,T'16ZS12\C+a:L0#D`I.l)#mn7W*u'=AE")m4#J(hLY3a3`5pb;*ZO/gb>#DYuS`UiuG&2+q44-=u)[9BLIOn)uC2tQS>rc.S;64;'cpN7XXKQl=Xr#2&faVMODc@=48cJ`rcp4U9VJIkLe-:>at<4LKT1VnC6@^A?F6,-6H3kFaN@gK>TV&&!WKCj[GA&.rn?ZG9&r$r;Wobm_'@P9t_m:8&@8AG2Y_7LTtHDF]'8uS;<1/MNOM>+MP"tcsE&>"t)?J*7oq0OiiA1N)Lo0Z;V=2!tZS+n+IW1OIJDpq$k(FdsdW\!@4.K`&oEuo&iU*ou`a3B#J>QYiEUP9_m!P5=98Wdk&Mup8KY!MH4pA75gU&p>pMYSSs9C?I4i`LRa^;CJ6&bP"?q,`jR\OY6Y=.g6>]aT?YEVYe8gc50l;p\)>P:BQ.&?!E4d;]_%3`eVbt3&Km8tOdP(Rq>T:\RP$T"/d`:-f!kZg[[%[&HiqLN;+VE[oI:W`g(JL>m%`ALdZcW[]BtJ/eaQ"s2-3FL-aSej(52.*W39HOJkrB5\h?%bL$52>k9h^;i1`B(b+:nbd]khhO3m[=AKq8(/MN9M+p'Q.g)*"c7X('tJI1Te(m97@$4`t%d$R@"n+k)G"Q5AP_j9o1Wt,-94*.CNed5-Tf7I0o\b(UBmdJo3l/;OY;2OskdTLRdFb4usk"^U.^3.OmA_kfs3=EP""rMIOnV/R;C#DU"!'Hl#D_s\*bm[/Q>!#Rc+.Ee%NGP1;RQkSl0^*IT$V_Lo\*pF:2F2Ou1[K.S@Uk9(-*T:'7KSm-flXA#jcV^83=$W-H;Ju&I\1tn%Xh(iA_ir>KQ=-`I_[[]@f:*#g4-g@8s`nbl'dZmnU+>=XBl2UZPj%fd)K-,/;J[(I8N?[8HMFR8DbqY4+uKS7:1CU_k$/CO&#\EnXT+a:`l;TLuHbZOtcT=@:sE8*5WJrbRANK6C(LpR"'IikHf*+SG6^JbiPD&oIp'5YJHng#\Krf$K%@EUNUnUadjk!&+]H^pe[P7*%7G;)@p3&0f[@=_J"NhI!,B;Wq"35P=b'9Ytbc"0V2*L7);PSma#k'\&t!`4ql;0,7U\fK.YqP/92EVs`(jT47'3:Mu65H7K#UQi*"QuunXRXo_\AMDHSj2O$-o<5$o+Otu13:d!L$45[@fKo@'6UQ'rlNlH0E`?"[o*PaL-dg*YS[H$7%mFN,RI#3%K"gUPFbp%FfRkc]6@GH$8V3)g&#p_1YH[=?uoGZ"gC6JuN#eNt%;6\JN%_gJb[T>uB]0.U#PK;'U@iTTGrgTNZ*j'%MgreIXKG.n[QX35NMIsU-4+G&E)>-spd9hVI)98([)2L,'_F"bcYEP*e&09!hpU6$cn[I1Q<+si3?C[RTO'@Po7rN1p+T\;dOclDV^PiRT?O&I7u^G,9]lJ3bd,#j<,N!'j-qkle*Uer=K*67dB`/%sD:GG!\8?%"jQMV>KLn(ZK'58J6s!$d_XB^aAd=pSa1c0T@bZlh.$kuSr3t?t02+&Ttk??6LBMpkn5hMa*:enlp13J#OJ?k;'e/`O.-o&7^?4^j?VT$,u;4?nl/HH6pFU;0,5hhjn8_/MPT;Ypi;C?ul[21a'&e)=b3D)J88+LG-N0r33-"$+3'YA54=IR^pMi9CdDK$cC[Xsqc)/2M`Q2PbW,p`e6ST@uWj\*Eg-^;@sD'@0,rN\IQ0giBdQ:QF!cRWbT!`5>a0ZEY4]/s^u&V,Zo7Z%gF766l*PA.)%qI'CmGR2PS^p0:Sg@'XJ^$n=V1.13_W%6Af'j)4FNudHG:=1'RO&oAZcW;.D=/pC=>jL?'H'AZFLTSb"n/k?LI*5="c^FuHVH>78Vlk'Pd6Wbt;OlLB+K6r:NpNZ/OI?t,C^5?<#8g[e6*\OVE0%/VGj3*$t@oLon`g9KH+%%l$53N]:H,Z7r%#nX%o2;t'c$FXo#40Ej>GKNsf(=KeQ8fN%E1;u`)jB"]+Uer[K-[-8s7D8@?U2PfFWY?^32"%pIkDB\u:Y:E$7g]*-/LEfZAESDg7N#,GS^:+ru%@F]/BYe<6SE6QD9:LVK;)^r,'oiR#-Zn[FnX>l>VKqNSH!VhGrc7u))BhSP4"!\dYpJd2ja:,[0noDPUf/[H<;"X#Ccf?K]U:'iHT<*RA6b?d6*B]BP%LG(,)FQ8mT@\Pmn@X0edU?.1.FNc_toqK;eT-PbsccN;/Z:&BHn#308AT+Ca&%u?shS^4#`pA?[KPo*[l.1/=E?rH`4?K51FiA^P1Wp*PH#+m6A\@r7+2>AKo!ZrCV_dp"QT%9m5CA3np`5',<2M%2YB+=7pDlgC/=9.H^rM%mMTfcP6/_\1`ud]3r7&m^p%m'/eNU"d^:)I"i3HJ_[&n8)l.scYks7'[qn;k)4gjWb&P+!%<('b_da,=hcfa*8*VnS3=,+,C]j'-iLYYXRY$#acmU0P])TUG7`YqtmmZFjRHYGfFPSA$jS$hBk::\3*H+`l_P$:UkHLZf#n=/HL?#sfX9!>mCG%bdP[/L7`=b<(R1<"F>n%gkn\^\CeZPV@%YU.fsT`:K)N=p?9$m7+(2IK*gEs,XliWtd\7l9A*agp&ifEjNr95js](pH<.\s]dRa<#@Me4-m*YLUY?g':_%llV5OuE<2eRi+^AC[X-@f-,q^,,Gu3HM=j<>5^PkBp%nQ[4b:$1U-XDnR\6AETaUM55S+MkcPBm$^F>]%H&&i2L8/ONRf?GICGHZ7r45MkL\dYr2nRiF_Fsu]6Too0]E/7^E9bBtU2_?H'N;Ka!HTY]ooA)YUqtEJ67Q_b"t>epq%H2CB*j.bGh&P;:(QPT`qA?$mA"iYURG(bmpeJir3t@rilZ3Ai>ZJ4Ioke]5_#/8.KO!E?o5_KVteR?'a6k9J^a(8"6]>3kXeI%d#,N*Cl*#FT:j5V8T[/hhMWW!_oLrP0g;;BAnFNeTte3ogKR'Tmjpiq2&p3Ro.uH"b)PYd\dk*DDB!f;m942i)=_lXf`;B5X?8J0C>]m],N5r01J;?tN\iGRPD"U8H"N9TK&74Q)aJfk`blt#Z)BK=UD'4FM]nBYZL1D^1eq-=b0D/(L4k*^oFZg"(iIn)5]L3D)6P4ma>)$A9>G&63A<'DgtuD:-eZR&,kL;DVdne[6^EWG#0JZLaNl<_WM>]BYiji\4:fY`hX94@A("9t3FK8b@D#tWgiQA_+Yd*\"HXm+3!qd-b$+lWmec,?5"%b)`>>n=^"D9OLI]Fd)p]7bUf>E`S(._o,jeQXK!`juoI1E\p;?`GK\2YJ2Cb(O\Yf3jef*H`C>.]!N5)m]G5bS'TsK6oL[p#56h6Ma0U!_F0/(NDs6oHV_(>]cqO+(+pbo[4ZO#89A,W2Kr-a:pPZ3$uKegS8"I.D5;[j.2XH!-4OG0X.pL(p6r4+Y[7!Xd\)IgihQ9r6=J5&F$%#]]7&kY>,An'>KT;qAKt,E&/GpFr*1Hb5?gmL.,r/p-moj<&Fi%Vp*_D;V%jg1YgndHlMZ_J"QWFf-CO@T82e@lQ0R/e@Mpl2)+4iN^So;$aNC!mqX65kZqB:s0-57'`XER9955;lFCT.&rfj<>O((0h5h3=k7QX+75WCbK,*a>55MadBJ[IUsa*#]:spcdRk.$W(OlP&+EnpO<$n'"gb9.-In7bN[bjn\RpFEB9O_E!rR[[@VVU1jI05IK)E*fGm93Q*6oa]Tq[@-5I\r4YN*kI`Y_gAAiA?=^B3I#/_u3illV4`lkRNQmu>PJu6m$6if`/-I[ZeLO6qL`n6ojAr9/l-7?tZ;a6,/?jsV))c,:pJf"_iV,TjAJMerD4q12,Bh8L"!pJ:LVqqU\"LlK6"D<-VX4PVenMlW;K/W$?oqn-3D;a+Tol%p$FetrT28M_PSR+NWuLg^VX(d3*d3YgOGoPEn=dq"7.I*5A>@SY3G$IR8;2M&IQu%HHJ;,$OMVlrT>:rH%nhPpA1S#ko[!;E:;8fT:arAQb1-KWVZfC$MHtA:[na<_qaV5-MN!=HWq!#2uO]loeDhaaUQPdSQmQa:\/9rdkB,81-g&JS-,<>#j2U*p?s+q+X*Mqfq;nbDpI5Wo\2YOjWc*#^JBOF2PVkP'cKY_]3&2_=&@:'Zgi!%5J-e"P%>75IMo-#/#A>:Ua#n=AE%]U%`KaO`o_Ga?f!3-+6*QL-h##FuZE:Vl/*o0tuf]GM83H":6D!Cqli*0&]&dqYf8Pq`/C/FZU6BPD>m-I6HG7mIjJ9i3[)c$(.ar:-aKiAB,FfjP!$j8,@KQ\t6&/*W-02_9(3GLYYl/l9!K0=;D.8'u?'@0sY4"+4&$:MSVeFh`iKPb_2ZE%*-TeQ4s-[_c'B'-W(Vq343N833=8-UIHYt`:qoV?l*YP@5]%ZbgrHoDG$>1tc`%=-cgJb@f"0]qf5K$>s]F_51T-a"HI2'%mINn\BcFD9!<1>V*M/[FQf]G',^ElLa)FXVTU40pLFWn=cl^4s4KAX%$nn:G\X*?J+5iJt\ZB_Dq\<%-g=Telt!`&AJj6sf;2?f17JG'@gTN=:Fnk#7"/_AGqXbF:gbDI7l,;jdQ+kfdeMVr#S_..8ZLhC-&GUY5&biX%g"c'0mLr2H>"gd&[eg3kh[/VM;)necEc+LFtFL[Kc\*Wcf/i\?!)0&oV]Y8V9Y"PBJlQEQc\3*aA+[#+Oj@'!k7F.+^f0FT]Xeg=cPLdI%q/"+YM\fPGf]90P`*`Cr@7k)^tV5f"Ni>?8&f,02dF:H4N)JU63j6G(>W,Y3e.g;_g.+!54-QK-`V;]hS/9V"/bANSpE$-N<U)c]!j*DsM9O4cT:OHJ<2\@\iP2BWJ[6YM\BVGh0,d`f`u3R-c.C.O<(#_OjE-_TeGM2'ruWd>,6h0+B!*#1CM:.O]h(ka3`L7%1^1KufY^$LSLIK`iD=`Nc?"/%IjVUFr^6JRg@CpC=,o@9=WpsYtT8&2s@ll?oND@CL%B[n1VZ*ndd#M-h?&'n07gFT++YjldS7]t=NjrU-#o\t?W1IE'A55uB,`CBe5a"bn2JL5%5hFi8i4u-b+*D16>P@))X6Al"u"_D]02^"t8)bl/M[_;7]N*OJ7Fq4O>Z$G.`(m3i=dYMe3N#liiC_bi'"6g=$q2-/5k.k7i%):\UX"RDE(Fq[(`.qH0_"G14C1tXMr)Z:%?60OlM,QU<'c"-ZW"l%X4M0cOT>.!co6amf]/fJA6m-kTL9VT'?$E')`'YT2?ogRmfs>4%=R5U4-KiF]'7gHkTpOa=*'$lNMuDH4O71)g"PmeYqK`GT)@1FNJ>'"h9#@SUc\ef9]6H#p]F89"#'h(66%G42Ik4@''jK9m;Y+Ot'u\XI2RnN,Q_8l\Ull06B`@jMGb,.mO+eJC?@lhZ5X1K+5ghO:g*>Z7q6N=L!R54h,*S4p"fGuB;*="[`1.n:2/tfq#b-K<+\5,H24hCVbE&:b;XlFp$UG]712)Tj2&mnA@23n9gYFpIE5Z_),KgQ)B?lP1aLP0fI-n&n4k.?,%c8mn$`MpQ&Kr*jnBdQP4*Ha>dKIHY_2D;<:Ug^f6^`9+W^rsA2-!+1HXQ(jbH.ecL\]0;JHL>Q&-ghM0fG#&lKVp%_ln[A!huY_h#6("_0hU<sFr_S"H1X_"pJ+_C15=$%*5U\H+f:N1KLF1e':.WD]\Ef3)pkQXa4^(*+tQ]oG4a/=o'On^lkng69Zj,N"N/?!._I$u-JXqogV*t9gP]ctY-AJN[I"T4ff9-gZ8*YR5R/Ok9jkEt2;TM(4,Wbu[kSYCk)."1b?l1U06&R(GW9`TQ"Z"5j.$AfZOLfERP/)7I\!WQZodIZPq>?iISQC+5_qt:Z#4R7I0m6ZM&8<+5^).&2h,K!LB?mEi"U+&,X.p3LnhocQMi0stBCYlk/NnAdj"1+Pnr5HFjW(X$HV0*k]#MJL5Y?b![0rGH)ifKdnYM;4Xc'^\[L]/qBqI&C[6p3r=!VJX-nMPZhR15,`oh&UK05_iRp=XK"KJA*\ORO[@;=P5,mA?>);o'r]A[r:AIi9#QR,XETrsBu[.DM5V9K3<@745.dh@irbg!kO\*(6JDYk(>0\d*GgY'=ZEn+6KN-Ifcg)aDU*9Tc8[-IMB'BFXdU[GCAUG96D75dr<4E+VWh%JGi-2(Q!pB20Zl-FB/d'?,#@GAtUI1T)A6YZWlP_\G$3G-7R:ueDWFLA3U*fiJNZA>c3f6^#H-R/aG*]=7lF;DJ5;G)rOShoi_J_epM]Xg)"D_@$STh4*44*fV]49"]HdKq.QhP4>\r-rdrI^ANS=>r%_Z#=RE%f(>-6N"+Z0s-58pJb#$3D%:Gn&l)!YN`8^[QgP?Q_t;sn]I6i`eNX&jCjKPlbpEO4=EN"*:#e3/?h3mr3F7pKR-Z=01Po+[enP>c[PoAp@i@cQ?Eg^&4U[*T,n._]2cfp[XQdgn@bJS=iOt(J=7@n:riNO'E[k`j!F,Q0o!d/Mn<7UnP9V,^$/T)q.-JlB1jg$i9]c.Ob(>-&k`=FBm4/5:=J^$NH,ee/Q5tm_@Z-FN6.4j.e,Ti9G5F^Xn*./l*X#%WaGWFa]2IX=>F_m-ki?qGF-RB-;l7L^Gop0We*1;=L"==;9tgeB?lFqD46b*/q@n2/RE:(VF3=EI,"7O;5(%Z-K%N[UFIb&jk,Vjm@d#d'.c-9c[dq[]!;U3\kARhn^_nM5f.WmdF(&?rIr8+L9$$hp;3WlWmtDVX8%Tr>/"WA+#ENKQ5C>D2]6%s5;o3X$Ze&%+:(PRNca.,0^Q@;o^9(u5=^i)JeKdEG(j.MX2F;J@s.59f'Q(;.Gg*2,&O4/LA1D>..6%,VoLQFsU+/?++#D3nc0+no64HpLD%"OHjpd(cWA8;62.&m#OkIm[9/1K^WbEg3eo8W-fo+_@g=WIt)pE5*W$1HHDXfU>+j$Pdc2.G6R,(Tdlr:e@l2&k@VGLI>g,>$>h#reffJ.'dgRr80Y0An)I0,?D/=-ChJCcM9Ino1t#eIdWip3jb=BMaecaVpge):,>GM6E!.4!"iAEM/ZCo4?L$U+/bPg)*MLX`A5mB^Mgu9nJ%0.UVnl5t9,#_D7@sAB5+q?;==$b8bcTg)%h#)9)O[Y!fl5:kEkeo6fq9X$js[)Lo_/(q)!I\ADdDG-GE$PY:&%5j+/5>1=tEF3@'tR@t'#Q3K=/pjLf&9J*>;McC[k-:p'UF,HtYIhJMV@q/ia6QCV!QJQ.KWo-N=-S5_`/uXbgX']bs4PDMmu,4I7r'8eL_:R'))AQP0D5bF415_=[UNcV5TjJ(EK,q7u6%I95cU.#L\tO\qNZfB5A3!@u_U`q&LXq+)+%momLlB(QO'tKG)Zlq*+^s.Dg+r9N[Q5c7"]1`6GH#,)&aKR#&!9)9J-ki:875/$h7&H#TrETbp77$!sF!N$1n?JVmg;>,X4(a*OK.q6l2Uo*pm$gQl#YHUF9&iHfW^&m0A#o`n*L:j.5GXDl;TTh=7%W]?28F2LZ7$MW:+4+Ai'rZJ5S,-IbTOY^9!YG.g(^s29C#leHp&\3bV]haatL4[g!9mm>!a(G#nf5XLAF>3,;2MBJkX'+#bkDnq3<4\6UD1p/h"Q4j.ah.oagD,*+4XU*-Q<2CEc%sWGpp4.keAkK%e1-nreX1a?NHH4oV.i=%iJl_>3c1>\=!5W6/Y"2'q^1gYM*GSA)DhY>&MVjj!S%[u34KdG$F[@&%jI"0,:gA]_1XNOJrpD<&pl9)?s0hQ_\L,PP.Y]b&o@]t2H*P]`9tJ@cX*/!C+#oifbKCAtf4.ZT9Q5F/%nPNp^j'`F?(sih7?E'V1jYVa,gIPqi\]u)"mEbJ3/&Js?--iHi:jkF*OQTo51rqeQt95-MXpbrVoPo"UE]@CGsfBepha%YEVR:aY4_fc\J??A?kOlk@6DWfq+4..s)+s*Ba':Z&*oB`ME\$n^%f@_bg=))M7<68ItFApRH%QVkiF)A%b7_Yq_>H7Y?;f3R/aS>;K?$%/,cmcH$IE%^t0\VqM#&rFm''l=EJ3UmmUn`AAkBq<9Z0IkV#2E=Op:RJ/@plnE`+7RUU15e!6%,HWZ\>]PC@'#4'7bPHXo?--pd:k;d'j>&.;\$K"o]==ES$H.Z*=/1cKL6*=C'CD'rGo$N/Bg&s1.TYoG*A[`<*o`lAOaUT&U6kmZf4k;Xr.^^pT5`p<68LeUY]:!FON,SP"?ptBJc`ejZ<,"5F0SA`m"8uLNqOI]5qj1r&9g8&^Z3AEC)pgF:\m]&$RT:uUn1eN_gTk3G.3TbQO@H;O]UL'Y]I8u9dtWLT95Nf3rU]=CTDTYN<[Wj#Eteo*p/X4C2QLNZ&tLI,5k]d9nh3l;;mSeU?4dOu]CpGnQ[nJ?jf6*]I21S^*m[&+e:]keJs)PUugjb5i[E2b/BiPHZ(fV,Qg/pu*53,W9[)4Y%a%6a%BC6Ri&[3b?&@!1da]Z1Ec]>3_p?.5Qp**+B?X"$TRpF2e"``=(G35%>[6kPn9C;1#%`lc$5Cfb.B6j;d<7S5oVmhr2.IbVS]EOFed1gcKn/-CEj,FWB?]Z>$Nj4+g%+`I.E-W=HK\s`.IS.,=KH&nAdLL>-0BtBM,6f353$RAooC%CUgZ(Mb3*9o.`"<76I57audlR+8,/E7%0XT9>41jXUMm`VK8nOhPrOr.Bh3k]1:+Zc8NS@Ar9.@SB1T_>borjQg'Nfe3hWE0?AO./d5ri4*jf=iGo*j4?1<%9Z*#nUqY'&NJ\gPr5uCIs!_';/gA0W@8%$G^j;7Rc1<^\Dr8X*,6%#HYSe!dm[54>%YJHDiRd1fS]NOggCFLlY!mF73jhAlpVH[a[R!H,fi;>iA1lCR&iSNK^=?^5[*"'c_G#!s`_+A`LqcY)`bHdJA/d+[$Br/-a1SNZ)KEnOb'G"0o\XHk[=MFmmR@RR24:+k;g]lC;2jio\kVfEEss!)a*^IC.ZoS[[TXm>SOT+X>`mlm40[$bj8p;<+jCADTL=s`3R)7tZ";Vr@A(-bMCE.3Q%ILj%ZiF!KV+Zu0%=a@DpbpA@uKW^-CY$mKOMsA>c27Kfh9;gSS&i42!(WA3bN%h4WAPi53l/!;3!IC4J*M"%!1/U'qmtm[%.Fbh6:KZXb$0M:VdlKHYM7$f@4WWJuF^tJY#nMULb@5Vi!P._`nY*r&rmnV_o9n5rX3$1n4`L+gsP+26Knt_+p"p!j5r[j$EraCEOV2C#V:Q'ae'EP9`&uponR):4/fsNTPZk1.VckoNML$MVEl#AH%Iu!o,NpG=[eIBk>lF_Lm^ne$.pBe:'M]r9'J]S1[*hEN6LaL=4&XTmcbTLQbH[n,AGPe?p6T$d5B4I#F8)+`$.'flcDmqZ,7uXL2QXDEpQ)`%uF04R.M>*Jd2o-KchWn1?qQlH]'do^+KLaVQ_\oB;n$!EJLWT6rgVmr"pHD?ppc!]T?qtM)rdq8\)Yhi/+=/G2Hpj5a<-L42m%Kk#I_f.chH5At!>?fuOIU2H\(hM)/P,\tuQ59$$D[K'Y1X".'Uf;@s138;Ks=+LNInLaj*%SDG/OCjcX6r'B`W)hC]s9eK/nn)ohFgZbJ+6)fD^<1Ah7O@#fq$G*SP6UMRg_rm1ZZR#'p).48\Mm[orkb/9t_&L9(F@?FC[sj"70Q<'h"(N8%)'cTs[$Y65^Dc^9"5Bgo?rILqANaeV's<3,PV*P>ZX#pVO!2Oo8Oat$[&mCTa];4t\ab:Nmq-aqE6l1KZYTfg1!1#,YQJ5&$ZUt":_e/6l"D-$l9HDP9:(VaIkrG/Cj(A;5;&#@=)0>!oK,Xp%BCoI2?CdndVM]L(lA&T1h,Z)Po6St-g*EcE6$T;cOA6gXV3DS=ca6=TZ)"lud2KDPAYeLbhJs;+<";%?2_:UuGX!n2!SA[r&'\W4+UdFj0?)HW%^i,Z@nY@oRdL`(*KPk,hHaQj.sQGaTe:.Chke/eMPi@;G<4hGqXg*nUDaeQN7OK#I!mlhR-D9PkFMNnqD./nEMASg8q$^1=n.-pkV9:M9s9C#YEm0nBl@@]>2^H"K&G!40d,o;-RdX4;Qr@d"'-1l&ce^;"+42f#>s4d7V>u1Gq)_Z>48BBomIY\b4?]X5A/*6\WX&@oSn;na:]"(pmC0oQpDuI1R=Ji5-6;_h'1BEI'*''5q'g6Rd*%[EJ-UVfj&^:E8K?tMV%Fus>'`t'@BRpK?1dVQT1+h#=/)nV#DdU+je+D&P$ABrolmq!Vpc'i@_>fj]:#rI^$cE7Y3rZ!)n8q!q2O>601WRh`bIa9]S,?7h>QZOd[RYG.GPVOl*F.45NIFt^BfU[7*i\"Cj;SA_/6u+mLf9>^r=!I>07aR(.`L2J>bfb.<3*@[mCKSEpB^YZXIl-C]h=q4GC6k_V%@T?HmQB:s#a4GHD&g*V7Jg'WUpVBnVhVG$e$U7gPsUra0%go'&T\iK6@*Ki54n5t?*qIg4C\f"cl!9qHY#?TXbK?);Pib_$DtU4c$4c1eSJ[++^23VdJ#9iq9.c1YCY9*=f^*GqM\'?-So69GlP#dgLWKdab]m[U$cAjM;K[n7&@dn<1-P$PK$mHJ^G+sYjSrJre.D6c<=!18Tnf]&9EXD$HtmGqaH`0]M>97[`C3P.>?G4N]Q[LZhE;*Ab:2pCiI=W0`rSn+K1\<_E],aZ*^?(9#=$%Xj(V@^QP;a8B:M81N5]Q1C\-YL0L9S>2*)d/iYSY-;nJ!J<3!$:Q[MtCBfN,XRV\D,=q99Lb5+T<6OY`oYDj6EcBFWiuB"A'DWujg2ZgeHPI,cFZk,_4$itfKl8mU".dAo\M7p)_8Bk7'RI'bn>-5\+CP1Z#G^0QWnW:)9SlXsAlb:dYZ.&um'a>!m^U4&ASd;]^4p@g*mTWKed=#]!lP+suP9V?eIe/H^pJ*[jPjP!(!6*/kh'2-3Y:`bOG[Q/)p"&^2J2<:Gu`0lY1YU2/A+!_!R9dnJGIkb)o<+tZ.&af6h0_9g-B\sm/?[L@@88nBE3j$;i=_F"N8/Z]*6+^oZ.cupROPphKl94/qI&f%s_LCiYr1an0<,g!HQ_B_GL6CBMU+u0ut:>iuUMPcd&K7[Y_O?l>ie5N.;\=M5gePo$M@LH$>YY3,a;IpRH.@I(;+@ss$#S\EsY&Pj8;,CB4-6k$<]O6\X35%jR=JH!B!6WJ)jdl;^Ht8@.oAkso;@A_PAkI%n";j5+D6&8Wn"-!S_7^,s2gnC*o)P!t@9R7Zuf+%rn0%dJZNH(7-SS)Vp\fsk`eZ;so)l$f#M+lL2jCQIEP%87f]'\5M-G/GSO'smkZ2W8tW3c5@99/l@"*:[\#_Ql0]sLEc7CsWs)@%__m>GELZ_,^^3ClFld71bX'GgBrt'_M$2-/prUhI"aS[B_<,>oI@T;"a-t4g8RFTmA`PL#o/gTf_(=?;6,*#5pDC'77n>t.CT[A5M"7MQ"V-u'I8I^i.o9\X<%(WMW7\'PLU6earg03tbGB@5a">E!lLqp^Fdp5)N+njYNc-p/F4B/tf$\k#1ga@Fl+Ms6gf$dP1rN!V6:!s'X:^)r1:JiIb7[lYj.PbWA5/T51LDMue3NUJ/2o&!<]$$u)SI`44s<V:q>TX+c,NAEWEsADEgO4cV.j_O\]HTmF^%JfqQDK^L)AuE;MqSV[gJYWHk*QWjU?=f`*M*"m]Z@9^fPWdLS6_\)/!U2pS9!QK^9Hchpi3Jb=^&O$G1ftm]2f_:lO#B?ZFE3)X3)5j(ojuF,uNB*(pPnBgY)@"^#Q"_@u63:i?&6+qF/HXq<]tmp9,o<6Mf5(ZCL>sSLl:i($+r#4VaHE@@GN&fOq$/qn(![mKJKFX'9gTom*!YQ((Z!E^'FKp2s'ogUi-[):@<&WX)7g>fWBNbZgkc*NC^u]2S/%MFmV!VX\sF_U!6hZ'8)A'DKTtGGA&7,Tf@Dol`FPkEiEI,OCIuN-B55GFm)aU/7ti$CYD>f/D`(.F-*\:;iG/ll''J>OC$7tp[[\*YfO+PR6\`%TA:?+`jt=$E&76o?4E6PWOkSXBa3XhYiT,_H.+(ND[cHq?#=*%3N@+scEheaMG,Kh'Jb?3&pib^a*O2KorVlP].(q$55X@/F=d.L9R7]Q8N,t*8$:qh0JLVq%n6OY5ue=(kjFQ76k"I1&pBn@N;IgkNqkB/@^P*!2X*>7HFRK)*8iZUiqN#0L:CpL$afWJ#CcU:@siW2?e:=qg1-*F@a/b3cKF&)Fs._1Af@%o7M:`(.%.2RQ&o/4M"]\&+YlVG4slH`V6q5Ag-M1"3lpq'WG+FHgTe.W6AWia.)4D,&C[M82rMJSCe!\79Tq<=+W3M01Wgg!MG)^@R=Q/Q^W/,%+]Hq7srWO%k]j[lW51Uprmnuf<./AMpB!XcD^C0ODqm*,FXtYk0*%#\!3cV1P.0)Y?U-eSLl^KADE0lDd`"pbb]cs1(G/go2#6E)UNp7K.^9lH"k=aGeD?2-e?8Z9PKWfmQFfFg'"q/YE8.!Ln/_agtQ*1;2Y="G$3o*gQ9[d27t]b$_>O0L.#HP[3[:/VkTS^c??=>)D/'ph=d`[-?&Lpn*j&fW;Jbe-10,3M%>o9]dY)C?*NqfFZ`F`NtnQD3lX0U3Y?M:k@rILa@W1%jRP)E0s\Kuc:-H.E_&`7YpK#$rWM)ihXaC&5pql>k*9p=3L-Eq2^.Q+@-X@J`?W0%ebdS$P/0;h7EOeAI0H)'`'K5.lq[[#"K+tdNd**qK6m=:b8g)q;QP;o4\@S"'U^,\g*Fu50#ef>+e))OGfjV.VZXKD/`r)s2^LU*5XPuh0F_O^n`\$RPPeM%pSiZOaR9q`rpL(:Wki0h=^bA&F"4RjTOqj7BD5(]l;RG\JbjZH%.2JdR8gq!*g674`X6,@>[.LYq*2/gg$sBT(HX6X_GhoZI\m^Ie`uLsI"^Q>PKIf[fi8?at++%=VBp;/1Cb5pgUHTFrFH"Cn$D+1//XHXVX3T-9aXU3#^a(lGGOjHF%F1m8BH3blgXnMqD/MBn@&LVk<6.)"@W't9`Ja%%TD7R)ajah1O\O>Eb%:bir=R`^_N7?m!^mEQl8niK0:OT.G2:_]$$$PM_gQdMSf8E("fF"ZK[*Fi0TS1'Cp%L(WPcHglh7`NP\;2,Nk]?HNB!L)ThrS*)P:.OMJqHiXJEl7WQl^rsa2XbC0fDe0g?i&dr7oCft`Q],52qdeL+nF"X/10n@r-:QnNmb[O>A%\"X#PU4>cHi83>ajfHe\a>V&uc+!/96^-[1*gNPjn2kuTDXKpk/uY&.k?f17C1#<3(SBTVe[L1(]8hXJV+R7eCoE:($$*#q>UX/A9*nFVIrrq3io1Q+<7N9(bPQ0hkdG&['.2L7I_cen%#[/uZr8qJ9i+6fgSo!cFT8eGKQ`kPSFDgZ8*SfX?9!N:".7k8[nRdDH9@KfM_i6D?nJe5(q.no;7a'%((,<2Co@qc@)$r)p2MPb%QNO(%Z[d=49cXFLFo"$r.*piJ?pjtL"A$f\Ia.53`CNH"eaJk^Mm^^0F#k"R5&ZT>AS-Wt`G--fR@%]-N7.02P#0V^dq^P(/\444"\V9n80bLd#f\>>O@6ol-$c6QiC*8U!Kg@0Vg)W.?*Pb,Mo^GI5Yo$2bmmD\8!YJ(oXj`WE,iG3HLm,'_1%+U=8#FNWl84gN6G[9A=RGWF0mDR()&h.WPA[Y6?1*d8dj'8!GA@d;ujcr7>+etSihB$SF^FG;Gd)5*/#+CC*%jh"$3h9'mdRnSR*"M@3:TlIa@+^:TnV,#B=]hS5^`-1E6);o>oeVS9\[j-n6NY.4>0+hQSRIOtc''GM(l]\-ZGt]CHr[2+klM+`-h)ckcadIfHOT`.V#_9N6tAii*2E?18m;GZtlq@YI>6M[Y0o6j:$`AQ8PLOOGlp7l+'++Y$QJfH"J0icmcq1_ta42`R1+?POh!7_QqJaWMP2Z?'qq,E%M+DWmIGHp`uR"khMo9:QnU\)G)H-XWk.3YupiL.a_9Ra5lps.n#,luqk>n$DQ#695eKD=*Xgi5-@.$,^+kKeMCaJ&!/Ga_%M6H+5Ba.aWn!7XGr!mN1cTb%U[;b85pB+tq#-ZTT(o>/k(4a%.gPC+S20-BQco7fs%i%T@Wjo&BrJO#TAO>>e+a&oA\Q:aT(ObQm/6nF`6dT&@.F1;bl5r%VoBJC%g_%M_.J_W4JhX)3jR,Z14#\o7Lb8^A^@/2Kj5/@8_SW,$GVATV70N;M?SKPbNbq-t%Y)qt\4%KV;"f(o(%uHkHAUgc8R=Bd'%%N"hGs+DB3>N'DPE'2YM='6ssOT[opaEG'b2hn/[ErBCA`8a!8UEE`?(1&b;$&'Oh(a3j#/8U,W`rS2&/n*0gW\GV9O>*^*\SprC]<4bA-[iR9a$c%[MBB=SK#G'cuIJH[[cau76ISH7_Ln(^>#2A+"H"F2&ERA(,-^!.$p&*Jn7"\jY)aY,#RTXq5Vtqc>n/:!,5'";Pa8/WiS_ZB3dddM,h&Y'9T?EkEZ!aecW$gp%c#_EVOe-`ggQDAYEgqIIr/LU=oBu!am/Ga/V1)*#&AA+krP'56cd?(un%[VKK_]tD[?b\%=6nS"bo]E`q'>uC=S7l'rcq'*aK95:G0l,J/+n@rFhRQsN3`!F1\\/VDf"/^.o>qr]J0'Sko3hro/ZC)h4B(%bR]-PrB\o!g$n$)g)kS-M)I)5hd61](Yn'*U5pB:^J5hV_f&ECrYM%AGAhE=n>uLg^JrnTcVLIVlht1nhaS3Uao9?VINPIQ_tS$2QgXA?-09&>'rO"`rh#D3M<@NZgoB"<4079_o=)S;ZfG\WZL&i:r'"(uK6iCP:ZB+u-i*ca?7aPer#]bXBk`KsJhQbD`W"?5+jf3p0_u?.&7U\5IG-XZ^CD93^D,k7Vi?c!2"([]p@H>]\*om^gd.T'a4C@!_4GQB$=7edW1fW&W1=]!^g.Z1MqG($!_h]Dk^e=%YiL7CbhS4SkYL*q:2XAI>fXOqBq36"h/@u2oA1JSoiL1!e)t@+Ge*S7fBg9/qgDc-93aQC*OYVfRqO40_08nNASdidW=p.'VUeG[,-pN6A]lcA[io;AM_oDmjrclNYQa`;jeIPlCrM@0)JdppuN*Z@;03Tt57Il;K(oDQ]!A6^sCQOd=UH65*>r2mi"%=2XB&!,@lD7#k7r;28?*tP]316gnmH2$JdO*"u,4tgiqhZI5^V>+:_Jn=:2#r$d<*/chbas>kse%u@I3niIm@nuR\5/,aq)rb?'LB]*FR4%28:t'*?i?CaMVQh;*lJ.#CJCr*`,l`a7S1s$C+f_:?":uEgN->T&iW_5\"s=FI?/^A?rZ@Qqdq%NjSnO$:Y;WD^Z;g[0X'-3LRkD[CfiHX'gao\d>V>7^M#>P_mOj5Pk8c\J.*u[X+5-I]=NJ*Hf4P1s9<#U(/Yqi<-.'^X0dKJI\6(3pO%H]8k5qMh>:"&nWmkQ[ti`3IrEC)IQ6bCJDMg$0F+R5*lKf)H2YIZ]U)3:FeYZ1g%fX\`:DrYYL>^jO[u#jSe38AF\6]S0%3mds36%@^7R:KO/$uJ3./AUpqA_-q6%J6eSjKW\$r,NYK-"%gSOqfmXP$3O5c1)rE\9`9>mIG?`a)e=ej(0)4]@NHgo(R:Ysba1uWl/]8l>ujpN98I#V]e")J6E$ZE=L9qjp]L<:K:T)l`oOj]slXX"=[I##=T*Pmr`$""Z)3@q7ge_XZhT#gbY8W&0[%;Q*_p.OqHkIHOA(A%>n$@-6QN;,tZiMn%_[oPi"4cCKil34.pj&QJqd.OJP$PrTaXAs'4!p@B;i/6+BX`Ke2@ob!E9(0/1'KpbS*"9AWKP#0+G+Yd?"WM]nV;(@\HH!iM(Sqc%h%L4Ep$1Oa?"eFZNXK=hM[LBS.".La<>F.?lM8SmWssHon%mIR\?F\[bVr,VXnFMZnn6c`-k]Z+mkWUV$,uHbX=q0BHPHl0!Gu5Gi7dLqku.Lr;[i3Z82N#S"u$XI.@&fnW"/j2M0%4,sqI)t*(E/mLoP\XOeaULFe3$%oU;5t1p8EtKH?;ZZ>_!@K'\K>2cnNb8nQRA\E$,9dY<0![TPU(-l6';_4(-I%Qj%5Gt@7EP^M-8)E5"4?P902>!Z9q61=RV36l4#WbY4PIn/5^BXpKSRj!asWek]dVYl^2-m3b^rR\1Xs-bEm"3%;!)\^6>YDg$Z]N4=N#9YTs,pe4+-rWC&Ibee(;*cpbe(mq>KWGY9Gr$*Ot$ngl%PVBBJ'o+>piR6h3&0-^ZLS4bCD-XG^l,_AU32N1]G@(HL33"nc)P%hEE0^sVNFu=6Hei?5IYu.C#84@#,lT!K=kYGdN^[(KAnI1b8_nC@-;c+7#NP)Ye`#cJ,f1cMl8V/;!AH">Dn9o<8J'Er$:LM2DBS.nASqf-BosdjU=16WS%O'nAI$Xoa0_FLP&`ia.&:,1ORo"/CC#m+KiIc]t6:7#?%B:c%j,e4-:BBu16/`[P#>Ca0m'"8!12rH82NNI*qc8h-"XV*SOR5M;GZIn1\CE^ofu^#aL(5ID1_G#*Sf>[h<>!*caMo]$%F`n(ld1=O*3O14[1ZI/j2Z4'k+W&Y6GI%:8gVEWL'Le."hDXLAApH^h79a?ZD?Yl2QTOGEI.'OdnJ$9r@*LBm9(+?sL51h'A-&laq&7=fAKN02TrsFA]c1:hENOoM6Q:I\-/n;2pGFmXA32jDa!V8:K>tk6]p>C'e5BCbG6ed?AjVALP7%ZM_]BAINGHWP[Mk!E&5e+-7V6>$tW%-3Bj84"J)UOjK8)Z_WK0[CT5icknO_\ocj"3IOOQu.mFa4)=e'5r]mr8/no.E*3/s*L;hL[kk0s(!MPR&3ClI2<;I8Y\PE=((\'ho0LM[X*TY+C71>Il*+iuJiWmGf6NG)%si^j3TZr8[`Ip"R28P:om+XT,Di/43p,j.3D*b&;I95-aIWiFFCDJSJdNC'MCnqB3'kY"R@ZM1O@R4;,=V(V>SX:M$>VhZBCO@3AC2Q&dMq?U1gFdqNFsTd;/\A/QRkTX;IG=<@r'tb_@;F(iRH(m!MB\s'T(I@4=LZ',kXS_nCE-n?X8c'0E4b[m/]t7G(2'kT$]D3kC>Kp="Xo*,fs-j3LH.SR07aDGLdj<-1W(dHB*8kE2VoqF^>-9@eqpJLm+N__S%s.saL@X-JWQVE@%;lckZr^VZkheaKooU;P%m_g)t(G/fLkNjn#=n/27s*KG<*CL-]_[L1+c594OFj%oQ#+2b")\kIOC5<]FWSo[;Pd@6m.Z!"]N6:WgWV\K\1TsYk][5C=NJ]Xob3Yr.]`j:"EY',h&m\95-R@*MI^g9uQ&GYst0J?Wf*G*<'AV@$&#<\OG[(B#tM7JHVEDs_E,o*44(;U0dLFYlG7G4q1]Rj4k:-Q7DW^`#,;\/JeG^K\`4M#UeN*.\ADu.im4I__L9\c!HRRoT)m7GpT#>#VRZfUF>K8:ra]_:*Z2OQ!H]aRJgX-;p:Ui'.,Wm47jIsDoA\]7#3/gLQG3#K]5g@-o3sN7+4F]H@K?[Qb_iif%)E0d3Y&+m]iJ5'<(;!$X#hichaEU%[/)JJ`RkAr,`2NjBN`L.RuolFgFhYs]!ZYrc!jj@>=kLKMj2Tru&KG>didpQY'(193s?:.hb;/pK^aN^7F_7=l(]chC5Y39A16$!mWa^']8f4uFhKS/atfIn"1e.!m7Je!CqI'5dst`*s(9Q$!@5aG==u<"(QXG&6go=tt=I`#h%R6"_2Q4]_$oLVLp`f]SaI(Bf^tR:aN]ArULk'M][e`2">i(?qO&kZA3c(s\q6Sh#c0*=I*n&E=785Bc^=ihY['"hhJ4RRlt\S5*1[frI=9r0af.lciUjgWU8q4lmQ4#nEL^Z\'^:fi%2"i$[pHBP:8N\Q5,:otE!%AjJdnk&dmF%4AY!$)=)&9\m%q#%cJID7U@Y5uB[JVB[OEEK]pReJk5-<\^Km`?2\80(&2paf)\?6NTTNq%S+1W7HlA,\LceB);B"RR_5#MTKZ$o6>I%l]*kPA0BFAS9`LOYY+1673.IY_H''A.6F>'B56"oU'7(b\lQ^.Odcrgo;#:j?t>XgMpU.a"`?SL$E+JM(b$ET=ra:R)o=&fQNFrQT$L<9U3cQo]_W=J:9:SRI(Q9r)@=iJ5o7u?R%FkX,L=GuRB=,9ZANE4Je*NoNL5>(Z%[MAc)_JFZdsQ[C]cdFVab;I>dZ^*Nu/;D\?-/Ws\YV@>/P(U5P'*[=4RLl)+$3dm99D%8$Ju\.UjS&.gb3mKbM^HLC#GPM\W?okM$371:&c6FY8DH#cq?4\!(OE\(B)B_nR6;m-3^YVW5>0+#f\cl4%E99M4!u\gj'j3^/XCL>Yj\Pq\.?=WgjsO%IAmE$,ka4'C@U)j+_d0#e"-#)+m[Xk7:\!8[D$u$VZ0om+#b/RBHC7(#/L`4,bm]BTZ2srX>(=\4$D&MApgV"E5n:Z[*I\>BZkBt;3nqf4-OmF(O(pf?.DG(jo:E1eW)Ud;WUl:W(D'NH3n!B&Msb^o67`k;XCng8YgNq5X`YXmhlaoh4t7up!aM60VD(S@DTa,/VR2M<>;JcIR8r10?SdW#BKO9+.-luhmU!dXg#_qISDbiK4-fVSn"`S$-M]gn*E2co?q2ChJs,F/nS1Ze=O6`^=gPRd[[<-?arq?DJnAp^6i+<&'HJ7]V,Btua-utj.t4`,Vd-n(+gtE?I(#m8Q6NS4!U2.!N2C#mL/-/t_p>-2\bmV_^RbR:;9ECuN45j3bE'Z**^!`W#p03+bfQ"PTq]TLlcrpNkAMs:"P('SE`\f-<=EVZR(Z^`FbkBNN']TdY:V,H0-W'Vl#pnPa&m#6j!N``rZ)^+0d[CNoW*l#EH:itF!Q<,:=BMtm2N,kU?_)@!P7s7":\HNabpOeUXN3.pmM-;eF9,R,E+h%WI\-A>tkJO0_cQe&N,+bh"$u7-/!PLFPT-)b@(%-qg^jMMSq4Im6&a:q#6Wj+!)%8:*@_UDJt04;<%\25kHF*(dl(fF`9t9*A":ahho%e&k\ERaX@^moYL7#D>XVh4,PtbMB!l*nWUsQ11:3LUH;k1"##`9]8=_g%@O0IK&ARl[tmhTUWiOXm3os5iL:62iS6WqU`7?3eW&9%s.9?RT7Q6IlStpPL`h"C@:_c%c#Yil,@r>il54J!N1$c%6kIM&`?J1t4*PkqsV$b_pJ7!ogb4rgMfg*7V[5o6s$(T,olMSS5Isq-0qFr*8[=ZE=I,1i;oci6M:l!&=K37Pk(Bd+nQgKLh05iP7+^AiO$#5#0W_nJ.%+FjiV[IoM36almP8p\X/*7&I'H8k.'01u7-%DmT1mer\?iAhc:YH_M(0uIPtUjQNd#VlldsF28BVt.2Aj/GSu)`ApVqmNBYq@ZeaBt-\t!7OMnM,7$6lgpR7_jtp#eI)4>3e4c\*-JX/T9C_BVe;r2UaL5)lg],6I"KN/LS99[%\g,<[[m752]U1ehc:\QrW0;rfU$@UVuBQ4DX.pU#p#Po8$s5u1&>`Ur]nq=`p:*6Xitk?&c47k.5rgI@S6fr"FnG]DghF@?=9an#3@ou`T;bhH*g$X79(j]3cHMp75)UZ3(j-[ZWH.@iI3;?Sn91mWLJLIb3PlBX$%]9bXJth0S03_oGdD2LM+IGD!nV9?X_,N+2WP\EmC;QF,UA;A(8(PJXg):<96cD>UDCZDY,*UX:P\!5HUpJBhSO\_QuhT4gGq0;h]SZ6-`s8gVB7H""/g4JrCZS%g>e/@`83N*4K)aVcqt3\MWs:-\3.tODN`(GB+$hM1n@u@F3KVbj$J$3=k2IKhgOSo.GiiG?f!_+3*IKQ=,+3XpBo:N8oiVfc>^PtJFsY]K?G12]e.ZhAriB$bV+aBDIHDefigbDFLDDHEj(,9iitZU>sG;GZq#KQ\8F([a``m;0&(q1l$DCT`7-a@->&F;<[$^JSqaE>gCOTN)JR3la77:K:f+t]R$\R'UY*MgK`T0W(icVU;?&Tc@a*kC@S-m4TEmC]&eqF@iooK4EL3DpA*_hH6,t*B)6chLA0)kGjXJ!q>#*lV=:\;muqE`eS.S71B'ilmcR3,lP1[diUk,*iSEGeEb2@n1"'UI$?H_KiM;FYbD?mLUAef#L&8?)(;HDP)G#E-n^!)13^5V@Xo[>fpuSo3r_M=>Q<6jp;p>(ILAcibauPp[I\U!2^RUP!N7:MSpZTWCHI^NsO-S8QHL#^VH9FRh[DKW\N,f6K+ipk!f&KilK"GMojO\pI2enBpmQ,HhU[:[PTj]1&=u5.Mnlj`(-4ThP*:]k,T)_#7tdq%UDKXfB_O-6XhWK>iCs-ab.L6Th)@[>%S;kkG=]-d=*b@DIbae@-Hld-KR8h(^dg4m.66d^iD[_XWifLB3*AO9^F(%HVUl36d./u=ZseTG3iS5m,ZQKMlfg&?^4'>tO+Dkae/;*/;-YCep3^n?c3c[kVR5SP%($uO<;q2*.ef.TU\1OMeugDh1k(Z`W(1JAN,iWm2Oi3#YL._j1uIGIC1TG4=ecC412\8#3V'-A,;d`Ob':Mkf+2n1]))_-noP2'[qp`\+uL6cj)GRq9I[*oaW(-0!KM@e%(>t>nkQC`D19q@Cop7l_S^L9$)dAFbs-t0Ti5#N\!r$l$RVM.h%Q!'p1rgH'hnudpb\I)=!N4W5p@di<7bJ:1cWZ&-d&:X_=hNcolJPhRmdJNu^RDkXDAn2Me>O%&q)be_W'1UqH]IR`/dV8cWT..BNd:*r)W'O,rseEn'Z5%Zk[l3^,tuW0Xn"(_+URga/CGFIi$i/r9\nse)B?\k"eiO3nMN%IG15Te7c'SMcPqp6Nkb2d*5DglXk%+5>V!U0eo'd@ieKGNZKTY`A9Tmp>U0ZOP4IZT>1>ST;8UQ];3932)U>V`Li.UgMtXNp4Id^)<>JG2QY<-C!#:]+N0eDTrd9:*j3G/St>N9rSLon(utfQR%3Uqm`1]hOc:0Ou&aMH8.;7#QrpPIp)SjN7b*S-Qt6O08@qc02D.H2)$t#m)GnFfH4+o52'C;7d'@[=NIsC%EbLP&pqRM>oe%!*0$S]4aD6H2q;FHWojMcC)/oH6=bkpk2g;YIoir/Cs:G0j.FsnQ13+PFKnfhd/`>C/T/q,8Q_S*AEFWF7`U)$h6cYapZP-4Wm^Jr&#W3Tj_&rOVn[N?'[.j^@.oq=kSCK6\\sDEOE'V'C@8K@5X<:8G@oY&nu3o982`[bd#*c9E\YF]XkHr;,Ti*2'2ViH>[+'1#s6pQUp)aN#uX8D2(,dXp:!mr?H-LrXHqG=Y(6@\\-hdA9-i,f)*YqW1@t>i37trQ9-eeN5JZmB5DM-.RABWuPg&9O!@IjBWpR)%b0@YnSaJpdueqc]<_.[u8C4"n)nB(DrP<$Nl.ZY-Yd*]Y7`siKk1;-H+(q\T"^#;n7A<*MK-eLT@pHffp>AC-%Al7Y_)(hoD'paTDP]g.\iSaNM86[XAPkTqHdf^5`Bh2(<.,#p^A6C84kCeC:5?8*e7Z^Q/I4BOM"MJf)%#aL3&MofK2,8E[<>-Z.'[%jRMuU:l=O3ngj&NuLH*Dl*`K>nd%>Z,^T+.pUi)\s0Ho3!WN'9KPcVRpFZCnJ_`Z%i7T60.3FP'bVLaA1Lq!s:sMV/DQM?4"(V3]A#Qupt#0]L[<2`f72929"1.6,hMO`P"'k>m0b$Q!MJT#-t,.^=NJg`pBd\D46'Y$Iu\-TXe`c?X)k,`Cj%Hg(H`_M\^1EddGA`^_c@T8"lCOm\5RT(u&9"0?1R4iD\mrS/?-."^Sb$jjP-]Y1N:cKi)c9ZJ.[NANP\q.=hKL"QpnV0S8ghqWUWGFZ%ijVBNu@J`FO1/7^\([s,PWaL77#Lq.U"2mYM.-[BY_3O->o,TN,6@aRA6Y("C$48ZB"^Im6+q5!:,dA;*<*>'H0CFO_A#TL@MiFS!(&e!8o2Qq3-diuP$G0TJlFl=+T)jGuJ4kt/?`Ru.[SF9l%%f/d+1("2:be^7TkRX8jQu@o>O"NT@bI[&&tp"oL'NVp63WRjaLWaT?5gGifV!fN+Ne/uZ9Or@`q/6QL,QJqM=8^(T#Y.4gW^KV%epV-HSMf)JcL?.ZZOOR7RAo\Arsm\A5,@/DL9d'5p&4j0?]KUH>9V+s\#t!F@-5hVkdQkkRln3kP["t3oFasOX4$=_^:S^&WErH/&V?:"f#pV$]f.IJ\?c+'pF0M`CjP-O3_.p\58B$DlJ93H5SYq`-0#@'V3$pT4E1'Kn%8l^BgU[l7&DWhn@(WIILuoUQZNejT@W()G*:XG,Z0584&N;F[]Q78C+[g<=B:[W(pGX>F)up@Yfru9>fr.a>Kpd)."i`Rn_hD#i'\$o7kpmVgk-(cJ&.oE@.oHjD9RC5Q@O]@`\AG8%MM@AgWt0(pj@/*8.;jjV`?So5s[[FE`09<8G#+XE]F8:r]V8=`R+L@;lPEGY;b6bH#WB6mV"V;@hAPa'Ue7(=@jgE8jYn=+?a'pY/[\i6OemTdtZlt>E.9]"&epP#_P$G0M%9i3+:Ku$p/*=lD^e*^p.Lu5biNNHSb3WX(LGED&,k*74&s.K$*Np&A+-]-s9PK,mHNDR_/R9OR97c8]4dW/'"Isje"0g_dj63a.&P.P`4ZkG:o>Q8^*d#\-L[^3=?NUP6iI!:<=Ai#'@GfOoQQbNT[qD=d2iO+FNGqnaAWI/R6Uoj;?lK+>ZMA':@:/ZXXLY8i,PkX#*9(ihDecX3jZ.J)*gf=5BB%1'bGfsLJC=i$lTJ8UjT4hasm`(Y`=I;WenM;;*a2>"H>AP@1[]nE-;iEgmr_RrLoIQ7ini5d-%k\p?H2b1GCbe>Ei(sBe1u,Kh7aH6U2ooMi3_3>@kSS>kkgY9B68U$<;5ob3U1T'l"U6*cK2!X*#@KP3M+dGm[giD38N^*LMuk\,?aY*I04<]r*>*bjASCp6c=BPVoW];\1T,+;R=BY)\l%'WH!&KT6`2^uskLe&tI`/ofhUqDM-2_[#()alDZZ"Qq#IV+R#U4G@kobm-!g8lfCV-YO>LeRuFe2G7,a2?ODLKS^4"L"6b^.H/[HR(IZ3GHu[S?($nT%Y%3QpM%8+%A7?6>fBkiB7R1%f[1H+Ds^PP8q*-,QZmO"'JKWD@V47RVM0*'I;B$Z!gd:lanc-rb"ZK`lqeH(*:#-ZP5(h2nrOL@gU.s@@,0AG,C3ni%=iHbmY=WV;[+5odDJ/:(#Ri=T8,#WlW\USX_0HBq065n9P\!R)I_Z\Qu)5b8=JR!n#g\s3b\GkN/R7]8KeJX)3Y1GnFt&>_gLk?S<'g/G!;@"oftOk0[?nV;qK!EMPk,0eK2--O[HsNG_E>7$!!p7W/n-N,#)JYcoW$(]flF.&2jI]#3:;b2GE1JeFYOi=NB*,?!PhGlH4#DC6FC92EO87gGWPpJWW0?/j7"@]:@0X3tmGX&1A!u<]Yb6("0JsqMomInbn[E<5,+BE)0ei&Xo$imK"rK]/aIO=0jg,F`>[YKDA^?4clKVX;ODhbd/;*>F(fQYs3h20eR'eVsjNV`3Rs1SF!Srb6k3t64RAf>UZSd`@14@5dklssl4t5gE.$T:6i"B]IMFeC94Jc/1p8Q'.6NTNb%.q@:dT`mZC8TAf#&%M'bW22:"Ik151RR-"a?/rT(e-Y*)Z49r%#nJea/2**?@MbA0'(%Rp*o.`,D&Xc$Zs!'0pIMUHMn`L:0\$tl+HXa/lGMA'i]lT'"u<.-cpsJOPrfD1'=OIK<)XD,pB&hh4m?Om?do*Nq#,T_,hTN5hhfthr)pJ(h?R_FB2[E=HJ5CqiU4"G[15:a3m[X?ZX\J]>&H%`Ut1#a?%q90gCX9ha$$l:@IdNp7aK3_UInmKPXcN_IW-:V_98pdjI1W%%88-lhK6Ze7!2#KefcuUViKOquim6Z#DjgJak,n@6ko5Q8OcnKU23P-8gj=4i&;tU#:n^8o-^opI+D@LYmC'/bY.BoH,[9%Z5.-!/Hp@usgq&&-!AAB]Is1SUJ"Za)ZQEi+p-6N^HJ9dVBf+@M?C-WC_a^^)=8OjelP0?#'t<6,OoFh_@Lf7X97-am*\PYDr4ZD9\a3%1_!["VLEHd"lJ$CFg%18H%Kc)'2_5d=dcl+WCoKF2!@c>UJl8p#rll&#)kljjI-ndf`7E3XmF+>FIF0a4KuC6f;$_C-!(CQq)LkUjBH-Y%4NnXt0)WrOEc06Y)rSWZ2E+(s_/7%^H[Q%.qtI:PK'hF#l&/Ib(VGJ1]?R)BG.Mm-5p24e$I!r'sSm%H6("(Csu$;\IfM5/bS.9:Q*dn0G=rA[`:eOgkFHdSne[C$;6Ba:d=On*kp5a,GVq?,4b2`,r^]F+N5#3RR^C9nA$Af15hmI$_CNk-\qS>U)P?R/N5MaXPHLXFoCI.OE%I$q(BiFrt&;o_fth!ma!9V:,K>;5;5EfnO&BZ-dgY>#QBe'pW#s[r*UX4P<`!=6(VFLY6Dt]FlQ-JO.W3O6\P:,R5E]\P"0@8Ff_s?[?H"OO/=7)[.]%-aAuoU*>([!mH>)QD=b6ijcuah'Ghddo9X?1Gr:7,Oa&i^hPq(N5GS%(H4Zf9Y2F[\cjRV)K@#uJR`n?e%F"mnQ4@i".7VbG4sH>kiHi9`*pp`f*`ZX_g/%..U/8VIs3gm,rVDSDL7"u1[h*$gDmub!_m=?BjloR1KOa3jPUkE9@I*=q.^`p_>*#d$E>8Y`H`79`O0!'-F^ZheEeD&KbDNLJDCgGa>+3"A/CluR(o8\K:Wft]lb$!n'.!PNjsVuZ8n>+\PW$A'5D,k'TbER#G9QM7[SfYh@Uk_`8,ssilVOqV@o3LlUtGch]/4&_ae7[_[WP^Q.Dc\Lj7:1R]?^k=KN&HeC.@+1K[&/5S4Y;1/i3WD9&UeVBe>:W`NG^7Xk.^rRnen(Xg/gEO55aS;Dmp^N\jL41TBr3=DeP?&IbKSVaLpi..N\&Rq^j$ZTbQUKn4WCOA4bMjBF+o.TR3fJHrS8@mVq3E4VMZPl\&)gTVJ$Y)%"%6ODqUi.&+lmpuaEiNrg62;=.8<)\g0-VoS*FL6s"BZ4p\T%])L2fc:cPn#:-j_qp]!GP#G3/>pq)DG0(T6s,Jkj\:p99Z_^XaSaUn0r%KZG'\ACCfM5LRUuJLI;+OBkAlb-@$1)"+P-nQP+/:^F!^3.:%COiST53g_j>R;@nKqm^H?Z=_HVJ\Alu>+d,bD5[=/7)".`NE]IAsq\mP?kqZF6f8q:>D@Z4TWf27(5(6N%gGC0%X'NWc&OnU'?Ca):6n'=3g94:d[&*M)mb\KB/Bnr&acB&9*1!]YjNQo$:>)FR,`B'-M70S(uEP#oAG09"V'POQ9Ne.dM\"k8B$L>UMiPa&JGfRmU?1>+*3Bl7Bb_rT.fdRjQ+'K."W>Cr.)`3u'#uZpV1";:DKO*0Vekfn;kD2=@_hR>+.:+Eiq4l93qeU"t@M>>BiuoZ)G5oU/:N"B2?DCch0hc4HGEQQF8*iIgb7T;#:k]>HN4"?D,>N.u0"*SV-0m3F`3+&ej+S*Q33RZo,>V*lDR(6?KG,VsI@6n7:FK"7s@oCJ^j_=+urJmrEKWdn(f%[a+[@?\Oqo5Je8(U!dVc^&+W1-HSe:6-_M*q$8+kCW\nbhL^N@.$psj3(QnN:.t#2TM93*bHgkh1I!&7)>3aSbnHRRLHJDBfNqb:2gV!d(u.P-DO-JOfr"V<6R50.?RaISIZWiLRNE^Li063pEA(N<6HHa0:bI-P>/afG0)d&F<1l;fO>?6,8K6V[qM2Ohgf6QKGkTo&GL$uc?>HHm>CE=U,OQ'<@8EQ&HUQTO"@AUU,F2C-Bj7SbV,l0(]HQJG4LfP5fr>/?N7/%m2fB]Z`cd5a$XYdTZChNk4e5Bh*DRd[E1esQ9CjB<%\AY'!5D9pn7KaZcu,jU\@":GYB$T_oI_5`6@+TrU@Oc2GbK!/h78@rDB/ukC8\#/R["tYKHNrKq3]h].&L&H)O0!dZ*4LodX^pIGI&7)tcG9d-D?lpd1$NJgbJ_8W2^ZJ1K:8$!GB`A\M\b\<%S\XE-$^'j!u+3,RH*;Wc)R^(AVqM&O.I.r"!r@dt`qWD7<6dh)=*f5%L0o`Ob2-Z@3ec='Qb?@?p9qOd$JlH$DLM^(,6i'6mlqH"AN3lNBSa(Ee`um\/Pb$g*a;CI`>kl<--bjr7[`9")rXLpGL\WN(br`hA"Ts[REnNhe/FreHNW6@"WfoHJRNe9E*XS6PmQLAmJ3"C#YrP//X8,L'Rpq$F]+)g0)pACO1FRK)L@J\9rDA4nI4/2-%Za"a@Z-UnNIj.D+U\O_TE-Id[aO&f:mr#ms_4JsZNR&J%r.3bW2MZ:1]#E^t=aeEu0P+^NIOIPLOqWG6=)Z_CLTfggNPj'Orm&>oou`2L^Pdn&seU1mIu#N1j#D#]O7[*\V$`3PW?"B>6(,Cs=!E(\:CiM>dKuR[2>0:13&QrZm:%(ZpQ4D.--ljFdNnqA]r*8=:UUJ21dF<_'CQ"lY=Ht6=A#o1)R%";DD33_YDq]Z6Q%5,K_2u)sPbE:6#_Gki,8s.'h*`1U0;0+7EXZl:m]/N[4K(#%3M-kMlDBgV8cpjl,Q]/oeK@(JnQK:h\eLEU/U_\/U6YP)+a,BdM*/Sd0q^#$i)!0KqLPHuakQEA%aYJ>[A,a4Gt,T^_+u)\]*KCXtkBL>YRoQTB,8T,t+n(l,>DoCh/")rSPK1G_/<_h"s6n]XmNe(f?+m(aX3="OY,H-F,(HnN=;&NCq/aVIi#8.R"6jLSXF5WYSj+hlBT7WWTXTF;:cds[.U"bmEs7>sYFfT?gYbRm?s,>ORMa,Hd64XoN4"3?KjMO[Nk2IY:UUkYfF>6[e/3LURq_)SDR6Z#UT;ZI`4"lSL!blJ@b"G@8;/4$2>;cOlp8(&$_j0Ad0!+'UL.7sa0S'@Mn*[I]FdK`l\P+:eRZ#nMd\In1`IQbfkR1SKSrIO9k5^#EZ0-VPiq:PjBViVGC7.u"="2c!Ug^Ji,Z4KPk17n=>Hj*it5/J0)(571"nke_,FU4mmVXb7.!qM9mY@mLcmi8L8OL]A4GtMKnoT&_^jV'/WX1UO?-ii*5o/@s4KV\3.;5kH;d4L@YEHa^OquesFU^Br?\g[s0nuR'WL"Yc^0\f8KSPB/^8h`pCL]F,_,V@.D(4Ecjt%4;6:F$rE)NLR;,bQ\JZ<[p^+(YSE3Qc&g[pc]sOTBkBED)qWkr!luHJ![4IfO4Z=6m:>Jd16"(Hs#`(S%[q+8(-\c^S+t,=PN`56uPiVU^Br,0[IA/^5driZ)o_6CB47K5_B0C;L't[;5B]6bqEG\eei>*W'U7_!R>VDVS,`mnnhUlpU&u'MP72"1kmKZ(fKkk%:#aKYNsM@&Y=u'M[Lpt8c"HR]sT>;\!Ea3\B9p:2QA^dg(H:k$p]@`4l6!9MeQ%Coo\KpfCV1:H,(U=mJ24<.]5:p!fF_f7jEP1bsq-C$,Uh"g_XZg.X%lYVG'F/Qnf2(hJP^ZGn;f'8@5o1jP]e7IsT'o%%d)Vh]rV(&WuD;TOrO3ika]QI1pCTOhS38Ud^;BR'=m-m/",ZnBQ[mZupMbj5gY/d!n85kLYOqqcki:!VqOSg(lTj6l7U%mlX.n9u"JiJ@W(8a&=p]%iH?*#ir8Nj$rjWspp"(^obU2].3Cb!Z_/P-GiHM\"QHh6W>$*M@hFm/SF@CV2Z\'k_V*W61n`X0.V__(>u@2bp,?26`0da<(*38D@d[LdWCT1LWl-/%3Y#%K`X+&,*F@T/'(!Pb(U@%KKn,_S"53RO^aF?O>(17UOeW4NS"nQSq_Ko"IM!L2^?l#ZV:ZC@baK5$/Q.^J[kBFiS^;ofg-Z,nj13Hj;Ef-&I@Ue4BlbgVk2_a*hI!I/>SEPnO]'.Ek:m(Gd(&/h:+r\Ue*JUsnN)[=5(NBHlrMl&6okc9lT9EP%K0nKBEn:dplXc&o\XV-0NHpaI=L"qa5?"?(jX'nBg"imHs.Zj:U%Q4*h`-BG&%a7+/5I3McDsSp9$Oqo6Akd3#G3!g!N4/l4GTu'u->^?4pK&./Lk"5^GNA+>%)7r$#_:5GEl[dad.QRQp\CN7\;o`Lf%_Q;qlV:BnVaEKGKW7_Qn;$CHg4%Qs'S!Y02"]%frij&&/9F^Z"Z(f(kii4_\7jWE_fGpjmnF:S%bAQ2&4nl'T?!+@:(d",hPmd/K;e,`iPW^\&GH%(fKKNeTKqoa=U%.3":iXHbe]:D01Ok/Tn(SWV%N4`^pA!M4_ID+Pq3P[OFaFVEA0Cpe?q5JFOr,\0K!8E]&2Ui64^^'r?7rT(EE&t_AQF:SPIWa\?WKdQ%C^3G:9c6jInef:W`J4+1b_SracF4MH:tb3:rKp4@rq?OWP5;fo[`6'^=tNQ8),e=A[FOd+M/begR?0_'qTKbcAd@M3B?]6&l\>AKE`=0_"PgUhIHcrdEFsn&q^(2qF%6\mD(b813P;8CO,]Sprb2]REYML'+q\ffD?BS[oEM([mfL@O.Zk?m2eoXU?8[b<m"m4O?N2`=T9);#r0T^31nPe_=^S'j6r9dn[Br4p_A&ZpsuR&r%Bo(#Fh>^0*a:5e(M>E7Q);"UoV'=,n&isR@5gQ6bTVrV2'297!(JFS%4Tdn0R8AniopTd"1=Fo.m$r.%QGBrG!M"fFL/!i&kKpLM*bQbW_/lo3_:c=7*@a[sR-&'shP;hFBiN+g>@O7JSV2bT.58p3WEH*O6^H\9cG)]%:V7DJO2"j+sV+-H$/dKSo,f?Z9Unn-bj[!dMe@1bpGM`Vp([r]K7%_dDdqW93Y82tEsu.Y=m!LTJke?EOH9YN:%B<]',VQH@)jDI&NPrt**_;I?mUR)Ulne,h^:J`*B::Zj#?*\N!ZZ&_-tTVNd-^=#7LT8)O`rar,hPEo0g`nTennG&Dh>QafM6AF7^PPN_)d?Rd+O^\2-,uekXs@>3_163RM)\GhD!tN$fM\M(iu<+Vu2]`s/K>h*!gm&PP!H.McQhA7>jB@PUUcjCn_O8pT?>=Z7c,^%FgjlON6S-90?j,"Xn\Z9,tL)gTjM*naXn9n^MA\\E;TP#u[mptXK#cOH'X"*S9:P)tXnA-c]O`8OSbT022>@Q?4um+&@p9rLuE-uii>Qq`ApX>:aub-Td+&Z4_$?DHdM6>oE6(YHQ2*hBY18"-b?;#?,)V#1TSIE+5MZ'/:%U#k#4oUm3GImCJ=lI:LZ3`[9WXb$%&cpN'L;l@u[kFfe5J0ntj#9o$/>,4]0jD?$'E"MS\*P;Eg2@EC&LZ"<'MY-uMrKLZNhtN1oRru)U<#uM1X%nVh.;/u=9;L*EeC_lnc[WK4mJF;QK:k$W(M;*7"d0(dOJ.W?E@Q_)HCEcC"6pFk6XLHF>Qm>&-O#)Z%#:!!`T_R=IZ9\E2oi=jfqQQd&["V^^fV)\P'PP#r.3XCdqiQ%2p>kFrBcGCJ`UZP6N']?/5dZ4HJ!`Y=7KYs\-(&KEB5oaZTHE(hi;-a(ji?+Ho!%^BQ_U0E5$W2*#Fd;$0K(6t+Mc.s=3^B*q>IR,)$eeXiBJID`%[")8d6Mm^3i-FgtX6.`X5MA@-Iq32;/J?@Df"oCs6o,AMe,p0d-Z#X!#K70WLTt**ilKX,2\/UV,OO9RJfp7RcMf@Y#"eQqD1Db;14g9nH=S+iY!6dNbJoBs^#jLq)[)gd2Id*#rVLbedkH[UqNY]GFZHblnB$$rceK=9/Peh2%K2H#/q84d5UepG4.3e^(d\r/\a$LM,I*cpP!@ID6iTB2=qJhA`)+Z?e<65h=/H]9U&8@&-5'Nn[^2X^]p;+V@QmhgaW+:NZ%Gm;%S(\Al?uh@3MmTNgY&0HD#VV`$e$t>[c*^pV@S'B*V4`n"TK1I*)>o-tb_'<>Gl23"ErS-k3R4Yl^;m77HtGn:ZFXYGe(+g/2E=JL&5n?m58q"#D4f:$a&21i+)X;Xfc)GD9^TA:X\b,m-J%s0:#f/?i6J0FXlGbU@ZY5)TV5NMV<%DC_b)=M#[;c^h/-Iu26Kq-tNWNh$@EdjbaH41O$f$O)"/"QI*Z_V_62e_hnb*59*QhWZcUUc<;n(8=0Sda4q4c"5&b8a)Pn4oD3?J8@o%a@*f9Yg)PUU-cG.tG?1G'bMCmSnD-/)4ZX%4fFDWrD%&qBLLL9^At`'?i7Q$^rl@sGDkI.cl84J33+cNj_#j]*0hdUVH$d3ap5YO48g`/>X@%J/om@_EBm.MoQsND0pQ,Y)XnF^HBFXkAF*djlcbn*oL$C4UouO_%.YI!3J*$Bj*.AnOLHJ^,<]&opL#MsYaSZ]K"]0a#pMf3tk6ScQ(^XOo\VH0n1^"D?]X1A*T@mpP',1p1IAfIqN&SXkl\:kk>CIclBFDWmG,X-hiK$'UE8"NHC>cjZTZ+T&WkF^CL5BW*FPi.7OR9TIs?a!%U%-Ip3XP_!td]49nhmXLk8*I3?Z[^;@!IPb:7&t+B:Ak$;jm4;\CtYJ!B$;sqb^Xg&F9\Nc]=;FD.p!5G98G/QiVJ#\Zg@/STp_P8BPk"LUN"*G5Nas`=3(%pU%pGO66YuMO6t1!E,nm,?QVZZnK[dj=cr67P)!Fl#^put+!h@"+cV2K6_Oc_0We.peWi09_7qOVqJu.5^iH"P6/l1+2_i.)8$DXGR@1f/SY!n"kM/A5G49!05k>(sf-c1Un:llCH&2:?bKrNCPWDDS4.u_-@RtbK0A1_0#pe:t,gb&tjVo%f?p6R8EB)43%;9N.rcGjF1ibBM*illS0ZBkA:"#nC<6!NHX"YcUg^L0=INW'8Vr2"@KL#m,9H.MY>#?#,(iBrb4dub/!mL,qK%SO8Z'd;mc#K&W![0PaeshcDUFr2dp,/(lZA*BF"`CG/uh,(s?Js6`+!("uIT-ZreFAMlYRLaQ'pH3#NKH)8t*a\5H2*32<8gWZ<81kpPD+;jH$(5'(]Gl59\!Q0UL1_F6Rl._i_I^>t0*HXeuP46Z^V[^uM7"=%pLRS5ggA9\#FD;kGV[*e>h'D1W]@]'Y\"NY==>\XqM,flPs,WNAhkks<9H,:raWj!BUXn*h*OlpAl%-R/dI69?L;.l>.?1(OR[5i08'2nmT-kVVPK^lAEm;fgPo-Juk4*"%Q2(8-G11IVaIN\R"9t3?Rq%I$l8/45C".S*\;<'0TcoZdt0[OH/+X:heDS@'m^W4f;nUK>4QCo0*o1>6sVAl>Pac.i&nae=4.Rg(,^dRaFVHgr.-T#$G_7Rt[_f57cZK+LBKQhHYkW9e=Y5DQk=a*]f+CH>-8BD89FXm`Y"5>J1J2Ds&hXK(jR=!uD1B,lkD3:\:hV[]k4+7&dS&.a[&%)`Ke'HgT[@>]gT@uUeYEb@CV)&Gj$V6dZL?+`6p]9pK#*7nNm-Wb#RU)rd1TKD52pP8t5;c"!!6a:JX^L1R*I3'hl[L7),CKP&j[]!FkeCHOH]b"7K`#0#tFN+B#RaW)=NA.ABj;%X.a(pl;=NILWgu`n=RBHi_dNZgpr!kELCE@ZnMlWDO2f]8P/=)tUqj`Qb(L0Ru;Q_IGdmnQAH#!!&U^OeZCsQn(csbq-OrEf:kG"B8`DaBmN)?DKs*r4b`KkF;2-"aZNXJL3L@cD7uemISu57s2gdHW[-dM"s2VJ83,&WBBl4bf.MKDQiJN87DX;:srk!LBoU\puN.cZ9;\b$HCK_a#ml,o=TCB'0iAUngYItW7=3SRR"T`&K#Y>g7RtHRI_t54r,(\1([j])&^&6Z(X9-R=QP-;g9AXVXn(CI>[fn/V'WU?lpZ!2;6V<`\ouE1((SP_Z/cjf?U:P^a('.L[FoW4AZNI>ElCToGIahM<6WpV=okJ73A(oVX?;%OkU-9(hns9+P35/7t91mCs:N_N7[(l=2bd(/GM%DO6cXukJU@2pm8)7)]+l1%A^jq+f1ar#PlUm+>G@bJk^CtLh7g+CPf"T"q<"#M(Y]a0G/S057sZ_l!)aEG?/[M3"!6Hk2Vm=<(%9c6t\Cum%'0mAk=/ZRt%%SdJG@3BbA5`\e5K99`'d\1&`>IB'&g%KG4NrFG^.g7d7KOM*A'HROKh"LM\W!k#*ED%\c3Z`"-kY3-t0+^c7"?p253ZT7Xn/bY[*Y('e]gk$Yh@AkDUV^4GKF1%41H!G?NE&.f[S?KZ)R^RMn(V)7sZ1qD*agm%3urf_MgPi5N,QIKUD8'I>=';[D1h38tBJ!]L#k666tkMi@DrfI`cA.R,u%4N%g0ChAB7[B-,#Us=1,md\*!Wipi,c2=`J$d!b#sU<](d693;#j0Y#Nlk1]s!iN<$.'$5Ko\R^R+cZ+G3YS67[It>1U(oeqBEH09cNgL3"1/7`-5L6'F1L?WKjg`Kha)^d&C\!P>T,b(.;^*_!u/cso>9]=nj$R;3ftG)PO7e"+M/=?*r!/eN&72jaFA9F:fnLAcdC%>Q!cO^0+[&lhcmk=T=gLce(N1Lsqb$O@2,<*%9NJ[@a/`V_R`npH):Cj5b("4e;A-W&qYD+Y`P;pH$Od.7R@&3G[D`P\God1-/`FAFl0_/1tF*jaWn6VD)=4aq8%GLY7a&r_PL0U\Y1co.h77X4h1WiV]$:MJq?'Q.f-(Z]iMHYuER0d)R:"Gm7I&<$]q.t^2$*ns%d(2g3IL.GVr9a<`p/Fr"DItTIh`74":PK2E"f//Ed1^PC[c:jZ6G)$I17i9<2Pm-VhNG'd-+3SF@#(P5Wck+G+OD)P^"`Q]`Doo>#*[SfE2,NHIMLo,5(ulZ9IU%&-h,YTbT*0/j(A\q&e_JpiuZ!_^_A:5?lJ%)L:S,a2$/X%%Jpd^"iq\D235%!-&8juM:ID-B)Wb_Zqc1p"9W!7cmZ#Il3#`Iaq"C]OA0-U%N^Wk4QgoSmS;^NnklD2)c'kkqdJ":^t*QRdL7Lq.#/qhU!u"]#$"7thMk0fKOP*N2&7i4ZfHNe'lDJWW?fUK%k6Qca"``V1hkE48G38NUVK##+m2GHnE*_)6s,'V7>`S$BP.#6h^g?#<#u(sR'\/.Sp7G_YI@fsll6MJiI59UcS7YFS#%tuHI\d(luqb>Jq6FNE%+T(K*ZlGk7:.Ea?sB0$fQZC/ksM%I1ff$\'m\cTcMr]]088u9addc,R*a"u,i.[kTLgZajRjW;&[7YVk2K,$;`h_6^HEkf]p7&5g+[%Ue?GnmAULJ=4KWlmt>duc7,H)*FT70_\QlN"V<60k4H%TFW#;@>Q2%dYEHM;:pIfU3"D:RjKUqNN#AR",gBcVSQmqB&ST@Lt2R[B/iZ\t<1%E`V-?as4bh9t!"u`sDiA(G\u*9U+\7CRq>>bEXW)=!Lb:CGC(NV9e,g6MNBjE7U?mM[efFgi%F:*M=d%ju&72U$n0k%%&E(ACM'^+f*K?@lQS%C53#maIqJOD93IKXS7#kK+e6HkhcHdSr"c]rS$N%[F)HmZ79.Rp/L$OV_sGA4Cgtj_#'=\E4EM[>3#cR`80IVPK4*)*1;"uQcc:&Mg#j^E1aL,8HNSfFE"g$3#Z!aq=Qe`1%SD$W7KX7aPD0pEbsms.^eL1%*e+jk_')76<5trFJWh8B+:Fj+FCaZ?NaQ7((2=;h;6F>&"W<'5*2t2:Q6[E*&-j:D]_LVCR]A(:iZ4YUHa)q+#(STGCkfMD3g%)>GKT9o0BaFJ[]hhO<;TFKY?UUqM@eI0+D4A2CH3_s(sjS09bToe;u79iLjSY0[B2aA`7Wk"HKj6S+ZqI5rD^rp/k&fnE[5K5ZPdV*)kA3SDn`-[c]6#.)ipe=_A\)fQs!rbSQ']RCGNV6TCbHa$7%H<@Mb[3I]H/5>I?*c"g7/bIMJ02,M?KX*Q@@tIOirTF@Kg/H5cf,J7cqHWYCZN\,Uc?8*"sT3p>?$5+*>BJV#[3@RiOBi@)_N_d$H-&p):>3Z#k3_e8f&(=@k:Lg"8mFT'g^J8\dm6gN3*6"8LJeN!D,NZ'i9c\1(^`uIetN!J;fouJ9rj`.marjF<:4(i&1p>VC!^K5'VG!bSP]dM4h[[EbI,uGRmd=TYAJh6FWKh0X6H;3r?^?i5P"IIO:4Dm2GJsa%8pcFJQ'j$r)ES.N&a:$rh2"4K9O[(=@SX[*B+!;FrO,,SQ"f;I5m!ee?39Orr3sCsVX#)Z9Tmb_K[tTda7Z,Y=c"!.'kmN%`\,M"iHl>_17K+Zci<__5^VV0*8#Yc#/4QQ$laf^FHPng:%f@22Z,Ya!WV8:+)6GkmkGQq3D'<)WA3U418kN1L9AXqgH'Di&G5=Agp9p!ZJCPDG#>PlM_!0h#W76)Nn#B6Yt#!7G7_(#m*8#f552e)Zgs.c>J4&KpfSckm60e0CdCId@s*5g!VBK!f@@jle$C.")`pi#,/8@YN.l`%GT&;Ac$"7cZ0EP;F>ehNng@P=T9Mo;&0J&eqQE:\oqG!-SuXKOdHPOQ&VJ`''0&D)W-ak;/q4asQEGc2mF%BWt26a5%F!BnDUp+0k_#^IbK5p4*2C!=;d7p?gq=e?Kh?Kt3a#6jaLA6qdfN6P+?_(^[#*qET8r+p3b`ajkQidt$.hP'A!MKj#.7>RPTgYO\-;]5UPUN5W5bM/267*s,7Y%Ff#bY^a&L]iB!',iH"s>#;ZfXM:-U3GOj8qB(RP^Z<.`laKmdcC]m#VRnd?5GF!uQdP51B[jPRRuV^@Hmg]jo#4Ybb7]Ut5dHKrj"P6k\u#.d.nuE%*h7mU51t!Y2`^R!;CKY>BCmm0CDb(X'78VD#EF5c-Dl7'qDf9IW:_$d<1Y4];X\nlPaNQ&&.LKE#"KiE#2"Hj+*5E,%$2bp)1O9fN]I592VDch$6nH_m"-,4J.YLV%iKFLM7H+r;A=l4.KcoUTOT>L(q*bl%jm@ph_t9SKK*R?#53n(p1OoT&L^mY$W;Ioi#%G+[Ae%-40g64%2*s\a$;\@4JT-1WQl#RLs)pW!k$qd.3hRUT>9l_@X^EI.@"lF)*qRSZO6Mk5XH5,XjeM]T0QK]XIbg+HP%6CE#U:"&22oJFBikae*/*Q^jqH^++XIg^M?)RT,#H]C5iMe+b3OWPP,@fMDhj2JZV$IV1^Hn_aXa&/;5$O4L'U*lOqe7QM(+m.8f7Vn+:2!b.$QuM#sf")i-H)#O:_PY.ah/C.[7&8#k?PS5^]B\9gLIRJ*'khnc+B%#RH=F%O!P#St-c5Z%T=-1[ZO\8^99Bei!ftJH*/&q:-:7%Jud\^*^(5m>LLSWD:5C[A+Lr9"6"[H+e3@QW?Af"P9I>+HaS]=gbmUkAP488(&Z^Z2KYcW&$ZL\1M,+`h,c!^s8/;VP%K-JBV0aO?XrA#opTTK3X!C27TWBa;.!rj>aae]aDoa29X7"^N@>]s+)\eGJa'q$jTs*eEVA20MlA[E:6&\J2_LU(^K82*Vb&,?8&^8$=NGtOr#T6-f@4A^CM]n]("k3=>=FLuKTKiF\N?a!S(9GF'!k)icBB^Gj$erXi%NrmZ>3!B-(L[k/X9o^-;iYKV9%`W..:^4)H$V8+>I>$dcO\;?s'hl8fM(;j6OBA%FQ=Y]jEfOEha/69[8`1f6BQN=f0QBTA^^oX,^hrn?AHTPP[hr;W[ktI0*[&5?V1Jb"YC5)>rqV.42O3HiT`B;+0Dt**CCX"QtB[,#LdE5[eRF;$e8ia5f+6h)!#-OEYnF;f!CBIH'MsBHdOF@+hiebh:j+#IH.k-aans7Ih&,W7a[i6b.PRBkpB[Bf)bV.B[Td;>-oa'8-/**>>tm"EE_AqE]iYQ4,a?Aae3sAl.hJD)c@7eVrF=I1mK2;bI&8q[\T3GO_K8!s$%EclS=jnY>/4V<>Y-&Op_V5*#>e^o]L(/S>uN>Gj);\ZccA9N5?'k#L=R@tNALil&ZlPA'2^J:VKAbd_>`?fs$<1"d!XW%s"o7n$#";AiZMWhj6JdMY,qcGdT8MAau$?8boFio.5[mq[au;W)5#mbEB7HGPbC>L;XfN9OUt&)f\T&R%ZkLC#J*D8L=cLSEQ_Mc%u^V%RKn-]0_H9TofiR%NLT,G!&]_3Qiua)'jSI&q3q%C'#Eir=`0Ahn>G2//W.j#:o'\',DIl?7$RCkZ[=ei7(Hb>f<\4=enW=dHG/^0b9!0(GYfVPm)n_-p_1SNg1aP]-;j"pQ88\`Ol+p461G_V[NWSZ[iDE1(<.c+hX+?8dej[l)gt6\SgMQH4^#B*GH!?,V4-d_XJ7'tL*'ZJ?eJYpqg3I2d`YQR.2PPM_Nm7>"M+r*C2.mCG[n;d75"]RtaiZc:iQb@.V%ufTGUCCatM*4cp@.254n"HLg>5nCugM]Rl4dI7#0GW)@$c4CG[LV&M-3q6\R6)BK6:4:;OT/80+Mgb"u(o0Pjq4ZRu&/O4[mmL@5SEc/8U,V.'lO$],U6&J#B>otdOTgn8:5=q7)%qn^2JBEJ2&+_.q7RgjD5.cXC"1%!s5J7q@;6'i^IPR\Bejl?=s-&'AlC/KSA5uVpg/hT7XQS4K18L8nn7LNAD",p.p;^-B4E!jFu/LbRJR:BZ'OE%EA"mf(J2+o)\Ke&o@U]nhPh<>>SESs+Nf5cu2Q/@MbW',%4.MhSCkA8!D/q0S=8]2AumHHAc(H3]1$@j+6/S1)L)Q^nTN@pDcBUD=FK,,g<'TRqV&j_=`b%r:XbC-@P"[%J-/2K^]tU;"/8p;dKEF'PFdCm_>ONR:_%UYm=k%_g8C-&?td>a70;Qo@s$bFQBHUW:jhR-W+RX1&H2U60soTE1!\D0UtWQ#4U;a_=ecF[?HjB18r(P'$;r#QObk9UhbQ&%R@GU@CW@Im\6P&j"][mS29b#610/3iq[I6'Z/ZePCHk,D,ak-XaB=f:L_F_5/2??+V1U,NN$4.:"U(dF?o^_8(ME1fZHWR^-aCb!@n#/@'F`OXQR;eMZlm:aP78'?+BG-QV^*Ud(3AP^,T?Q@\d!s7B;6*0';Y*CVI^e!!,YFUAnJsnW*(g9s0;!N;sf^74tA0kp8mgpQpA2&CO%q.*7p@mN!P-?(!a>@Q`[,*SW9e.7?9RP^"5Kcg-"3:^`$m>4uV>:kGE-qD;g#"q)#uW:oT+&2):p8jhO*jS+0r1lL)plFXAXM8g]:Jf_M7T)\KYdC\MJ-nOj,R"OY3jU5%pRu)^"i`DJd@ubr+X9eIq"AR^*pg+t$&i?X]#DT=bh<)UFI^-nicZJt-:$Nt-5m/QL?,F-9i=B="US.*W5(Et5j!nhf$[+l0?EOt94FU](T]S*,/%li!,+;c#?3TmH+]K1I6D]q60(&ifV(+FG'<@`NerXL&e)EULc:u:29a$E&Wn>/+Z'CrV$X$Y*"gUW-Xo>IcW+?44.;9H?qfQD*BWa1X&$h-9mci0qTS&5"I_-["Es/$knRc64*[.M4(a$TrLi(1dU:N+!E5bIYlMZE4S#AHq3;I*phc1Osub*@-!&R(Vo&O?/@:;'FlN&Td,4".Y?h3V(L/K$8NQZaV8bE;-9Ic1Y2]'NKPI@meF!'H8>l7P<@OG;2rMN^lX;,m#HeT#7c'DZ;"DI\ki)B!NDp+Mujk>.])O2KgQd0`9N*Z6b=I!tU>eb-&#[)'C"LX$o^G3Qo"4u%jTss\,@R-.k*-T45l7iu=7q3>^.s*`a&lEp8%T,.@ET\g%l+=aL=OE%`?BR&nX>(FA1i'(%V$PhsM:%dAh(0!=hi5o&VjD$_G'*NWEasbuZJF0PKAOX&A^5+&7Kp*P2G+SN9O0MZ.j9-.cbgoaqu--#gA'gmc>c;ZdM6[lrB\Ce0'C.'35=AMgt4PNaW`e`!YQ1r$o-3YN8^'?#l0!.C\Vjnp>NZ(3l_h.E5*$$Q>kgA#(r`!Qsp)&+;(?9M_;l?F>nq&1OVopglP]@(rA:)ofbor,IW5oO0838mp^\16Ptj,\C8c,K>1!]^5\KC=B?O3WZ1acJVnpD5am4J^(b!9T[\dl*&\N]rbY`?b,k/&Igq+]-O_j348]Z*PL3/m<:J#"XD'%BV5@MkE"mYQ8=4(eS]]"&pOgDfBFB.F^;=B7%]a[9X&o@jk;^agR-\3ue",GtU;#]-YgC_M(+lH?'OX,?bJX6pQA8XHGd,l6VVc*>pr$Eu9bY4?LM'P'81)LJM$/CW2:")t75]5pL%1j03G*W]EL+l7t1*&^XXB&k^M)8TBLBGMG"4H]'_#jlDHk2ld5W9P6B'g/`*LEtT4au:ag.lC#G]4!$;?mW5E1'+Tu:Z,Ae'nTBfnJ$-24`V0N1Apcfsa%41sUI7KdBD@kR]jnU62E=>MJbE!3$\MfnsqpVA5\R*#];M"A/q2MSP*DZEjiPHVjmN6at?bhlFFWd,LU`;`hVgh1&A^aU[/kXQV,=ioJ0M"meZu]t7@oX(7&<[8@$r][_LCs`50G@:%9!Jdt7&1Gl<)<]l1ITZu'grd]7\TsAC1;^M6&t;mEM/#'Rb"Gd$_a.KZ(c9&\jm;cY'K(e9;au_@TV$mh6fAk)`;6p_Yl48>ThH0\-]0N47ZqJ0]CpQ^u!=HeF&OuM4=+e74"HLT^s7W,a<@%6Vp16MK0%fs22n=fg?6E]A9mJ3j)Cf?[T3-r:kZG;N]R;NbLrhbrHM?AJIA;fL0\538Ui.(umlLQ+aN0WKM>Xc?F7@-tK6`o-R$$'QQ=.Q5HU^A#in;)N[7b']@CZefERH?D\F)X"/]\7u2ei\nUj@-mBps&hg7T8p@g")hER$";jG_$0);a*R.$m_8db3K;@fXSg4-`QP:aoJ&kidr17NoBZ;'BhT?O$r+L]iWHKrHuogZc?&0e2qXO:3(;=g`bA+AFimp+bZG.b*qN-?b[nJN:dQ(QaLhJ__fKITqnk-gbY2C&JlXj)F8>3k7g?.K+78N3%]Ao\4YARNahb`%>]a&)3V&FJEAO%1(Qq(+gkupMIZ+t5sd*LYR26;^ST?b&<[;'!',"tb@&hg801qP'4)9(,X_aFR5\Nu2'q)_5D>WE"P8/>,)cO2ae8X[W8<0u2oo_RT/831nRqY.;Mh2h??^#PIW_j[ac7)aKRlM4+=RJ.),?eT0gntbZ,MTScJ8gZ8VSEsC\\Z?oc6"%?VBc:K7WVmGA?oG2"%I>3>1l`NkB';q5#rTsVYDF"bMP_j9^8JHlH"@,?g?LZ=daj,D`uB^0OLmmbAb>.'Hj4W8X5H=)QlILMj(I"O-4_DA3-nXPoCEI+q%4'>g.5bda'L'ekuf"L;d]=Q5\c4UGW0$+cjc/C^("3oqRKZIKs,(c9?9-/cu=]N88[GaauQ7ZW:9:B;HJc2Ecl*b0h]!5TuE+&8cTBXqr%j3l&o.;(AS4a^OpibaBG<3B/[L0gMOJ\JcbD$.MSc$$PE^$3A6FslfE\@!XtFe0kYe.obB:LNVBN)raCU,R9p"-HSPp5SM[d+s7Kp+L;&KkOG>_17WQ,aN3Gr\VSAhblfOUp1Om-*A=dK]-X[JEkK5U@'T^8SrDq#hD]GO45e(cF<_sg0gdD@MSGRNCh2'(+`[j#nWi6[JWW-mrN28Mff+Y5O(M)6u2fPbR_.`c-%&JJ(gW$9W2qA4]gZ?&2-B#=cWZfM=?Eh[rfJfsU3)]?cUpgH9hPJBaDGGB_KeOD0oF?,FYCIp2bQ;IZ/o?+L5jS&u_DM[S7_d%$NEs`Fptr:*9&t8q"]h^7+A$adKJs?+ZjPS,k\n*-ZSNuXJF/J(F8YuAobt_K5?/3[@A*nYbD)2%8,b^*pXTSEWP+Sh/'bK)&@o[`T*^c=F7rIj^bZU2O*N#&GUg!##4&S]h4j7q[eXGS(eg./[0shjO\sWbt#3!0l,=O$HQ`rNVQiLLe$36bM<=(:OV,,90KDT"s,%J/R9G[%HUP"M'F/T]f1%-mR2&;2Uf*TlsOeuiKjM$bLX.J,fA%2X"4mVKe:qki7]c*A`0+JM@/2$u=EnVapP3M(+'N^TG-\RIc0hK.9[X#ZQq-uLRJhM[M`ZRSj%Y136JWlUi3WK("`<#'bOFdS,ZHuXj"l,4=0d^dOM[eQ.U7]<:+,(rq$-r;s1k"<1R@#>Ys=/kYJ@c]GkU1$VL+B35aR[J0Q*!s#^A5"j)pDK]"cp7i)5l6\"4e&Hai7bCO"8.(j>Sd'mbiiq%kF*om8Au3tE?ru,*"\8XM+1I=DQ6Q1aM&7dL0JgUM7k]EWL(QIY8aS1K$ol+L6NuPAV0t[RM608NBK9XL_MX3",^kUl=a;[18dk-%gb]Fj]TeGB'=3,fI.5@W)+J8"UTg;\?l[O*`QuEdiY9h5ZQ$&a?qp7;jLH?f.`)-\+d?Kk>W2&XiDm""1)E-Jbd1J7;8Or6S&PJ)hUGmF+ZLc%>&BKL=.7M=0_?=ls$%ZN47)]mG;:W[00Xr]T7];bKDkn>p(Rg:C3">Q,QWX'CGmT=Y+l(`k)2q\J5`[q(Ri6.o`WT3hb!TVcNqku\MgF]l$\a1])/,C6iZ91&Ta$OJTh9FJE0Sn=VE'QiEYo#I6)L'kK**4%dJ(n6t<,LguMt=S.3E.oPc+/U,p61IihNo<=H3R.6C8u)%EECXuPW-"I/24"I72MD=U&DYEal!`]k\L0Z(.%1G2'4@qopme$4%J9n7=hc"%IC]I5G,Mq`7"n)4Z:A>S?RZhZ!Z_X?89b(7go72p<9u:m6SkpRerUL3Ps&L,:QkJP3sm4C_=1^&W5o.k*CjZ9+*$[6oH&I=*[m,&:g+LX5TaAqed&of1hi)K<<,mL9RLXHS/m;6m"XH#E)RROE<;S/c(O!^l.^_/oRBts!si'S*#f/-bnA8[*.>/#0,[),c1P)#qX]PEhakM0o8Z8F#g@l/AHE8]0kWnn2iL-mS4Md>ggOJQW+bsFj*C@mPLfU9@\#p"2]ki'imDJK!^#i4glbL.riNnM\%Bq0+jZO!rB6PsRR4gKZWnC*H,LTdoM"c`!@g"A:TEc^g>'pbagGMj&icUcoWKi;kX:6]=,nm2MGF44g0M7TsO*O(csC,UguUC#^M"h-XEo;L`hJb&+7GFoJ1`"_-T?\"nRB!Rjir@!lh+.fBks$5_JaHAk%p#.nb[lD1Io"T@eFZ+l24&qXY9op\CXBU3EQXrb@lrOjpg'/Z[a8JSkc9G_e[HMEX3,O/MKTO;Kc#5Z7<;dua1F4@e)eaHC)2+JB)1A!,j0#MM6lrjDHIIGoi1E_XqG-76MtYXYJJAh-LU'Qs/9%YMIIS^O%_:pC=q,='@*%-:%bCt6(l9XIW"/nu'Ai2.]X&:ie!h&#FYL#K_:*FGReLS3?XR5Jd`Tm@utM:">big3m#YeMi:MLkc)t3L9Z`C[;(^&:Bc",b5ZO<%ZqTs7hSLbj!G,/!OAAd)JV&@0^m'u&u\b`.5,F29V-ZiSQW\7rV#&+"#A!?]*HKp9i;3']l^UtTgHYndR*uKG-KAN*EORtVl'C0/%06gt>)JMd-rE!Bn5t#0^*_qdY`aNS=6"1,<8l[CLQpATs0\s8!'(&O2nqdS]]r)"+p*?\9J62(F#6KQ+!T-]TfMO:06.Zp$gQK6f[37q:aF>,"E=s9P)p]0U82/=:o-NFTjPi-N9j,mI7'5mWdI-g+6Xk6TEp&T!#eoogL^Tu-=QmXBa06H4I&mO*@h#-,&0i>IYTDr-UYmnZWKNs3T);#7fPr(p)PrYk4(ksH(Cp9odUhB$8Wnkt,+kJM`jK<9KLqlSt?e)uC)0(6f'm-.jbd=p7+pC_f%8=Y)3\`W65=!Ld,,E^gP&V9&kgQIC`aXKtPm)P/ijhM/bEg<-1Q0&dX.GU3X:>fc"q2G+=cF]8$4)4j/se/I2OO)V)]F;"OJ:,BDcfA@6Kpq7,r*_,$F:MiI9ErR;'sYgZ(-q`Y!u6?]GCUj]p<]%3s)6i_CiaD<_9J*;D?J^\OZ2oE])HSTatdMdF'DM+S%PhCY`C^PKEpU1kC;j`97\aiD6+?>W?a3fa3H#c#:^Ie'/onYGXCCU-[1[BH8p<_`l.Sd5VA>U$d+RC/[UL9?k869$qk&r6r2#/eAkYMAMN__+K4BjrJ857+U<+DIOBd9*#E='sA]+O9N;oP;,5ce5%epq*&0HUA,KVG-3?/f[QjK`rb+/Zf>&G"[5b10BrL=]V=g1HO:@aa>WM4.,QY/%&VP:8V:il'6'VTmnDn]=;I;8kRuT^\'WH]9s6ZSI2&#T8M/u_qLJ'dYMn=;Mg/e8An>[7%lSLkglWB0lT:aXhHo>GG?(fEc4J5JH>8V6"I/?02_8Rc.XNXSH-R!)S3G!sf:7.f0Zat-VqW4'3TGcb,mOs4d<:Jao3O\?P;8M$gYe-pGn61-"HYJJpT(_PLm."%/emVE(M#D3>G*1,#[rgSP;-X\_ZOG:`;C&iuT.USDPP[,b[(#9]P5FMW>OMHdp.M;u".B"Or:uj2<#1`dM#s:ca!"N[S#i-^:Jlq.g6'FR&]J'GX!bccl:?@8:4P>LCR4%cm'YCmh1%VBfY$5D?kVtm4Yps3-"i_=XZ_WIe6;W;IVF7s1n7\16HVpf'EIa3ERkk(1D2Vfbh!DLWc='J_'Ko+[C=jOf\bU&toT*Rui/<+7T1,#^8A%a`/U5$da<(*l32ghH$(8D:dCZ+5stNIZV((`K/m]lYSH#E=T]I38>OnP3@+Y"+hffPMnAaSku$""H[$G^cnAAcZEn2=sHtFLo?i-0+bqqT^N0>GClef+T>a$kVuYPoP=-ndBSo4rLb70;[FZ@:-sFZ!DOgQeHit15lgLU6FDO4Ulh*$+WA1VXFr/eoJd)^K;!g&1U'Zq6F;FJjIaL9=G@Ka;@Gc,I]tL&2!/e]2"56&C.:VS.oqF&/?1CNF#21bKSKX=JVMd`QNdJESYZ0+*o^p^a"p]o2'm>8oh,CqF4Pi)N^3&e0nT<"nSeocge+?86DGAO9Oe?sS-o?IR7)^.MC:>MTX'#gCG^_\ZqS;dHQ(nm',c6dTGZ&`+3q_i1GU-FqSV%dK_ZH,I!N'oZj'.EWeld)kGaV/#>`WS@]0>!+gF_\+9h@H06nWZmF`XBLe#TIMe(W!O0&J:FT]J]rSuO@r%)q(Esb=/6P"EW:/Eo!0^Zch:N!m(hr,*/pdR>gu8VGT@$kf05B^;S3TjQp'4JjcG)$6j16)@hr$(+F\QU"Hk5(#R5ut)GmqS_\,g5JaNP45`(D\cijM:.Gr?Hf;ENbn,QCP$rKiSO3"E%k`_1@(4gE,5g[pjaHGCOLkC@L:fOFqp(@AS+TsP+bUEZ\.5VUR.9+\KN"A[EZOKPqOJEL@!?dP`d[=0^*C@OQ$:KqH(IU)(n;nAs6ldR%%U_`qKhTjHW#j%K>_&B0Ti!!87?Ak%IP/.]E-!YP?-D>i0t[=q?u6"rL<8nJZnEg"Vf/>A(Dl'Q0:@QU[R1CZ"5;Xf(=%p+=GCG#d@.#Qp5g*nllp=$$,D9.CHM5eBuXFH6A\\J5"UB]%>4B@EC1UV;s?DK6e786)W-Zqk)J!7(h[e\:sHfNs+p5Jn@ZV]3+UmSuJZ^Gkn]\F\d8n)rVH/an6!<,/F_<<&EM8Eq"N$*eIO!D4^EBUW*0J[1,SkX"]M`gF;*o<>EAsGaSmXJ3G#DU5EVaQcNU:%g"mS_$&gQ:ZaUFT%c0Bmnn\PMM($r^)Bi&(lFoH93hF?VhuSsgVorLZSJIFH&37tgn<*G\l#JV.+LiQ![Nq.HnQJjt>KeHjZ&)kj-3&"(WCQ>en;8.0J$fk`i+d(;m`m[?/9CD&^D0n)lEnn4jm`hLe+^j70npEG$qR"c*4bQ\FT+"n-2bl+<1&kCG#OO9OH8Q7''9,a4Rn"bV:\8r24dY5B.E-=oshP+d/)KgC!se3gIkj,F,-(NW3UtYgOH*GEefM"AD*)C^,TXY9fqdQ,4E>F!u'>[iuM/0/0/o"%#/`$Y:UpObS94!KMG6oR5sc+Y*&ot-om+`.)Ru2+"^JHCll_u0oGXcAZ6]%+!.riR#&P%VG,'BA5$*eVV#?]n;#+G)F8W,"7#!sZ"4%Z6IVRS$,2p:C!)lqnf9O.Wr)I\5$\mIXmmgh;lU5"gE"2gXm>2[O(#e1Zpm_MfPM,>^*4faPh'H3oIN3CuT)S2_dh)]+TnNJhMbA:&8Q/E1%](atdC,KmAE5R9k*49THAqnE*6SClE'=H-Q?Cl>+igG\4H$Rld35':UJAGWl>@=T7fK$c-4a[IQ]aW,CO@9/mn/r%#n%)t$,$hsHMUW)oKn0m_[i[u#4cKZ@&J.AK3i7S);G"6M//t%Y6;q>[b"<^D*eO7195#0BQBt4CX:$RKeq7*8i@aWBW(Kgm-Sd^6)5F2$ce?55`&V9/VEU\7VibcJ"K/SJ%7oOa^'C%j+jL`-K%@.P,7^1hbWI?u+t7,sH$OH%LiXWqp'20H+<8ZiV1feS)AcKs4o%[o!^.P9q=#LRg&G8e%[pP%4rskD3d6dX86=[+l7p5G#GChR),e87f4VWl'PDSX]cA_W.pNF('F3oVTFMi#c+8*#!b*8YZNs2-@een.c>t>d_fAW'q/^>Tokd0!.ZOG/q\)+L3AQ,r:_6QjZF*l.]Kur5A-!=\X]9[*FS\C8H!-3h`rMX"Dqrt:b6prfi#Qij&/nWG&BDfLp+a/oL@'7s3XuORCg[CW/>-X&i>jUkdWO3W+\)7ia=SckiULIn9Vd8:C).8;"T.)^^PO\,VR6n(NU$3Gc-:^iUE#:*kMJbhAK7H,'0WF6%p]E5sI6DJ14AY?7WL)`!8Y%n!0MPLTQ!G!>pW=6j6"%^V;dCX6=c]X?@d0_XpHobqtM4_%P!-RTr+&'5,+uXP*I@d6Biai2!FC-6U9Q?SUQ`.SmNNMG3jV>@G7Yq^^^N5NSPo5&l^h[i=?qRBOn^caV#E4d\+iW-b%9,HOeM1*cFr4L]BW+JTo:I28N\d$e74!?PB)C4X.ZdKL"O5b7`$AH&'SBucJ8"3+K-9V)kWm$c1soj5d1#p;M@Ep7$*kQT)F]])/3PNne!7P^tqN(r:Rs5B>d]negQ5+0hL:_.!,0T-XBgDWLmhq$"a`JMqb!&j0bS1/@ZmKaO,eo]iaaqlNX?'-p@dl0lW1GkAGpob*]tGQGa!EcgeOKr"@LN"_P3`$/)/Im)A\ps+pagRlFT46F2+sqXD+72n:@gZs1]cq0NhO,hrN(I,'N.FPam\.BT8E]&=A1l#!>KmV+OJ_QnEk_+A$QB(Le_B?=GKR)jj/o8_@#8;,Ruh(Pq#@@G`n8U"f>:.5Xh]A;[TO^2oWuAUfn62#8=J/^$nT8)Q9=QAKniLB=WK?h\KPWTRF[!bkU+T<1'Bp3o7=!P`tdR"XhM%*b8&clH>nG/%Jql&%e5lW??]o^U.XYO)A)DLHGeD@Ui0?V(Qt<`Z9eW>F$eTJ8gV.!hOG496:!Aq5uii4)c[.Za=%E!UD`"60JX;HkZC`:%1>bGL?-/pD]Kt`JV>)be!CNL;plga6_^"u)c/gf#Ir_?6O0q:Oc>!KXu-dToc?e*g]uPT#?;*KkX:cXE`1]/"JlLC47(:Yjfbat?>j*JluT`21Gfe4`FoA4IArq7c@u^WGle4p0@)rRm7kdf&'B)Ac0MbRjaD!T:]5G;XR;Lk4&OMOmK5#G(a2bU!c]o*9e5`b@]6+FmW\M&(YE+8,/#TZ*N@f8ZY2DAZI'QiC?fo:q9$7UPA/09#Jqq3C&S\Mji/\W]%>3Qe0>1UGYY0:%b^+!%/XesOLpHDs`h3K.C=DXDZpi`lg>PfduI6;W@O;Ab/M\trq+QpcXpaNDt>i0b?OtR;NK^.Ejn*!<7@r/Ukfr2%dF?X0-\(m[.b9KEkX8_FdY;B-=+@)<9\\`R]\#D'ojLjO0$PM&DWC1(QuqJ5_manHfm$J`A;h#%8>qs?G;WCp$"t-hNBBNaJEb&\<5OTF;3.omU?tE;be]%Q"CQ6F$*QZe<^Z!&Zu-;%Q$^MPVbuZ#?3Q5"KcJK2*i'MTV,Wd]:0L*9VP')"10I0E;bsjE^ssk:k`inB7O7OF/:;F>_=du5[\0N#AtgSk#=^1ibnWH\FkWbdJKRG_Gg-\G5L3H"IUU1=(i"dc/d@[HW7V#lBhcYg/KYIWr_ei-IT*;W.+YsA@`sQ6rk.P>Hil#A#qt8RXq7_"JF,rBP27UPI1p4mJu,Hnq5RZ#gjhI:BVSdBVS`HP)PbCR1M8#+b5"/c%SSX-a4`[--Pj271:--jl&<_7<_./_R!Ce"7VKWL*shIY@NP`&2bp?Ih&UF!Df'$3N$e(CamtGgY++K^n)g(]E`)T)A83fJuD:TAn6XHWaqM(8eQ`5No5]EBXTr_p\4r?$4ERoaH7.^f[K`W"6c/*#f$5UlYgsG+$rDb<(oTe@&24JK7\2]dh;-RGQo>uj;[#=k?pfE'ApX[a$U`d>N!LHBJFq\>AcnDZ,Dfj/1oDLnM2=+m+9js]P8T%BF]59r(ePW4TNmp'Stj_1peBp"Cf"girb,"Zj0CS`?c)Rcn`Mmd)L2r!!W=R)65R,XOR^9j\^f^#];!qF&[4n*n#AD;0.7eA5_GH^qh4jC8g'3XANooi2/5Ai/JErVpqWTu0>7)g8+6:2oR-uQaa+Omd8H3o9,1,7.("kSk$+@!mBVBf?pY?3+2=fqD3#f&rTO7GYd'ND&LouRG6o]0VCh3Jdd<"aI0:C"s?cn99ra-M%&=]ifEVZ-8QO]=Z&Pq#rPtZ)3Xd`cZ8mKSjOKPWRIq>AVV2@5(.P?:qq+71<=,oU'u]%p<^*IMC_.DPfTeiMmF0sNRBEtL=tHY/DqmFBqIMMb$<]]IfuWU"]]2mR.ua(]`Xq+a?1OXWP[O-cctJU4alVettoINc<"5UGOn5kJtkp&h,D4W[m(!@71B.6TuW#MhV):=,2>(Qf2UR&V6MOG0C+LsiB;'3*]01\0K@ikmWt=?D^Y%?95S0esc=I(8W@P^=oL+&U/-UtZ;_K92TE35[4[.hWPb!QTeq&L4fJRRQsa7='mR%F;W\A3(_e;hI1a;b[Fi/RfsslR"%"^3/OGDV6*R^+4GAJ!2?&:*2D5fgOc(ni95J"V'FP7aVPe%T"*H4OXBV`%6qMtnTXR1R2[Dqg%LJB#Ot+[%.?%8mm)sC1/@_+@eW]['$__;`@dbq$k)g)FUPhH8Ig.ki:gp1COZ9R7#gC(W.ci%!@k0Mk/a2!aNg]Gn@6VUg5VuRS6qInT1)*'I>d:e)70-g[S2\8LOQ$X:c:KY2'b+Vp@m,oAbG[g5(Ja=N;E"fhUObb>j;k^]4G%4M8Tu%6J>r+khUVs+&)"si!uc/--,BYs/+]hC,7Yj;n4hR1KEE6V9Sd(R)%h)&JTIs3<,,&Q!anEE+J_+>F1m+:+,U&I;C!t&/qFoFDMssjm8F%m]1):n;!n`&)\cGik)s`^2\P$P=OKP8,nc'JdbJOV9j5?uduS!QA;gEm#O+l5&`U5`(6G^X4V^1;.9nE2KkLsd;%lS5Vr&B)2A.U,Ll?@L^=(TmK?Bb*tR!G^K_CE$]fEF!W%PF.%n\'lkmpq(IF_=?b$L4Rb0KLg5uWLlN.!6cpW^,@H=he?7)U"4?&#n:[Ulc2<[$j1q3NkI7+KZ(UHM$*L-C-DWC>L1#n)JshFR_[#](Vn8k>^9.J&5L`JAmU)*u+42UcMl$br)i&G8)UMM8m*WcENi9RAH%JV@Jm!X2JrfAr1D(<8Yra1n?m#_#KTMPiZRHZA,,fd#$?RAnL1o_m&4N6L1Hpn.fkWOS/F-#E1=I!R#/0b$o9lb)is,b6\KfShlJafd%Bpq:qbP^V29fH,/V[o+\HV4HOP=aCd\NeXWP3?%Ns9A)8\Zk#Wqm&1jq`G[P/16hor;CEHAAl0+4A)9-mGZYNCkM7!)ZR(V7;$=A>&(9UM+kAkG4/I=i[R4`]uc.,tNY9V`1,;6^3DrO:/r3nrs5M!MHoQ[g[*uaO953@(IJK0Ck]ee9*,_C32Rf;<+I=jEQ;g$7I,3:h'FO^&TkA"i`#+9j_bXB,FC!k229n`^NZqcp&$X#+r^(abNRSeLG-0#J#Vph2L"L"Y$H4e,CTRVKU@7lADoMJ7'W9W_.Q$ikl2YReDelTJ<:+9=]qI"M542Q)!t>r.uJqI.Yr`a6s'oo9GF_)$2TkO6:]@3o;`"g6Li1hD#t.iKk'>m)DQ.dB.8m-1G;3`^+:4N:Quobt*.5pBIn`.D8N6FmrO+Y=%>To>4+E^u3An&_T5jiUGeT>5'@T!Ja=,p&n!68]Q7#U"i.U7Fp)gYm2WX2p#GUGu8$qUQ'LS7^Sj3>V2m:E:\Ye3l`IZ4:dRTl5hUAsW%9VQ%S2'gh;&$Sr[+^"!j6*_.P>mp.<.Gkr;b'OEN,nTn)^+"04AYRjIG).?q(9g^"H--KLagL*l8K4YNH7^q`#T'L?[i"_)4q?cC5_n]^2$1PST=-*[:*mjkIp0A.k?n3T^,V]G2Sj.+4IrZXRS#?rkZC!jbj.>._8[s&+j3jl@Bep?6A&("mBQ,T.\QL1jo4orsoK@;9Wt!S'88)P3me@i2*oY&18uF`;Yj^90IJW^gId!G\,mq"OJTn!3a/pRu$U(RJMRVQQsSl1:Vrr1#u/O\Z7Wl1r7)?GB8UOMGf[j&K1X:a\^?`&g\rr`Za$W70JFn]T=ilO%uh\S=,#4#+=S73mG'dHb+V[kSgaG_dS_;,n+b=,fDh'Enn]5"@$^hQg_0piO=k^kfuol5UuFCGb(ncAn\%KY+K9JOm_:"dA0l8fZjgjJnXq57EeJgLgsL/+0Q9LoTXTk4O1U31UDQnC\$/rGB<<$p;fhC4K'V6N@)RUDk*G*c,V:5k:%Br!PsJ1S^u0PlLMG3+n8&kku^!f>&rE1<4O-9:AYe,H^dT\r=JWjJ@OOB?.@&,S1P6:))/b,O,f5V7OQLt'UigB:AB!@U%>UoK8qdiCsNN3H27Vq1!h[c3;Rr"a@6,=E7V0f*O>?a7mt,o$j)8S"/c,%2(6eqKPK(rTY%7W-/1P,<4eAcnu:=k$9g!2m-0;nF#a)P!gr&2GQbMksi_^cTVf%hT=o/3+=icMG.;=o=`8gWfoLSSE!a-C*V#WP`$%4=Y=9R'NMu#0eeKa.nu/2NB]O^$9l/V0]/a<6qN!CB>6Cm_2E/=M\NE@UA+fI=^\`o4E]R$o1LVAPtnTa7Yb@"MOE8kN9C@R:+t8H[7nGaCd=)E)c.D-=YkV/^DZaib=d\L1)lnV'rD7&`GR$l(djQjL5MjUlOsQ[Jg@mjI"Q3Au(8QOf-i=0,%<:@O1D9M0%4/5`iL]M5hk6%bDK6o:J&HuE'dk,b0g],;LKo7::1]ZBXQ"6f!Y>W`F&?BK:ub=BruaK;2h.OtWT&.D[g-[X-VS6j%o0/cQne7(*G7.;mHC]o&=P'Ua]11;Rnah)VOiiYY3C4^+#X_/6W$SE]]Jt_*LFC-QlC7cQ^lRE,Vn#W,YSg5kg>S-ke^4b.&(*HkORYn0Q"VQUdrOc-sP`n7n(D]`2"RaC]Qj,\qqO#*2ZG).,].)A5$8\Z_IhQcqG6*)'NG<-lX&Of/&4<4ggZ;a$Mq)Tf@USo)^WW=>1-(4i/hX_&ZqfsgbIX9$:Sa_6tlp'#a'aC?+)b&+#bM]&5&8i:lWHF^_hT#^q6R6J\YlZ5/%iOG6n?Q9I.s*UOAFgr1mt[7-c3%;A8Er+d>*Y)Ru$o7cuQ((_o=]u\Nlupf!2P7-<5YE\!-76RR3`i/jZrABmgG9EQ@a^Msgou6d+k_;15B?X'q`+RW1`%s&4e)sm#q8X,TWe"]W*:TXZ?'`3mggHnE@"AbBF>(8+5uj9IJu_sek6k!Cke501>U%LgFX2fT<*lAM,5IEn]s(.'/"d,NcHTb@tsjW7L;>_XhnO)LG6i+7(BKeMhHhC^-L>ES)i;#/VaRTIOJd8!j&-lbUr$.^8m*=?mRG8EU/EO;GprWd.-_(QA>6@T:kUPX1aI2SfMaKf>?fcYN#G6Y;II8<*bk8%dk*u861?8]Ft.S1H7,LR3@^PLk[JW9ld:_0cH\F8*3GYticRV=4Q$8_FUf$T/kCLfVBc_73`/>)<*[_g@F$0PL^\-\@DGl!+,S8_mK8[g7&IJJa\&5]a;H1cP[r"B@Sk_%$:,NhOlRf2;C%baVif%[<*MIjFS'W8M(8-?&aWI?es2+9BS`=U+;uXW+IXJf)-U>a\%`]eOf\uc:22>1ha)eH1lBCgb)a^2m+Uj%d!i^&nd3DVXf\5;;,HimXGco\Vp]?!(XXQp5?qqkUhKtmLqtQ/JInbXdcf%u;j0L>#9esIXAF*n+JDt:J=m^@U`?HQOFRQKA0ql-j.#%-hQ+l:%3*%*jA>UVaO,cN!\o_"!/?H:Olt$0g*0p&'tnL@R5^4,[b!dQjQ6BX;N@nb`InHrs-pN"IZ6*)`4riW>$Uu4^pEKOip<=b4sST\!%Gd)n-*"FNr/!abFGpMdrC/lSg<$FC0;NESjL.oT8,1S'i8M2jfUf.WMb&/BT?+:38XL92#NEcQ&,6]#:A?1e^KNTocp`Jh'jtGFiD9/qXe81^QlDVM-?sN`(T_f9K2oDA>+N4g?UZP'!;UC_Z8rjm+rR/ku5f)l]c[J=t66#IhadNSoB94uOY\AAk`P`sS7RPTtaQ*bJn"NDrL2;i`"0=Q@5]hA<6,IQ!A13J4\[("[t<)6sb'[K^0p#cXINaO%][XApmD+Y]-'kZ8HT8-c+1O9*Ei5d]&c1kK6DjM;NQOX#6+jO$)t$MXgVd'?%4,-X4[>JSPQ?b02I_,73u-ijh+>S"gV&c7R3mm\O7XR?r#Q;1YRgMO1/`cWo,?6H"3%/Md:!X0i]pZGWk3!105pk/^5$3>qeN'S%!e9ajib=7jEorq?C$DkV^P&pAggmu?EE&'8_&WeF%Aim*t_.[p-,bkoaLuGk))$1ulkqSig-j$q=k1lrP)EMrb%u1f$JICJ'jIAVhLj7pX_#Z"&_j9SWVE)O6H=5]Q]%uCKDKO_&%a8RUGnlkS&`F"0liG0;LSl9iph\u%!:YPYREGnq&Gd3"LSo>0U'&@7a;AO:'N[P-$:B]$8BaIlP*0iNpDf_-K31#`s%MS-T9[f(s#/%m_)`dJ%?*mYHIFcS=)TSL&YN61Vj'PILYIYbs.]:6QPCfQd1TGp*.lH=?Fk.3Y>teP_V7">J0*R>1(/aE4SphDrp;D-Hcn)YkoB-I@2S&??q*aFZps.JZMpS8u!'TR>jVXla^j+NWo:p2*rI-6nk9#Yqgkl;grX-oc(K*cG?b=a"p#77+;+g"1#7+%+>G>e]$gs(6A5Fp7d%_@CHGt%aH``-9!nf:_qIkX's&A^s+qL@&I)*Ad%RIE`JH$G1;GCPlr$(k@_lhMaI/[KMb6iKH\llISFuXE4ZW^r.b:hcN-(Lm?#$BuQ=t0R6F3@98gKgddkE3A28i*`JM?`.0RWM:JoE&[(:^L@JTZ\]m+CrDe0Zj`uZD'9T&'$54a_ba'Nh+9:Jap7*WtD(n%oFf=1@-1a5MLqR"Igb#JB4E@(h6Na7`Bh_bJJjpiV^L\kL`'bXVN^p'Ts'0'VnLLU`r.&%C%3QkS27ViuciJ8;C$&NX$aH$%k_J]'C^i($::dJUWstnU1p52urf[IbfJs$lDPY=bHu7:n=eX%s.rr1'B<_1e^HH6kW0,.RP>@4>o#WBV@b[-J6B40Pcd3T-Lg?N]Dn(T]Vu:@0hUd7^tfW&936Z,-b`K^qcm^5g0BC;d(khH,h*,k@"UKJUf!gJ7*q'Es]rSj>cuGX+4Q`OnK%@L&q6Oj/Hl[K#QrF%C,]L"kMA013fSjpgB(Wo!)]miE=nBa\BF5?`dc=k"U*+^s\gDGLH78=bg;,La(fuP>1([am\OqgD8:sf4QoC@-thpaZ?Sb8F"r6RRs-.*B=AnI#c6`>3Ba"IG]E&o5F4X[:P!UW2Z!;_6./f\`nP6"H@$po\VOuG<0/;HF3LD-SaO+Q_4kO7Cn"-\JK'@k9f+&!jkOsj%$N$:Oj&qE@n'!+_;LjKD$JFF&C5n>InkJ1M$g;#T".+n+PYL5qi1p:#T8G-me".2-7&#)RUn1)mZ`\^j0IGMJj7'g$-TnWUY[4#.6BpR6m*J:+Ljt]FL/sm.5gcN&&@]tGV,np*U*Q>HaQs0P3j)jS_Rk[>8eAeVFGC9ZLS?npU@j%#T\:2q&!WeOnWjC"j`5t$J"_YQab7TE;nUjt8/)"/_?#c%jWF\=6T=V1Ut?r>5o"^q:^\jA1s-OVpB*&;qGJ57:UN;dQlgu7^)jNEliYZZckPh3l2Z,:EYTK*?L+tg+T:fB5j=S+'Q*e`IHSO4_,#6+nm%+T8BdMrJjZr:>'4KSA/!Cc+65[P"D(pBlj(J.8rl^EV@37*bOqDu'UL6BTTQMXF]_8ZFa%5EPN_/=*@a9=aFsH/XAtJqSA5_uMnlJ<\PsDc$c."#Xt23]A]$FPY>T\1Tg4g1BC:7`cX.rBgg(OZAf:L[D")o/:S.+$$0hkEf(c&^2ngKa^B]r`m?(]SH^<5&Ae#eB8f"+rECF20X!X-6eli';f*-\!;`$PSm::g>96$?,F\iYWm<@/KqP+t_B1lo]Od-aO,3$5d8M2oP=$$`GPk][35DHh;SAEp^H(n""STj"cTFp@4T4G%F=>BX;2q;J%kR;S@uO@Sk=sU73.X4YA55B.$:p9bKOBAsA-9CN>A2W/J?GFmfq.$QoZ3&AHH[50mZa.M.X`&3WD]PcUZ4%i.Y[?ooN8!?qWuGP=XIF?7-^;dcFBi;:4`_S*^]7]VR=r?&/aFWrL@j_6Vo1f7(8n6[(3]5dLhD7!1*Gsm1&XbnN!EZ-pOc'JJUWN&@^+qmZY2"P/EL&c!?h4CD.cA`W=Z"5uL"h"+95M>?5O?Y2fL]ekEq&9pW(d1WK/+G)qIqW<&SdjSp%uBj[HR);+^dK@I6Bn;J[L=@@pp(3kj?T3\\+ZUe'Dp6J5KH]sb[K;fFOuGS[(mBEWo*l4C==ql1:SOP2DA>NkC!8I1':\j#EeaKHHoDqNWr-$5iI_6j\qo%)$f.F]Cp8);qs.*aGJUlA)A9'efG\lQ1mQGIRMX(#%*RB:3Zq!F"q]oiYdp^JEWpu;F`eqE(V#\4DYJGE(\C=cFa#J$"+SX!kR*d1Y<@/=eLL#tQmd]Ui<\oZ!/jCoiSqTiXi>hq^0RT\+Ber6Sc"dE)9f3qpo8&kQ&P>*^+41;^R`VBE5HRF:W9Co4/dmPJ#ndIaU7.9RPd'Cl1tN3b2^9`=i5m2"@+-U%`+"P0')Tm@=ofq.pI30[T\S5mGDk34]S4QOF;-Vn6'7jbIa>S&p-*#cml*0VM5eDbijp4Z/G`LM85Z&4:`":('pT5hIt!E4lSYPJ0'.X3.[I"T[?^0tM[GuQg<)4!ShpUmUYIh\5DNIQc)Nj+$:JCN*,/c#?Fs>b/&ADo,?^p8a[Jdc&&c-IJ[HpoL[h"Y.fe=d$u"!,bA_"F9UeR4F)Kmsj9<^!2FP72ab_kE*9Mu0@0maR0gP<37-@DG2*1VI#9KK^e3)`t59.\F7DUbf"?h[k3&LnVD#st]*M=;3iUS03k?_VkFYD6t:'Q>FY0(s!$5bJ/EBs@@h`9h\\KZ&GW3F560^21XpqYADb0kVN)@.N,8]"Mtr\WV(jpbMkkdD?<_V@V<]l:l2@EgJ:>ocr5&&S8RZDP)$3#9=b%*!\)E(jKG%3'(JAJ.:-78Z_n#OT6uN@3qN#3$PB&]`o$7m=q<6]951'O>uE+kh$[ae2S13dPkC#9oiW..-*fB5@u>FU&Jd`.9`#2J-Y\o9/*[7O=V(BZ6^:r9SCiN29-)nbh0H]oq'2^fMs(n?Y%-i"^[1#V]G/INMd*25;b6fq%.?AB1_GE[%$K2<+g+sJ6u`'b8NqP_9q@k\QoHQ`>O^),=_X"*jZ%U283*dm%i#WG)bUo$XqE3:3@f\O.d%IVJI-dWp(`DYIKRt@n1VC]\pnh3nikj0'"4Q$%Td,Wl!mQo>>C[bl_Wj7f")'"'e%m,(R**nh[bmj!`TtZoqm]"I_tcXO.T85Tlg9H@c?24@]qj4lbXY9iFWN@Ook?)o1gprX;!IIlUMXbF@1pK+6TG"U4?M%+>UhiYWu3Lg^Ci=FIXaB873f]p1T_3DK&KIaG#^OdGVJC`]ap_AEmB0L][\:`+k>VGd.,:tBUiF6$K67(EAYijPPH`WkQdO(W)t4HMano!&b(p5fJI,V(+o[NBG`:")cILEI*>pkHqC*l*@r[i%.O'ZD'm&r1cM%_G:K'b9h4gSe75D2&k6T63JPN`3e3R9m%dl2[._^9b=*/O89]T'7HRJ![biA:oa;BkWot!Xh%8D;8^t*TfS=X&fSHkXZ&X.BF3gRtkK`m3\U$rKbCA?iG$4dJ*H@pc6aE[IN_X[`l+A.!3V54a]n@jNBl*2@QIe!5UI4TE4+G"37itXe!OsMHN_Ehm6OZrb:-4"S4\N!0`#Ii-/nF3+DT-=>mW2?G\Lh,Ye+j39X1DENJKIGdia=T'+HN5j%8BZ^J#W`5<9^BM3#B.8DfhVM_(C'Kmo:HA%#(#\'^[);;YY#oKfp$C:;ne[Dl(WlqH6$B*%6DFVb-,BT+X=m6^BC7Q1pLa&eC+CXtc2su%M@tYC5hRg&OUK<0mTg=B0SW85>cNk&6Prd5XY.P\%#6"8=dpKenFXuW&]Jg&cDD;=ftsbDd/loABKP)E_5;Vn(a^D^XH3XX]2;Vra1^XL6$!5XYSohX=sdhgDOGGPM$YN".al[@TQ(Xo!QZ<,bUk9=\MR6:l-("9S2k,UTSamjNF<-Y1G?Wd0aP3k'GEa$"GF,I+mJEBDga<[lCP-lb([jV:_>!7&B(*l?:giN&/Ct/LGG*I'*K/*dX/ui$7_/(N=23-bd7s-P5um@_&#canA&Y(=-f%e;,EU!\Hn\[Lk2C^LXu!CP\Ib*_bW,o:?!BBW>q973,,$W7]MhL9gk:D9u+u8oo1@J206;n2\@M`&)*m7#=+DbC.MqkEd>PJ9\bP>gD!?r;]Q-$B-F!7lt`!3<>a_7Fc@[J_7@H!U3'7O1)P9ONb=[b1BYG49a3V;Z%>o;73(c@,s8b[N:GZ9mkNJR)BpH8<[c.X+u'0`=1.'oZZm\3=IfQtTbHihKM\n]Pp04?ohc!a;AP,DhOkdt-!N8Z.2'+I6rJe-(pOMoE06lp#teG2`et^Y(5O54M$S_=$^N#q_@/_;O#I'p7q7=1=_p`>-u?ki%18DQ-4#tObU5:_64"Vmee/e###I$R77<@i"7PYiMCug-*odI\5HUjn"387OE?abtPVnHm@h,YOegWH]^$N?o,e^sip`lm:Ic)k]8)ak\Q^Yt09?ZH>Lc;)UCVp/b74HK:p%&kDbBJ#sALP!lRYcJ[M<*H#mE8tYic_lN%d/%j3UfDmp\3J1rCQ"/VAC-K]pHEE'bJ1*C#j3!,&c1IE-O(`"eXGkT/DP:S`4P26SAF:Glc1*b+Q?sppr-\9(S5=.hEMj6?A7fk'3"rQpB8fV:o^OD<:-Q;#O=@$_3-f$0'F\qc.4fg1f%?R:5GPUJab>,irKL?DD2!OSQ)BKgPLE&I$Tf3JNag=X:QA9+9HtTc],GiY[R,$Z:gs6&>[lD$F@bB_VdpV>`R'DZ5LiBWKj_`)c6)kj'H)]HA%0>?UFF&E+c=LNsrlbR190:l*FHqFar0^R?YfoHg@"JFlXD&b6bH;I\9>iUmN'([.E?PEr)'OSok'*S@Ml1lD%Tb\<;k'F^X.Q*^MDTnY*9ob=er*__[0?e*]jd<27OHV,D%tEAY^A[=6F;u8%'$\8UOmZE;Vq$drQ$Z8:j;O)AfC<7oRL.>$t@1YV!B9+r:4n1kNr0?E0>*Zr&\Q(4,@bsL(9.rMu?#N&4fAni;Q5LYgS^SPeC&UE7Ri6."K`6H!#t;Z4IjWI_T6pNtog#KSlXoJL1q[G1m9D"@4UH5n$%%5qV7q\<,^!I0=Y_P&-j^Ucj9UC:oVZmIA=:PVA>Nl8GHWqCdQV>>kafT>@5cjA^l:L'5Ut+Y4&??EbD;F'*luM4:)inkdf9h(LVSWQptd>sDck1&CO'R$_!9=<2r/gu9R2HfZ'C"%lUHZsO4sG`7Ad#S"99i9Gt5MO04KDd0jd[iasTB&H*[YZdfA[/Z;g>!KmXVXNXG3Q(E?UiLidSe>/IV%3m^OW5)-c#2KkaG0hMP"KJN.-_@S7,HhZ,kBO(8//&0ZYHb&Wea(mT0"I4.V(0T[TMYp[_\-bp*Go4&qK>SC1&SZ6,NSal_\BhI7WXdecM&cV=[P2QQaAim@?@paQQ.QGf`4tSpp%q^;9'q_\.,%,OiigaM<:E3JH/M'S)uV+ejcpFZbas@drT#@3YC.+4^a>$gm6s7i.OGXKBHRtNpBE,;%4=>D+"lSDk414/8(A-A[9n5YBHS$Q5c-f`6ChW?Sp3Bd<'Up(8*iG6r:6(K0a^a\,W3QrVeYq?Rl!DPEV[ITD8Jt3E15`=0o(n8dEL$Z%TG2e"%L+BCA2@q%9jb1RQ#KVmPZY5jr.OA3)YkN\]IBK*(POparq+q"0eJhc//g.3++Xp-s5.0F@8r;&9/g-(7(8RF(c5C7VJ4M'9"1PT])FT7!h:<>)=)]_jVXb=G@#%'g0[s#J2'A^?@bZ6A4r;ZG7@MArL=oBQ&(3?o\?XD5EORU+s9b<6$t;WTOqI1_0kn'U'7FOWmY98juk(FO(bZpFfd(M5VBl9sZ:4;!$Ib\,DMD-!rSSOH,N]VCsdce(CL\9ZZLhn+9lcch8j!B0jG;/uCSo9;=gt=f+jS:nta$An\06)^Ree^'g;jY'm_k5!dotB;V?(3aHoV@+Rst9"k0DaKQ:Cl;R@GZB)oVoBk@uUSFJJKP*1UN_uY5`Q>P=]=o5:@P,m]66@e^M_=t=J#>H'!&#JfNP:$ntQ,eHk"q,1Hh-p9,4ii=iqNaWIL7?8RXPT;bMdqpG&e?^Iq`O,n/coSbY?#HgMD8Z4N?8J>6K/laBuMNPb%n?Vdgp"`9?h!V=)__VR!i$+J93BnG9(LjS4\br8WIG?Fj[YRHt4_7N'/!"G8V[')6GGoVH_LHKqorW7_:6*tf5UE@?^Og*g/GWR*Pe5cg^hd]+kq3,mHU,Yj*heK1V,H&'(fXa28eLcpn#1uX6loZ?7d'CqDceBSk\![`i?\1I@^"N]1tl4EB7hPX\5#)gM=LQRT_5Ko9JLafi34E!I8UMXHH8g;&2Y/OH"$5kW#:sj1h2@`+0\*aVQJ@IL&!:=1TX.%NO&PC]jK'3J.gUP:&@!DHP-](G:Xp0_gj]^RBg**Il7%bG+W@"RHH8*EeBVUW6pM6Rs#")7>RDmsET4JR%EeoO6$fj!qhS+<>0s9hbX"NOI3AmeJfFbbg;KiJe"j'U8eGktak&-)1_GD36Y17d]drbJp^aSZuGa("#pT?12tcS^gJSnb9GYL?Qqg#6K3j$M:G*W6GF@^S\i!!(i/Mn2bnK0;,\;=%Dl@4lX_AoHilgFi6N5dSRXA/3FV.TNg9)a?C7/[bECZTWc"G#$GU&>:@7W*`eHCb,k2bf[T^b8#?1=:l02)TpYN5!2YiOTOLr?mVY[)4=/SL0?$\NA?kk#O)SFlrp_\+>R.X?9+6S#k$;D']AW5S_Cbh`[%%I3@m=WcV_eR:JPp!,Wr+mO-c9m/YB.77Q.GO3H="KZ3Vl/B8UT__I4r67o8(Y2F03F#5E(^0aM)7-S0e'M$/chnl#l>"'OHu'bugJ,;BLN=;6!:FW;cV_]f6grnM;@9Om/!m1HR!%.6/mjJZGjUdUnNjM2G(J@hIl4a-U9DHISi`W>q/@UNO^Y30G"=b\W7buS@?(mWbCmDFb*Ll."UoGI'UJ$a_e62"U,gP\QQ#@oCpE?''p'LE:DF6>;mF.B;EV9H"h8i6qB#bdMg:9G8Pp7D:7mFB$Vm65iO$VWTcm4ga$B]Pbc2\h(\#%*7H.@r3Flg48g#i@)/1Z.O;qQX+Ufg5.YIACH4f6)7`f7M;s/oZ0$eLW)1+iM>kme6B;d[p_e>b2RV,,'<2AK@P)mj2mP!X`Z>:uL3`36tSslT'X\Elmm?Rl1rHc0[M#co[Rn5XX\e$tj_oE(#IHn1"Z=C`=%&`M3c94\Suc6BH_"i%AEUjf&$Igh!F9q2fX5_K.q`-N*FFhccDB5r1>,pGlA[9Vf*O7PTH:pOJ5M.";los&sce07nUc@th/'qSYL*7#,aB6D^'r5@O$^%#:A!=Bo:Ka#V4:@"lDaFQb2dOb,(%N'8(GFMSUBJn;m/OOVGTj+ojS!K\;5]ak4X?0O[0Pb>r;ML]/Wbl$u63NF5-o/Y!!TYsZ7"kY5TE(!j+AS(C#R2I+jM?.&*-sVIJXZc0D%Tbl6kL#j8\F3l.'&`]D,h/`0ObDO0N)D1M/o8SLP%T2$tK0&(*TLi=\&+6'#19YZ/NlB%.#(^Xs'&G&h#q;C>,_&a5gCtN0N2\ers**&6/m7Yn;kujRE1.Vau!pE5\-"Os#:Mf%86LnH`UD2'7+Z-_`Ce68@oH8qA74)/s)/%Lb(D2gk%2$-LsB#T+CI:s.3LD.R<-Oqf`&*mUA$&S4(2I)V;91Gh/L\+bI'q.!@k=]D(_)CW+sFD_`Q3*/QT/tD#8@b4:OD8X+aI,9PtrL)l&;Q2U-u@W*CKem'_]&Po5!CU_=1aBDAY)B<7.5q0P&!9pbB;#n"6oaO`W:*Uqn-`)TJFf$8VN,D-'@L`cu!79Ld/'>r#;]cu%a!JMqrVW`M`1;dCTeo&kncT8A,Q*-G7a`3fDa`*B!_8K,2;[sZda81$:_u"5^$6_f8*69;&GZROo>E[]dPsA@k9!m"E-Ghc!YHeF5AX)e1\>!Mn+YZA_M1$6nGDK9YJ3:FZFA9MM100!*99L.5a*"7uTY+-==4FX2qL$:/&l5bng?=V38rMY@,ILh3dRVL;g2e#Q6D+QLRBIJ#K7!m6/nf;XN*p:2m2FU>Sih8j0;&g#P;,cBrEC?ERd)]@&+/qDu&>L4@FW8ZhG(FM8A(`+ldl`o?TY229fS6%Yh>4b@=omfLPThMU-D63h&nD?*!Z1t_J0AI'.Yqb1C*o5N!Jj\\?]ebJ-bWia@CF#5<(&^gOD02^lkkfC,26e\7O7&MpS;qn6Tfn`OTuiL#Y300BEFDfq,7>8OcG4;0g#ercHbn>E'$qH/uBbK%Sc#Lg`f=(>YM(Ck#!7U&G_TVD]2Q;#t=n8.(<2a0NUd_DX_:bZM"1)knrRCcUeLPG^GRt9Yd`?-6ZauiKEO:))]DY@Q]aATkXmI"[n1*J2C/m;27\KEX9OQKV]bp*)]6.5FM<&;#9As.'s_.fo8:M"@;.ZkZrlhXMGraQ):ILe)2#0FNFn3B<^7`nVmAs'u:V&!3ldK`I5Z>C`8QRY?5C\b17c-Fu]%_SsSS2CAX@@O=9M>3laR1euCb^2u^N$p;G"ba]B/;;(jiIO+6*#UQEJo\QJ#o,;_bAItKi]D@s]f]D.DAUnGtEXmmg$7qYe;Lmsd'5/:!$Nud5Os3KD'/4D.Sn]q)9hg;N9D*$Z$P/*bO@Y1Qr;bSL3`&d'q+qPBN*]n?a;?Oa"rIFd9Nu?kYJG:eoAK0oB_^A"Q;8e\iom/!4i_s_he2[e125DEr<1H+as^3q6iAe)s*a[fQ@93$W;S/bf6>D]@ZG%4_ZY-&1k]-Mp0SMWhJRARKSbii<6S3oGYtsEX*j5JE62RqRo,Q<6IF*t@)E_bVh(Pm^r(E[bC,^kGV%<].$Jg'27ql%0Oda%fO.:^&oY4/9:5UW5m&<-Le*:hajK?,[i<**X8o]Sh]+SK1C[n1QAh%ilEqRb1*I>`")4SH3V0R].L?`H)&F,J)29(;M65jhad23<8/`fu'6XSRaTG-:nVM;A'<3^:'!OP\,!G`G)E[$R5T7q-G(W.,Z+f&%>d7-VPnF6KNJ`I)7-#bP$>G(*25hFaaNC$p#q5!#)q7XB,)/l4Q?cR_9lE)FT@=5Mh&C6?2>/rFpQOOL65`Nm'6VoB0p.aqY+[If(W8JCo&/t/@'gB3.R^hGN_.O=RPPuO)S!E_7P6EdmVD,jc>M`E)e%Rq'4X7)=\nbub;QO0u;(upd,f@oX.@8J[k,OY4R3[%$P]UkU%$a-$+aZr,ONSap"Lp'C-nn-pfRi=A7Ir;m`/,'K.&('HiC(E8E=iH7LKqfh<4UErl@G^n;/mn@3(0l#/#Pon@aJgf3Y&N:^'S$`bI_daiaP\b;+X^)%6SV;"\h/H`2)qlRcfsiODu)g,kZNLX1=K./VjY@ZH\37$6Kics&NE\fIf0'_@eSJj1+k.\]YC-'/IdW@u2U9,mk:PFXIghcOlkrj?-RO8(OjE%-Lj8WR4\6])l\OqeQLN6rQ%(7us,O=ikH4PiQk&h!sY<>D2OY"Gpsi0g98[NU5+!XoW/Sk=Ym`C(l)6H0F3Ygf+pOG5c#f7q_@T)&j@kc)\@3ie;G&(U\oe`c;0u:DAL5/U/(nl8Map=g3E>60lG8R`\?.UPn#9\R,t)",q,SGmitgqp/)DS3[DBgZqII-=S(TUZ\!_?b`^"*iMj=pb\bl\SK$KBaMNbZ1OMDMMH/^sN4:d%_P-Hu_/n"F'=)42<3nk^9l$XRo^s4gaQJOkdtk77iF$e('BEa(>^YNcd!@:`?DQ@!R0?HTcqMdk2EngDJ5]o3X,[PQ]hd'0YnV,_*&*-3NkR9=#+d(k@)T\M;\]*._q^nQpg*U%l?n]/9$iPnYd-I_\kAo7VO2Y:$$nfn;GKu=ka,o@Obj4j1*BcZ&O>T3+]PTS;AK+hjNh+^^Pi%$3bJQ(F!Z=46IPFa(7R!Wh#j,K`L%N-)Pof>tfLH4EFj"H!c-Sg"=#a]U#pIK\V=cgkp>QjqegbTW/\>CQ"'P&?@4j#.#"97#hE>V#h*#/iNsX'+V25,"t_@Jf'$D;^"usNn"]_D=;O#5)gRorJ(/.q`^%,=/'d'G3F)lqT\=b-Y3u/Q*UT>Cl[OOM.:L=>1R42oZL8Q/IEV*U8G5!BKH\t&A`fBkA""%jC^:YO:Fs;U_MnSm1eBuk*F(?su)2Q@qZ8jir87DcGq\CO_)B5`-DGNPn^sHd/A51k"Tb`Yo"l,=PBc2f[Hkn\XR8$aAI)IYpH4T/M/@^B_`QK6d^I)")B?@'jjga_On&P%JZ;>cl?`QP9I*8`<+Hr!Qqc'jI^5;o(('H$D@iC_So-q;'s_?Gb`+7X31NB.]k&86JTale"bAr$b$Z[LaPh#)T=be@AV[jh#Z_TGep2UC6;,#D*q_YoYmObnZ5GHa=at.Mhi:5`]05sF_UL14cYaYKS^og0d>'ZNf`h>9q4u\3n9u=Su'^'@:[+be.qWhiD[dM3X0'H<)m!QO71g`N[fk(nWZ3LUN;bRq4-jYSL.aB(F*Q%RE`#.YIYDl!>EOaEFJA!I;$ZX*]Z13n]#)UulG-K2k)!ZR$Ui3;%8[H'>31?'`j/Kab_48gYZ66e7?7I-,e&#P'Pg,UOU?TKKA4].?m%2Yg@Fi0Lr6WSAB$)S;o%`YVlN`u(9F`\>&VX`.L5cSs%rG:>ed!gjC(U)^K?XXgW#gS4ZocS5N*u"cVeLe8[8;._&i0WFN2Qp,j)"=b=-4n\1'EDsnhgRj=(Se4Gu;fp5=\)m#%(;#SMTit`QHaMZ$!RO&,Un4WknHn5W$O7$.VsaO'+m%k`3Vsi-31.Z'L`h)pF.B4tquCsfM(==='b*?cG--(Q]Ec*C'kpCA/:kt;'Rb0&EW>t]gmW$;3/Nrrsurbqr#7Z_he6'bpP62qZh^Dq@Ie)J-J0fLYj;oJO2W>&JD)2O'JC"=UpsH"26QfcY,-VLef]G@/TXFS\mtg5K<\,4JDSl)@.9/&dD7$Tu?'?IK'%j>b;,_<-e:1_25a$MLI:]aA!7$@W-KgPaXVJp(J(pk_B[Ya&9`Kt8mh.4C#J$hdPF$":u9Z]/78J>#TC2"*$X/,-]b#(Qh`$c1blmWDQJsS3J'8>*K4e=t-3>#=(`\*AU5qqrdU>0KuUmn8NNC42<<:HVG-G%0_,)mcn=DKB)P(Z``:pe%>&AcHt1u^ipUm@%0d=cS9KSR]4A-[Z,D^7DAoQ]usqrRE6-r,gnC6ema"."X)4I%T&F3OEQii%&A2cMUP=3Ps,4T-=BjU,N#5gUM$;+Weh%4\S9F%5U]-E#H:U('MZ^u.LhSJ"OVNC*CBpO1d$FnK-_\WGuf_7&8i0b>n\\mZt:@[&7@N>aa3Z>ms\o?D3fAL*]uESk-)1L/le$(#9j+QoV/*FKk`*PC:,ZZF1856KeujkOL^?I5;$&E-@?i`DQ4Z/gA;:?O:ZAP4S0m)XQp8YQRs5l;K$IUGc//V/!KV*D6>]aYr>5D]n[Lisi\2#t]h5a2tjXI6JuESQf>SGO9[h4F3TYf$Z?@P&iNP"q;c40fhOVI^f&;PBqHjBPL7:$rT(f$A@^E3>-#8%!UB"u!@Vs(BRN'-:HVDIN#,%,B;4;SI"ckpZ@#%M;-4:rh\%)?]30Qb)r9W3"U5L!1ZHuLt[Y@RjpB`N`UoS<:OiZFlg-CSC.lrMZ@=aEVZ8!Ra^#(Y&G>$;!-R$]ZY_AJO?RI`N6>a=7k#s??I#lhcY+,YK=,f3N$E@=BiE=!%sauN8"iWLXT"b4c(KZO*f:59[s(`0Vg4s%>S?XKiIDm7,nE`Z>?j6[j3m%.$qQ/g[11mhIC5ID$G=!=c;HMKT@Qmi;M)>4XW!=m(J[8]AR*_@,j0Y.cLl5'uQ'g$gA5*:P,mY\o5[k!@9$eZDO-!5u<5-#mhgZ16BXQ$r%$664STt8-sAELIN$\7i2Yn"KTreKHgL6%gN)T3(uXQ4ZSlmUAfM39_sU%k?$=;7MoR3N,Q\NIE:QriIpn'Q;adOgeTAr8Arlkr#S,%Z[*.siJAp=ZroBfCZJq4I><(`OL5h1OS'5?BpTI;PhcqU+l!kIbn1!X0pi5q,!/5$H+Up>VMO\cF2s@TQ`m;!^arm3qV33j&&Y5;\P39q!MJiTc8gP+Atod=2Qg6`7@D@%(.re0m/.&^eH,3=)G;JTp)al%6^e(T'Eu#i$)F4EEp1F`@HC#\q/YGkS7ouuom2FBm\M5u*BG"k#2]Lr,`@7tNsfDH8#1I9G5\>4J'-Zl7=Pfg'q@XPj2SV?2W6P/%m5`Terkhc[Ig_pNVpnf0`P$!rX,_VhGr8WS(qCm2)\a6_=MZak-*ooe1oCq#K%%EIGan=qUg3+X\-G5B\.WR]FPL0-i5i@"F!%tTh:,B(QkINB_fD)0SL:3cGJ\C@8lC&q8dHuaB$42WFb89$g'3NI,T/RJbWrnj@I?d8W&n,5KKs-KV^YQ$eInFZ_+nD<:,j8;+8*l$P1?f1lJ\,APdINSFde,GuOqu8>Js5X-Wec5)6q1"J'5L7m[5Onb*4X0Opg45R1&)i19K0E\"$f5?VTA0B,(N>_Ue/SA'%7*hgZ&)KV&Q@[%qAa3_C7*"A&J@]HcaI?uZ>sH:mY*3A^Y]n.5oj>!"i(V0SRE"B#N7uBKe;7[2A%@)Qd!6T1L[H?Lj:pS0JL^iNZU5HP%:\'.=Y[2+]Y1b_?*!:8cD=84Q@>?NkcYl#80b6jE$`brt`AahY)""JJe^/s(7&8gZ!e%."@Qo"=Nl;PJ:6AE&IG\8ese24p*s.]E@HJ725s!Y.&Tg.71#"!&0m:gN(/784#jA1ebF_n\N+&T@Nm=L$I%EhaeXq;jAA\+ubWJYL(u#1-Koqs/`TBHJ>:E>)gaAG@\U&Nb=3#ht-"E!T_Kn2PeXRpamY[&Rfstkt8$X)'W*r;SVM91Q[cA6N.h5h\XlC"Mhu&lnsp,0S=?nO46I-RaUfR1=jX`QPa=NUQLT18,9oQ=AHok7)]lpclrs9+s@miL96l3TGT51fjb5g,tiCee%r^4!VkZ='p])XW&dt0,"(REmQ3qaFus$/`T7.W32]Mjq`jrRK22jrN)BV.)ma#BF8>h+cNr5Z$@#ol!D!n:+qt%m,q,`lNAM=U$Re2Sl44_-ob*WY*BCn/4AW0bf1G#cA9YJ>jGAjh^o3s-eM3;S7$V3%_>!Cas%^D/]`#/11.3s.]W#A#CIH#(;`R6<[T2JM!@>8ur<%\`)*W\,nYg/F(A.t#,MEl4gLTG2s8A4QdTe=EY7Fu##7,SLjE;J"Q9[4+ERXN,9a<9'972gBp2F8?"_tOlBp5q7>7!_RB&f=fIY+rD?7=k,]OA2?kBlKEd^'*rM5!0J4,>/!?%O`,6Dt6#TjgtX17AVkm.P]%9KB#gpHl(L;@fikYkR.*an>,)4%#(]1"Hm/L4fYo'<*A[M'b$n_u*$p+:H=kh@<<6Nl7QqH:'s90bbj?%CV`n1B$huir5Op&V=Fj#HjcmLN.nEm"+mr8*Id6,l:`dnd5p&nB'd_1k3UlqKTc4_nao%#"e])NnOEcIp]4n1gn9pnO]Nh_+).+TD#H`YPaR'ENRJ1?hu8i]8klGU9N10KT.Aoa\8*1HP`6[e"`CAf7'"B*,^8=Fi>9`d-/LIPeLE"EsDXb0PZ\Y;k1t+.Qi,V&X11'AI-;r+JX(D*aWIFbj@TA3.K&B^](J*1jj6AG(0/!=,6P&@@8qGa;Qnt>gnV4BZ%^:bi@RSMcImU*g4Cm42S)'N%]P&me;rH0LcC0N-s,.3!'Wj`S?SN'I4Y*cYl& +#6<\%_0gSqh;d#""QRi4MNW9%Ys8;Tjs8W-!s8W-!s8W*A!!!?/+s:iT#QPE@+:JNalM^0u7E&7,zzU5BWbz!oq"M1#9$/UR'Q@h2E0$HX4Xf:2NWkAtYU?>A0Z5XLk)fl$_aFmsXWhU_,Lb16eF=;LtY_;4@7:GM-3XH_GC2j>#5d`0]WUYfGLm@uTQ\8/5QGJZ:^!al1hiXX4Z1]3!!bahTQJ6W5j?(>6<:;j),Tb;_rq(S"]4Tp^n;;I($KLb"*XME*kPRs*a8a2mA3[.1[C%gSaknoQEB!KJ-V"e78sKLqQ7f<[g/oQpRq#,Vr%IVd/!*kI"26_!32kCX@/ja$DLgq@fQK/-iaSS!!!!";/3L+=0I&?f7!+ek.8]W)APb35bL",pV+k_pMdk@?LdFY3?)DUUjT#DH7:>M`,MT5>M/qVQ)JWr&9p34.AoCg76^f"/EJ?[LOSc!G2QpN!kMlQ5PB>Qe9%Xo[YKlb;dNP`]gkf@ssK;9s,dbO;"NT3MhD^$AIlhY2:7flm,"G4"[>Y<&9$D@`gThd^jnZ_MkF;8&MfhT_KQmgJI5!mpgHlFYZOZqC'b^!'!4K5Y]WkSeBG<@%rN>Lj:QF;+aoG>u01g@k+Y`YU:#VlpC;Vn7Acp27T:*mH>2S\UodkG^QSWW;eD-_iLEpYGS9D;0"0)e=XTS%GZeH+R"qG6Vro=)?^%<8/(-0o!<.!:A;%gu=t9pWoEpgV1/+h`#2J>>)ZQbs<_*Sb@9_n8e[!qoO3!";6&f\`o3cnr@F4mWY5$95Q*D:)19M*#1*/qjW`(cF0ohH"Sbcj?;r*gO8fKJ^K*SY2=G/[tW[F]b3d#aR,7p%`R)?hV@.e\_[;n;U_NV[bIcYT6Hej%op:XeGJR,RIVId78h^iJ?PM]q?Dl)pH7hk*r!DC]u.OU?Z#Pf^%]/-]_@H?DVG!CXk<*KmsE[D2n-r&Z1j9lpNOa;T\4qGD4TF@T(]d&k69`8a5+JD-#2Z4^"r*:3\V7INr!(i71t/D!e`=D!/W),8%`Cj]6isn]cM^NFjX2S"V3l^mpg\RYT3@:>!Dht^,jl`_Y8=.c(64"dKXeQn`/[l`pC0`([UDk<"N=94JdUXD?tIB\s`!.]Sb+:)W`d$OrL)?aTBR8Mp5ksK.e7R<"V!!!.T+p``HN<'#R!hZ;9rDPPH]i3T2RSQjX;ot`-%0K>!$%8JQ,isPJ`I(_*2iqB_BAV?,)f%m'T+R?Tj/]O&cNVHHmAUBFJ)M[a@.lm9LU2t3gM1h8cL-RdLdWh<NV%3lH^70+kPbWurM"Ubm[_%@s3!@.eH,m6RM"VVRa^dO;B$l)I@,sagc'i`+J`=Pu]:dHonP`-:j;\9^#6Ua?t6:1ke6pUhb`(<<^&Oa^J6U=+,&JA%GKG$]V;$96["9hK+PT^Tk'ZEL0:t%,Bd"KV2727LS9T9TK<#$[p6ps?V1pg.SYZ4)U'N!1G,r66gKMtRd&i?DG_[I6t@aV8J*f0;^;oNPXJ,8$OmeH`.LTS$PQFW'*S[TPS$lG1GVNq92)0U5tOCB&/S(*oi7$%aW>)(HP\#`'glVCAL=Lo*WZL`g5_!\.rR$5S/DTI(jJR3Dqe8j]CgTS??rPaW^cP(K?nq*K'M784CL1BLQ5'L9T09b`^(9%>XAN=,k69/6Z&#f+U15nGda*A@dR3T,"&fGR\_J>alb5_=\9TdlM*#RDb'Qt`9#,bc-=Q4aHM#RQb>A-N@?)G-f7M1UuV!Z`n*%5B:c1C410"Xt]*`"Fb'OAmr4&P5fPN>4-=1/ftp:st:g'bF3`9%-*].7l!cK#7Wn1lWma5SOIN.tp8U!(\m["%a4>4cCp)`'I5)+\PN[,qpVh:_=Br#n2do8u!l`&OeDg70Oo&_$lM@0bh!Jb;,.hKeP8=,SJIWb"DfWf`6V'l_!>8(&YfTiV6j45Y#gB+Q6Hl+@!DQCq+B(iu[$7C3:f,)!1DEeU8PE)0;)1g5d8`an:t&E:9LCTIb(Tsh;cQ7";af![<'jKI`6cq16NES)/4hBd&d9]mZk5"AZOp2;";*CeYYtfAV(E!A;O%BI"N7QB6kGP.'b]"-;_T@\&O?Cb`!e%.'NHA(&-RYTBR-JLDjpK*FW;8kKekTV@R9-A"Q.+:;MXUhRJYZPnOX2E=9M6!19#/p[&@0Nt<00BY`.V)`_6=-:W>[+\@:C(J-kqMo-n6*$JV#'q6:=-W'SZ`U.7?e$U4SgX-NSQW&HY?H,r#uf.8rYZ0b6m5Q!t)d;Q-t>s-j*dWs,EdI]%Cr(m4d>e0kLPcTrcnGMfkMIt2d@80uNa&N5E/mY[Y2cPmY^KAApchTGs,*%kFc2X$UU,l\(FVC$6&p?t[,3r=>mbD$@qt)SQhRbC8\U2["2n>ia:T<6)6H\9_%A<;W*o6.j_H>H$U++PXZ*lD;&Gm4dQPuVA;ap3,k@Fh8'`led1@no?to3''K0\[i@#_)("eY9d).6dmEWFZUA-n&]8pH/)rP:S^McNds_PS9gslAVP%@r!r4/Nj>T.T$;d6DZL#122"e$EZh\m)[1PrHDp?=E7-lps8;>TGnJ[Wn,hQC"7;Fup4f-9;m:c=^iS-g^"nA+4TN9k]B>+;h:mbT1Dern<)TjE2tMkMN6FSFp?FUXP,Oi'blRY;Pr*FG9N_5#c7X7K3!a.10c:$qH]4`TcKcY3^\$a>W@apXq5K)]/Yq>h\7Lcos_R&ES?Gu)UG&1P,Pua+r$;-EOWWCDcB]V;!@/-eF?MjK;^@2(k8R5U0JsbsjdqQrm7.E4UBap7PipE&\MlAk`TpX!=M.]U3*;WX`KW.PI*RBs_$l.D?2Ru*?Zut73*Z!R=$uq+;^g4Fq.flXjcb_C:NBJJ%O"SWZ_2ra:ZCOX26]pEG(UZ-jAmC%I,@3?I]0+8b:IQ8"VPinq+oFEB&:W#a8J!CAeQq.E0J+]jQ'/NlIe9P_Iobr9@rP3][1+mXd\ro%lE=(,Ge,sBi7KpOJUhV)cI5K<*@R`fDI&KlISf?'g&F([mdHjS8-6f#OOLIQ1q,N0sDWW_e5Ia[AW?ajb$>n$bl?0V"Ves4qEp?WQ-M^e&4_hG+Wqg>)">&%pVrZ7,mR=\\N=i@;:.c271V*-KB911'qp"b%\S9Xla^b*F4bBTARI2CUDD&;\62U/Gs;om+GIc=b%.T%/p8B-p2Io5P[=U*^Nd6`98;Eq[qY@p/b11o$L;j;j.7i=dq_i"[pB?)5Rg=*4GbpIbc?>J\An0g<*'jucP.`T<;?SHRI]9d]n8rS@!9]B8rUiHI+*2h-SJh`:Ja1L+RKLc"'5ZtDM>WKoEX-f2runUHIr;Mj>``QkAa6>:2qhp_/ku-*6`e);E7SsqA?F6,(*>B+H[a\LOrjEoPATdEcsp0!n+&H>0_d&<+k]^(#_`NnenMEr"7^.Zm]s6=Yi_,qrDa?12SG!4-AGc[0^r$\+/u!E[tLpfM5QElOD`7CZT_0EU+gER`6n8*X\Z+D.a:)?@Q&oG+Cs[$1s(n<7s3E[D-Ej$^@ROB8LE;6%ghsB\l*geF/IsQZ5MhAEoY1l:H@7WXPt:l_[T/CLMcRG3dU?i=!N_MNY[u#D0Itrd#of4S!PC,l.Aj,:%9J%Qu3Xb7Nd,fj?a<.`M&E_a9_C)?^J;j2toZs7psO,.0iFY9I3:4h,9A54MOu&#.;*:)%E%F"69,E4NgNf7e;!/J3!Cp"YXrQ;tEkj^b;_bB_7=G\SC$Oj510U8<-)\ii&L]?6NKZ;,+iM5J$>.6=/#M.l'Y\ojV][<.jQk=$XiiTaAoBs]/LdD8>i,djHX]^GVqdnKMN*=6BE22P"PUm6;`^kmIsP(p+XP!k(k+1aoh.*^Y3DWo+ICLYXfYG8nJ,i:Ur*MWM)#d\3EkuJqdm9rjk:HNM`\5DKV-d"6PM:2$N>G`bg,ipeO'M#cgWTG)e.he[;rD0;ZG'%B;(lK68?nmVno-"Mc&(=\.@N(iu;4Y"C0Hi@f$q;0%$5eL#7Nr+I3N?g.,(qY0&EE?GDP[4^G3Mr1ZkB!Jmf^%TFR'=jhr2=ae&D6+UD*"cUpK/Tm0*4Kd%(L?r@=>,bIaWpEYjB+N+9&PPVHKkcNLKQ''Fq_-;V3_&St\$>%)@>B`%cV%/=VWo=9OFa'jd=31[5`gRLNMP.FCab0#'p*%3M,^tCge$9`6)=MPim4Yn'm@f#:YSXa(3qYmgeFBO`Q)(*Uj94uf6h,]F`U\F,](F]g^%:W>f:)BA&omm"e2opoIR,pj.7#T:jmpo&c6#6PJTjdd_]l;AcSPfHU`+GPA)RX!*5nqa2)=`uL]FaAuD^)ej4QpW_g-s$9j6DJ`mHfWJ:NCWgAiV[@b-OZf3N]I]#dn7"VU*ge8)=ubX4'.l8Dh>)5?g3CgcWak-+N4ut0\'5F\n[n;=rLCt.Bj:Q)R3r"pqFsL[jpSPM]qC@:oF;Nh:G%VfO^T$;[lQlI6CZijeOj^*hDFCHm-QAKP,0O]Vcb=@shiAjH];;VLN22Ylf)$N>"c&8Ia&/OFPe"^X8,$H-[lKq>&'qHQi?.G"isQHmEVWNj)63HS_"emH1^V!Ff0O3U'G#LIold=)nh+.+e%7;Z#D`"G`o(oG"Y&mX%_er#o?.>]Ps)&j`t]OPSco>!4W%Y4O0%e:pRE?s73D(-N;+;E`j*'i\>MG'nVYOj]$1B@/`G6:CdV'##ch6=t:Q6ZpLDiI'l75)VD*JtA7dgt#iPH+nAdOm747O+''ffiRQr?,G5/>te>m``6`hS)8\k'Ih/_<%>-]ic*+,D&U?&r=XUr+eHCT.t\%'jf]C>Oac1P([3_Q2,`f3"ON<&OQLP%l92em?nS^8kH@TaHn))0Iu5o^Qfj?^]19/>d]n04?dl&+\3[@k,YN)?4HRORrtSU`Qh"7UDNg;)WWJ2%,k@3P?hcXY.0NNl/1t9P1BIQLbaY.AXWC=[dLNAH4%qttMUTr(XG7WLPhtch"0i"D)SWp#t3:(u0(X`'aW#'(3/Wg[A28ilg9@(=o1Fbg+,)U2!rAl;UI,WG%IiO9S_b8rAM\O.^(WUD^kZF1K4OIkAO*B7Hpq.\9Tq5F;jc0fmJbf^BK+VW=*$5:16sF)PTuq9#CXfnt-6$RLNi)St`i646-sJD`eX&W/bdVC0p5]:-hRG>ja'][NK#FP#7f-%^[X^4(JKWO9_<7J2m$k!-W',Z=8INZ2ViiiJ\nL9*M!l7mT,["#r(9@[=:\[QEPh0et1MrT26]*6G#Ai7P=h':M\.beY@#SK]5Gs&>]dTe5G.VA7$\iZ[u>30uKJgbAOV*Y3oBUI7;K)h^B>6krqe>N.cX&^[_'7pVnCZ?EP,97k;9NKMq;imN[iJk8@rYgDjW?"Vo&WFt_,k^aUeSeOmtgGrR'TZYre:2Se.MNZ_IGNV!iK[&[_)13fpP.&c6SO,&$c!k<&4BFNUMre7X3-b>[TY"t$_T^Qd1"Y*L1S#)ejVH;mX@OV4+QTuG>KP97g]J&,+^lHJA%MM,E])g#1lm%`,?gi\A*t#XMW:>D=7Ql-af%)(FRXUY2FGttFNQ^CQSPehEEja97>,oAG!j[+-4O#koI?ZG`*\^(7@G99n>;82RpJ8QUrqN>VkdqfdnJjNK&k[!QgefJcohejJU9jE88;1#QDE:>JX(M[D]'6))KV`O&,5YPgV%*@^RH1,bngg]6egQhZPIqp^8+3"rN3)/B4&%VZ:L'@6rVPlt>Is^!l:J17Ng63b+]Ymj_d3q7/4?+;Y2o96jq0)@3,%JDUu-*+N+@[i>o,n;B\FIQXJSXcKbIq*ie,%T,D3TqcBD&8?Q-6AS:%[`:iFs=`mYW2tV@#[Zjo+lN]?^,i>]LPNKB!3;]+A\>I%+r0,+GN-W=IJ"[-9TQ^XDZ/j^tcF6q/`h?V0G\Eo^.Er%7(_Qtk=E2[CNS%b7VX-8S&J$V7J(-Jk]K\Yhqh0OPKb"eF1R^6SMh03S%6O3M?I*V=WCE"as&8(HT)X,X%-l0h+:1QZeL0nXe]d*2/OFNCCSO'Tfln1pua`,QJ4K7WZdsH*rf#qr#-3,%lDQ;6:m[19`DM8ceic+h`/TIKjIsJU;Oo6"Yp#@B?AK9JWGV(+*8Su1p\Lc,Bs!2[@o%l$7/Oga4QGb:We]tX1QGsP%5b$/EZ$T2G:%o+-U'IWqs`EAqo^m:X$fd0N1:B=K^3*qU8J\SP0!cb[4<-N&#@HP]2Ad/6&OL_iCb`[7(#:.C$+U&Z]WPpXE0>ReV#:9Hp24R'00t@"T,7fp?D$VN>7bNN+b2+m&KBs3%kB`J%&h>Y!uf2RHZ<.HG.l&rJsPq7rPa?O87$rL758Pcto+d2mttZE:HPH.^>QT)/D6h`_a2b?ZG6g^NAgkM&LOfem1eapThZTasqu#,p.PsQd#7&rL.Q8F?l-1=?EQbbC<&V5U'\YB#OOt=PVgKC%3,uJ2?i#:gpM.sWu8G]7DBB=W_g[+-@DsZ?JXKSt,VDM9uOFKNG4hj_Uk)qm/)?(^1^O@-2gZ)3m=ms:NK9=2NSZXBACE;cFaUM9c>,XPX*N"t1opE!>-j]EQj4ebbU7m;U_b7.AFg*HQk<$Mm!OV;C":=`mW&BBoGCD3*7TG;fTJGM%6luj3@U-/arFEJU%2;K9(4P[,R7Y_+,#^]H\>V:(i^)68+GADr9jJLi`[eK\N9Y/..D^p(cjs"^)cY+i6.JR4]%>i;j486-H-Rm=S._@RofVTTR(j0\468Z3)_Bk8cJsLcMKb8%\Sg?S9K.gMg@o]D7?a=J%OR>5i\$76F1F,f]sb2h/&>-*P9H5,S_:%r(><:N"o7hVjU_(#>]5D5!JJ5s$5r+%I;fH,h8.Wu]0tU$S.no2[_e=b]\]M^;/QNA`0kajBS3=)*Cu;FPEI1E/h[K%e#=F_":?Z7`mdik+V+%J=n5o8)a-+G?#3q,JSU7PJNodk.3LhTe^03eM^bM8Iq?'q6li0g!q^B?LiESl+XN1K'lIQ!sOdWq9Oe`TEpe_LI8DK$'_#^u#5>T6F5$uVFU)to&B'+J1MbK0KsWsmG4_5l[oe\\[i05js0MV)J%P",rddSe['+>Acn3pMZ10i6LS1o1pX1t";5b53PFfeNf$Jf\$snpbU@Fgq\uXj[>,G$o6e9^!<"GdAE)c%0oE",>RY:V2^4,kLAGVfD<(WR"S.0\OHAgl4+\)Oe3.9-$+i#Dr9fUZ(%cR?(KE]d8BAP7?URE,j8lE.l2?S.\)^MZC0W)6-m@LYppGau?8TBE8fiJh,YG7!G^R-8R-YbSNVF(Ijh-1!o]7F1%VDO%DRhrQ!\8=-L&lSUCBqj62*.I!NdYO'sMkL9\G(`-r\qRq;sV^fS%HNC"(W\gFCe,Im4N*Stu:;\jqu9G$togb>^hgI*HP5P=hl7X/T1Tqe*8\5tq7A-_*X>tUI\r`P#cNUrQD-W9__O6VrFlJlaCE1eZ[c[T:r0qp.I_]n!WPoDPn.@g]%;oFY7#Y!B`WHh6!@pQH5)3>qr@N-$*l6=A>tGRt\[J`t\QQ7,D,7a$(JC!f;pF(gN_M)-]*mWVgjH`P-uk+S?$+TKUlVlLXXr%EJLNo#\/2FE%s4VCq"nlqMCMTCco)3;^R01TJ-5jb$YL\B"%7C4,2N;af;fuU(\EKO\aM_$?0Qne_WFsCWip`!7%Lpk7RG'<:][*P6Z+TZfl@50W9d.Eb.Bct/KpkPNiKS-UeTdXTK,nKoZkFOnnB^B/]M)Jj\T<7i(5[rSd5Za%r(4a=C5X@Zq<2+Zb8jf%d5e'6(R=p\R7j:WoH?;!4P?W<:+)qcG#+@@R,__pPk1I01beu(?'r3[jMfKhpkZ]P`1dKLpR2HNQ4Q(;NS63/r9aU9t=J;A%+-14,CG_foPc8Q,Y/8#^.t$-`C6;RiKC"1G+?P^9g.3d1Kk#u",o9g3S8F,[7VJT`8=6#M5bDEW9]H72kh'`:/W<5.*Cc;k&i'P-QZH4:E]/AS8V."WQGfu"LFj\h)Lh,Q1(a>"3S]NL5480+deOHZL.-QXGM%OJ#KmFq4\;qTl$Uf@i<2>8hUXVapGq4XaaD7c@9E6$pS.m#gU)97>>&F]+<.;Y;5l>4BRR:.&R$8ha.rHt-SMVs9)p7K70X=W^Fj-*qn)Q224_X6HDO*;X*?Bg!cans-A4n2kmimZeG#+KQbrSk7R%.NU1g)>Wjs8Ji\eJt2^d+oTs&+VF*$'1@s6lmC3'Ip8V7V23N6W>jE0bXN[QbK:_,0K%-&NR9ao9AR&b[)OnOK)UPCLJ:i43mjsL1YQPe$,kMjOJfEh?hfHH>&0?8(dg%NGc'YWkMjR=gfs97VK)AJa!.>MSGQgZ;p]I4G4]d+T&/b&LrmB,(HI\LQi1:+*Vsf6H,oZI8TU$hjWg1kZ6l>$3h()lY'SUGhp/)D5_l_":J+8,L&<+YQ)-PY4*c9uZ;:371=8MZT\JlKSZE:XE,n)`VoK$D^ol(Qa2;6_StCbg?On-:a6jLt=1K=E5JST8%th3+S)O8+mqd1g+8,-slt%mPRN&*b3k/%J2u5D0m$I&4)4gl#FMA-Rm+Qn:`/LEO8X02fi6b.Ul$os\9j/RHTbAJFoMHu59#3n6HWkg,<9O(3)6`A0oSbSN1D2rO92JUcCe6*M"@Q*Z9iOYL'+mK,5nHRb&A;Lo+)eKu_?$:'"rbXkmYMjF17cIM*+U4cWETObfNso?k5rYOaF<6_a@bsDX,i$*4E+b3)Gqnue'&lc?P)5[)XTkGZ1]c!#VFY_oBok2C-ECa(Hm39tCW"qQr;+D[d(@qd5GoT(Q=NY5!^1e>1-lc!6u6hn8sk7_fD-Moq`>;FX7K=&6!.GrIme0[_LRdCHp$llo@PkcG7t7GLT7+tSc503pX>>[oT;*g)Sj#D&YHNY%boC!K2F<$=*ac@HT7D^i]i/;SP5E"$BtW>dS*3!'*E6NEfd=2@Mo/oQkb`5$*f?IX3r^'#YlPc4CVL9_EL2Y;'LjmdP>F*d7L=;-SHs?r?B4&h=VL!fZc,_WE[;7%.:r02MV#'s>G*]Y,`iC]_7>::%2g8,?55o\^cC*gm=l6?]An*F?78^a+[(O:Jpm+gdFWlGk#2Nas/!@_[6D!"(n.`2`Uq?J"1)F$d2)8Q-ok(sF1?+cKE*;Q(23Wa1Z??jl6B#a0gbk'>u%`7jZOG!S$`jK5Lh$i)Skk1*gqS.4%"@T>ik1>*=Q\e$F!`K-+b0E)pAo8FUVcA^`"raY\O[)rj2&$N<]0F<5J,N8TQTrTaKiQJSt6g=^,+M;,`GEC&U*BZ]V%<-`\?1J+%3:Jf^N[G^Ct]JauD)E1]biG$mdIDeCWd'WS5Q?&/M3sk-tT/cJDi+k/e4(`Qk4NWA1,dgN\7JUVCPjhXmMe*i!&De:C#qgd+pXP;b0O5,L+!TC\dn9Lg)FOrak3q6doFHnuVqC:5`!AaXF%%KDJ6*ul;jS2\md/?!STCn*N=#CL\QOiOC7I'%Z]X@+_*sc.W(uEGIQ]>ICSj2e":<;L`EPg%(,NloR7Z]H3GW?j#3RRRP%QI^N#>,YXR+,AHR1]LrIJYZL2]D/aC29>S0qGn>&1:32-s`gQecjF,)fGpYpVGgWTQ&tcDji:Mo8P[-$*7FSg`#;aLntt?)j?N9@>.p3aUHI^BJq9Qs&n.!:fr^Z;Pr7W>*-H@d7RJY,/G:DeRdho3VZTn'm`LTU#IUA9FA0%/`niq)9LCZjoX>0DdM6dta`eYo-#^G?$65IZ*Jrn6?3Ap.RTDZeI=E?91&Qp$[A65g&/I.eXPifFL2.GmomV*!^tBD>WJdVf!e:)'Li6C`T8#H[`P(AC/gd"c#BXR0*(We_cr)ShVR%uEh!5O0Hj=-*[kS_"(.\/mGBI6c12kd0Ql:%8L\i_tYK57ma6iM(fCDG1N+6YNbOm%]-!`aFC3nO.RrK\(.'r6Z9[gNB:YDj7DDpcYm5%$9\kA3+h'k@X[CoB:8(Gp?;i'K32bc!%Ktf``gd3bG]S9stE/YtENOYHQ))fsf@fAb5PnA[tEG^=B$_l&^_`-paf([W7DCQ4lV2Os%7k!Y\m2:dH22r-)ZH",H'sC7f7b5G=hU"NXR2!]Bgq?.]ADpkB@M,tgFnG^rt*]\@[G_I.b/G8K-*.W&,>..HJg+S4r@E_GD=VkcK%M;6VmAd0m*8.c'"h\WkScM5#O-ES85mSUp>KLb+;6QmhNerAH#T#.\Ig[DA[kCFmN$c\7[)(+3;M1i#E+e.AY6fF=YM)#Q13;d>)_lg`Z$o.RS%ZHd>-CFnHWM@C\\4fo&\T.]Qo,`Xt`%C=7Q56l$gVrQ"*E,@H`>Mo:p_Hn(QIX-4,/d(3;mp4n'ldmDNUbA(?q+oj71?9pTPH@Fl$R:*Oa_>]i'0s%H@7&W%kh1(dL`4JbJWb[e7k\ja=ad21F&&H3K'$2nd`i;G3cf4Y8CfG;C#^*bIQ'YR;/`Y$bA@WX.Q4E8eeN9tDb3bE^:@g!,6eUUS7fL@8f+-)mXm[b8AGj2DM8n@-mDlAoH-cdhc_UJV:ig9M@2%qsO]YSAX:m[qeQ%`#L/"t-!i4ksZQFBI&](2W?5FjsM?r(h@`E1<7X<--\[`QbPI(G!3"?5WZd#Rob_FFc7h1ZE2)]MTgdu4mB15l!qiU4c[4(%qB9$9)i_;aWb^q2pZKXQC[[kcA0bngD1.F$k&RN4PATb8tKV6R^C/^c?T0ZXlX6=]"oKQ)RirrP[EgAQfkgV+G"f3'%B/#or9t8/NYE;/jaZ$Np?DF6SCb+T].S,/9ouM,T\"'afDhYB-&&aofplep8TOa]u`r)a8$]>og`rm#bM,Tp/=#+Bu.MXZ([4a.6Qo6s;8Ws1DYH/A\mW,@scs7<$RRss]S8skg@e[=^[S#uYN?0:EC1fi(.(A8a%:W'X6Lt6[cKU^Ur^^J^VRstld?c5J#?;,.cY9fs&f]CULa[lfcl.fgjBO-sD2Ui^6%WXm[#>F8>/7'XOjCW.F9:^c3Z`GqTpPc[7KT&8mqQ:)iq:XlY/hh.[Y"sa,bEXNUMhpIS^SqslQZ307-Yd!Ydah$t9PVderp%SHZ=^ei'-tK'K,ltj^7=Hn9XF*:TgiOhHFpi788*D?AWZAA_^;@@D%^=.7`bt"9hrAGWfE^mW7>"^%[]8_H%!?t'd-)=Y`jF(E:kU&lO^URaq89em@QANFUlnDQDqpLpi=TV)9R(W@T9nd.#q0uF)G[A(P`0NM3H@r%a-p'V)p,M4ph9&e)cD-elb=l]"6!jHONpkl6T?[eEegg#eH':/<9)>PR%)Y$=lQc>,^deJO`Hr[^'b*U3op]ouQ#'OV[S;nkVK94YZWM$u!2P8X*SEt8Xd@UpP<`:Z7jBIOjm^jpF.fboW^uEG(c;N7l]&7CC*,IqKmB,geP.8J+c>kTZ>6AK&;m1]fXaG=hU0:3JkWuPG7)d5^TG%HC>`%hZf.\)@`]krAGVBom(/DHaI71=L/Wq,Ve9OXj+)mCJ?,gG$u0/QhK]]IZ+]q2sq*,stAh2_BCI+]]lH>qVdbA^pr&Mqkiid+^U9;pY,>V58Jme*p)JAX<#$1"$QV(d34*FU7ma!k[p=kJt@+.Z%Nuo96[CoUg*[b:I;]"cJ??C?MVU[E5luV#oOSrJ=<9'P4IWAoAHRbn^f4$E[ikZWkgH29a\&'@`==#B0a;egIM8(4be'>\7g\lI$5Ic/iS,UVGLgePmCEd4r\X6G>;^ZKGs%SlRuVr4Mn_>ZlEaW1pWW;AY)l9"Zt9.Hh83bSdYGc(4W@;dhY]d^P>ug+12IP4Q'[j"^)cQc30leUrp#?0G,EaO9\&NC76OS"jeVkL2r<;bD="u*].`4hS+5Ntc_m(UD5d82JPH)amkr^rNTm*UB+>X^QYg^XiXbU8lR:`1SFN26`0RO5Via4d].rnXSLW_];!sMR3gUQWCj9$Iq53+S(Qf/ic5F\(4^&a0B-6kQNYIT8ENK7#B>!>Sgf)Chl'g^?3qqV&dVFsTY"5+k712GaG/1.[SVMmiLcYrA.F=1ejU]jbOU.@VC5uJ+Ec*?lY?3;!E=opG5s4bL.eQuh2T]!eoI5cH\pCu7_oG>j6Cl"7C).8Y5&_Ep5NnALc"LUAJXSd&e%/;61/WE=j#T(cC5]r#-)Vr?AR&h-Vs.C.&Q:Q:.Z\jug!`XM-:oJGTqKi6T8`$bc@5(=9oYS02\*@OU:YG`4ref=Vi^+/>koQp'7n8o&!lU@e>4Oj,oPR(Qoa%L8;*9jEh&V(ghbp97diCl,2?Q7;4_MNV:04CR[FOrGb>l-UqkKtts>1c[aC)LO&RG@Xs^?B)KKUue$#h1"deL'P?+lYN-@UQl;>7GGA<,B*;);LR\N*1'd@3jh?fUF0fk(Y6Uk`qU%!QJ#1f[OcM39WOCO-?1?Np`VrODJ>EUI*d%,,21oFdmh?Ch/96]ig_1u_mQ\nCh1[u.`V3d]Yl<[ggQ&cL@R*[>EdIXBskiVOrE&+hpXQVQ&,k6Zq)i*E]$NRT,D>J>?.Ni:#kVH=0$9d;-(BPHAn?#h%L4K9HI.5jYs=Fn9rc+o9u@%8g1"q,!4]2Arg1"W$/$8gdZ-.hF(gTotS5*+fc<<1UuLX8rADh8!/d8Uo?4oIbbts/hBps`QEt?c0`IZ0@]+0d@W)R2kt#XI8(VYo/sZnViH"c>Y-b^KW?t#KQc21k;d>lBY:sI]EG8`ohDV&qX.pd+/96iQaG#.nEp-n[SunsGN`"W_"o3%6AI!A$UiY+#0:[Af_p>Z(Cg6-6@$%83[Y#d3?1[HC>(oq@TqeNWIAbGsWBI_&ULlic4)h'F,@*+>j[REVF/)K_,W:&C1Rbn0lA4[n^h0<82aOb%d&At)G^5RTK2*Cr47ghUc`[fI9rn]>5C,#k@qhBf7TMK[3UD^fEH]"P;KjjMathq<15/U]5/toJ>r/G2M3G<+g\XctYGaM`LII$g_JFbB,t#nuV=Vk_cr1D^NOY^KBsOtN(Wk)04&EK7cR3HcpGd;48ss5e/h*[5A7@:;b$=+CB\c>'Yr^/el>+^PgpPSSI]>=2,X2I;mAS&T#;0qZgC/2]4uK$#rS#PLT+:3D,$#9C?%uf(CTRd2p@<'tPM^5H6piIsq0i>B%K^C,A6JXPiU"=B+m"p]d'>bLc!$1<-78.7bf,;`.m;C@RB0/`6LK5r5/eoP:pdKslE-CIH[L@/r1.P@7$7>XY!FdD2Ok8*Kl9f$"%,QsO)4JW'NRgG"Q>'1d/0-6XOJYJkb7('(h,fZsC3*cg16F[BO;hM1![RgeX_t,`m=AD^]Lf9_l0;lJ^S`ohGhkH-7%[[lDPAuDA#ZT8d,t_i"L5UiqIlnDa=>,g\N'VkhG-Bu!'Hn;I8&3&K&OD^(IT.V'6af1X#6jOK@%SGqJJQUCrR9oCo=Is?i2/C!SG'!S#'+eW[#]b_Zr%CK`&rdbAJL[V7qmYh?Vt!=>orEa\#k5EIG975[Z-UaP"]?p,U5)N<=VNEpjLIR+N1JhCLioCc.A1;-oFYrNCA$g#(0m#n0:-%W#lSk>erj;ih2%@kk'HSpS28JPl9o\Ur`CO\hP%^V5[\.$hQ:G'TjcFEL-LuP",<1`ptjGEjd-g%=6WYY/mJn>c@4S\b37!$fC0_XK%nK#>Z35!:B$]#mHXUpGOaftY_rcoB_#"6D=BZPP!D"14Hrq!b;;3.o%b]h%WCsX7_dC1GqX>:Od!__gc^RLJ-!?r+)gp?N,T^2N)/%ZjK:L^sB.l[nrL6da0,CR/kAKlL+V\On>fO4FS[>H>Tho2>'q^\j1mP_[_XEbP7c;rV0q1lS#m5_iFf`t2?5dr4pJ34WK/*4K=RO1o/ogJ,WOD!4848qC<6/qp*FNqYEH&m.oM\'\>iVs%aHVoDE7ELmk(Us\=860HT<#"Ol%W.fGII65.dNA8Uqb=UNh0'8In#=sDcXMdB=YZ\l6,'>3h^1!Eq9J4GgEncUPVp@Qm'?JV$gidZ_c60sE;eK8DV#YYh`mU,<,>9:@0.#AN9k8hI@2&S&,je0X6>aII*4la'X_mB.(E=:A'.G`!5Y*!*a3:!o21ngq6%;?P'Vb#%NoN!9TGt"tXjY$EN.+P&Cp^Q&X?+<)4'Zl"uT*H4.+!2+==8BW9-@mo!)%W(10?D^A`'=+YF^uDQ%MBaa7Bp"V%=n^2gK12&DeXLT9_o[SL/;]f.Da4+#'7&dBDN3A(XEn@QRL;kBfQ4/=#G)7b=.GkXs2LV/]&[)VNYolesf);=tkN-938O@TJK5\B':WsD*\Fm3@[^IUs1b>kl_^'E6&0VX]l=H8m+,3T-SgV]93)OB^:Ctm[mqc$;eEP.eiZ9G=j[2F4E):"S]14#(:*iHn\fJrT'WdfPW'/b#6I^^"AORt/5>T\fPZ0;4_:^!.:FiZrUHj.`,=,\+gP_?iXq!%SK6"?NN=u,>Il\X"]RIA7s6Ap&,r_0n6dTW72+48*IFZceHEf,D*j4Cpl\HSsLB+A`3"[m^ZGn%OFI\$8<`c.XeM'ZQ!h"8)A3?t,7kG,U9tCB\q?jUD?$WQsh"a.^JsZ,E?p%hihs9INO0m,BYD5,La44W`JKdsl;uWF%6,%50LnU.V&rJ1K1F*hFb*bH#@A^-"N8+3?Id/-T-*MSFP*5+Q85_1Dm>S+"nn\L87b_f>+C0M!B?>4e?QYcg+5fQinriFb.dETXVI,$35XDES6[IeoT-fHm#.W&N=059gojM!51C%=2*gp`FK"_*dima804qTj!']eO"s4`&^7Q"Ga>ZiVd\[1o,8sgNdGIR;U>dh`"_$*Z7GY?_HQga^q?i)u!Q>l7b[#M!phcUQ*APQ3N_58Er_o>ucJ1mYpPZBsPgFelc`L0c?0f1/-G8b`GNHQY)QRm'ea'$f`OUm:9<$>W)Zg"QIM1s>.t*t@W#5:X@UV,S[3W9b9p3.GqJG-b8TO*lT3C6<6Mt%Q0GA,hY%:V&odf+Wd3/?&sg#NP%n)uC$TK7'TMlgHEA$D(&$$D0M$UB/K[Y)hLMERCh/L1QNBIIq)N_>H((TP1Kr'@f3JK@EQtScK2a'XXWlPE\3_c6ZEpe8oQ<&n#32L(;H:?@H7qmY-2;si?F?Qt2L0@"?:))@CRW(FQA7CcD2J.-V;OF=K\^&\C85m4q[Tja#Z7DtC.QpXU6+1"a=)D3o".CX.<#\o,VBP>!1q6^tB$iGLpm9(mRN]S,W/ci*7p@dt/c)%'pRM$K_0RV\01K*6d:T;80:!R]k,a"SC#/4JMijMc32iARj2L[h^#Q;"AW`8Miu]SV%:\AcrAU.bKr`Kse@sI2D!*mKkt=W`7#:h^.:BCro.\]ir^IXW5#A;3ji!QdCQ0uP)&lXUMc#Z*4,'uNhA;a9[&8:St;O*gN=klq\qr=LCJZAm3V'GH0\)5/+fmC1cPHn3JiK^,jjiL`L)k?&B"b\79[n>ae'HF,TEQBn_5phT\0)O"mHJ$VAk1?u'(4&)Oo$TkLM,#g^-a%ARk!=>XF5c<;g_aR)/<&LrZ;9tKFiq:1mVt)YZI-8_A@\h%2'UQgkVm@0nX>5"7trS-q>?_!Y",!URjBAWnc6,10X4N2sWT%HT:.,SKKeliqN&1VV'G'0'SkeLOTa`@tn:A0C?r4lnZ_811muKl#ZKeh2"O0R>m/Z,8-$%.%.2ReWVL!%n+)&M^!#JD%1S]-7YJrB@E@g3+tKL9N%]h7IS.7P>R^_GTMp?%*>c2j?^blPifb3=t7l\U:a?pEI'eVO;`p@FsJCgde$<;!M\"AW:-GFU"blFQ)ra-ogSUUug*OY+nF,kr>06D^('d4L\L+rqhf%]/@6Bb837oLE+CS@apX@-D%5KB0"\RrWHG?[Ce(d7VpuFMr3TbMc'9F6qcF==V;f>B6?g;108:9[>:Hc;L`m&Y>kPBr.R4:a2qH."=Uf:@(X&?d&#Q3fc1!*LpcQ4c)8UoU#^=2AcSLrHl1cqVo6pn@e*p@@8/>";Wo!dr28J_DW3AC^4Xhd`4Ir5X<>1<'[,:.Boi-12aSFk!n=G(MKG.6c=O7SWDVV5_hV>/q,iUT&SP%\RPdZu$%jrDWe$YC`.?n[):6FPqJ^hDRtu\M\Ea\Qrh[aX[QR'PP;rK%#n[*11=Jf*h.a"Wh2Ga*jtijd:4=W(OK-tD8N&u3=YSS%VTc.!c>tW*'M0S+:R5Oe;1(;dQ+s/?oC'SXd2g!DRksSsTQ4Ki(5bqcB)\Z9%K5HPcW;2.UJ9LsT?)2T2Y"_1qd2b9+_;.+s0BOI]X5'*4L:]q:3U[MM8U8@8coHn'Z[,U614!u`,4Y))#Iatf""n/>S3WG?DVo>7bdpL;Ug@)KQFD2U>JD'^I%mJr5#)%>!r6RCa`bRcnH,u:6"C1t"\%r)5ED=8JBnS1tH9LHBK8L&mIQIlPGW,*-R++q=!]uhAqCp-&o!/_0\FDKUe4=G&^?:;-*R/50VR1J"-e.F<=O#Cc3uTPsXiS-rm.;kMD;s-,LB=;ERj)[IN$&bp;l[?(b&!@Xdp`6XfE-bD1Flh[`?qe*GPT\.1-Raq>^7gj+O6Sf&,,U.&&2:ZgAWEOs^o7K9'n7D2<2;P>m`>M3_N<]`L_!tAM=qGJn,-uIFq`oqd"$Q41p..O*(=Qh5k.S='n`AC]]"B'^VeesRIAM>AYPSG/`Ck?(#+]M;+WkRT52.jIdfJLU:[O7m52e&UL[hV:0&7mAR[`C-WHl'@oqhfsMqYItnZ#rK0C(L1l[3E`/"7Bh\m*Ba(A#^uH.66X=)-Z5E06(aIeP;;2XkfDd8@bRhsG?1Ds5%Z8WuSi!D864'-+d\^_]UqOd2fn`9iJtA(HKTpemKRHXXSU-(4jIHD"nodoA(r9Db@_>V0"is@`PmTd?MIO8B2\@F!*_YHo_ItW>T&a*YA3l,MEp>MUDV@_<(tjlL3]C08.o`r2Y,LRp[.L?<@mqV.`$U3(Y6\(V/rriCV%#6Hf6R5`BK[RS[PR45H:Glhc)0f+Ggj%>%$=[hP2VU^s\[0Zeiu/bZ9n:?aR#p/tL&ktpHYEp5X9+"7D-?m#@b0hY\,rMQo\j#0Sr5[lR((<[YA5l.M6]@mNRXRRG7YGb8k%ABp$&[3,!Qs=U+WLDQB;_q6I"Ai(>&Id1pfpKP4=9c'/W[5_52Orlh0smW@14R'"OWsHAG*,*_4@h^XcCXY(O6M##$]=(2S_H1ZMlkMhcLnD!(c(IVYX\+HSXSMn->%OQB"](c3&5=_@cCfEQ.FsW'e5(`*/%!$+iJ3Z._Lsp+dMZ:c9d`B!VhVY!&[--+F/FCD>G4[j&-R"JZRSmhT*:c@N5^ck9s!d8)-cA\MLQ9MF_Ru\7Ta[K-.0d5)J*',bR8`$a@rdJ2i1Q7i1a$a1UJI3`."k"ja4Ci)\eF_,@>T?f9fd;#+([1,KNsJ#m>i6P)&C&&d/8c3Ftq?MXBk8\A)GprNK!0BMLqjubLVP,o,()CbUIm,2(C]p*;+[!IZp',utdY>`]'Y[A=c./g4[n?gjM4#1]I!tL&.E_:6,FB(9gf8fDcWZSQB'X-NqhI#*(._MJNBDU`g*IkP&fD<(fY5d1Uk/k6JDT(iq]L.5:<8U%A8I%M9"[U'UOjF0_"kW\HdFe.+rQpT,,K#@;EsTXJ<;5T3]ss[:NQ[OI2#[.fZ[dg[[+(O/j0,oh;S5qO4fZNHh5itEGnY%B]8:TJj(Kpq>B+b0?NY\?fT5Wk1rG/Ms3HUXPiD-#JZ5NcSRj5#Cg.%ar6ZFIh,qqpiie#P!8J@RLhN!@]>nAR-FXI_D;F$;uNfn!Ur[k8FarrWlt1TJ1fSL[Y23E-TF85p/No7BqB&s*Ltu$lVpG5\,N4@hB"[dZf^p!>#hl6Bots.7FC@'JMgNIl_R^@45$G_C3qH+!c>bDE>3+dR-)*(b$bo5gcE\(_==i1%6*78Zp9("QsFZTm2]Uo>>Gdr;GhnGRI]"&FVfitb@"%qbhdgO"qL#o5"bZb^5B!-OVTYcp1pm8uBCYTV2Ys9GRK&SX55skt?hRY]/+[8i$fh.Lg%F_1:=4>gJTN+?aofag@sXs1XF7ke)JBt]sMVVX[Cse]Q*B1ei1%>k]H":^J-ihfKM5qp'4oRJ'4*iBRUQN&o=<4_f$$/[Vs+Ih:5#^QOhc15B4TnI/f>k`dSmZq0l>9I=-34V[f0oSmQ^/r[WDANIGg:J"Pj"2%4s]rgEd6O5DTPHK_Ik^UNoas#*BD/b8(*`cJ`=i\*BA1:<`14KY5tM-KOrdCtq?'Ddc"pFs@SbI+F:c/%W`1kS\?AqpCi3dJr@1Os"H)/G"#%YbjhfIse2^TVucCO`M]e)AltIG;:\jRm>$ja$Ys=29G*O+XnB[)&=4=;8CQ,,0g#^I6q`Hsg4oi5P%_U]Df_U3&Z:$f#ef60N84S,/BZUZUS;r?[Z5+mt`q5DH?'[7E*cmHMhS`a9OprEiX0e]FTQn+]'J*CWbU6.&TEBt:^TQZ2[Vm$YA.pG)TD:TEpIGM?K%o;C*`H#duumG%*El$`Q'c@%fNdp*tbiHNjMTrM)p0_"[]8DX)#H?/qQ)r^>mSJf^\h[DA:[=/R1U,AM;:%?lR5hrp#DEMFV`K(N`HG^Qgq@AAGH@\B;_h6.>T$]oYAu<.h?_cA*8(H\p^5na*`RUZqX7p9h@lmK$juTdDp36NX;pY;9h>7,:@ma$fkPgS(EB[`e]1JTgS9pn#E?n=)NuH=ZnA>Yb_Ju%m0oYSuSIP2ACY+Z#0>>k=lFtrj+1<-c^iVN-p")8]A"[d-HbBtL,L3\.kEo$='<'CIt*JSO9_HS(OR6;K'Bl#H>;WQ]kd*86%[9?<$4mga2UK@?jnb[_(`;3%1G\VKt[CGRNh@e;Oh^\;:LLXK3^Oqh5rlt\Qnt07Xc+S;IOjH2iFtrZ$;=*+`5n1"ue*3lUp)f5UcAT;__5bc:Ia's..@OunA:ordh&[Y&A,-#[nE^"7mEG3pp=%Xl>(CVWl=7fG)(ojrn#re;mnZcQ^P%$%4jiBQS-`c0_7P$-N@hj,r.bQ`/fMQ!LUn>9 "cL>tj[h/mP4e+]K0IgrB(IrBl/X6'*HVNRI`cW?-jqRe%>>'#%>B)569esGH;%LJK7ng)'(K:-@2\O;qWqY8`LSFtVIbGP5nl@5/3CC\col**_u)5K"jn*5%="9[r\IZVFD/Kl1=U4=+blL^)`5iW\.gN36u8a*lOjMN/8]W&3rP18%C?sL*NG&@'M>AA0&4(^SgZu?cZ`c#P%X3g)nG.hO^/8DrI:UT"jnLHdAV]G^h[8olg6s;&]IV&4H5er?mB2s!3)pV5o[@r'+5S0"rFT\'OQG^Ba)rlg$NE,P<%+(\:%eY<;87I5l7r>5:TgjM@?)@K.n>ns$kXCVEo:\XnQrbl>d9HN%^@*+^@Q@,1DrY3iT!Z`1XtlM:=l5Bf#,Qks3)=odPr*Mt'RZf:[sk.8an[1seYkNC%C'@2u-^Kj$,`?KDqR#*:sZ;[+bpJ#2+rf!AUn+L*/FQ^,&YB*ni?["-35"G,;1&EgiH[Ha'*lh:Y>$4&(*;r(H]'%PqhsC$K8c8;ZO0@624O:72h`nI=3BtK4e!op@gYMMJfBJ:@Y'8GC%YL[W+M@$KcVM:aH*d!U>k-pIL(Ib6a>f\f$=5-E"7Q.\N41DW@blSB`EkU^*^1VidLj.J`2IKj#Rm4m7)m;tRg[PnJ2Du?l`hr-3UD!6%aT?A34/QBbNSB`U8gslFL_[WJb#uSjE05#,BBg;^*!:OC125iFI;m@ps`JW15+Z."poAP17"(/!sh7>To)Z5AUfrDc4nYoW^LRd!A,#\)g@fkFW8VN*:4t:4cK)/R)P&Z/Z>mg.Z29Va.=8pXQ^CYjMU;q]Rd?-j]f4KhG,<>P^88F-!,r^@khTgLp83BUD+:g7H$q6JP>N`6j);q%`@WL\;`j!'d-s:_*OsFg-0u5pKl72P2?K,SQk(NC]&[1ICH,No>1A=B'K/nIp5f^[;_2lqEC#;blf6ogtY8+=k"Ug&$472K,oRG+.VY=)K7F%=UDD5U\!aHrt\tdhkneV/0P;[\)2c85','2\FgBq$(7B52K$#%SRq%Kooea_7V$S`Qq5Y_op1^;6aoN.mDhC[S/T.[obi.CaX`X`q6-Y9@]Nn]O=8rDj`PLFi,D>dnWaO0X0ud-\Jq`O5TQ0C/*$d?ej#^V8DPcc5r(^TGH=qaS`]Bb>mTg7of&%-Rt,9ahj[k;[A,kVEdF2kQ/RK;LRN&SstP]M"HRaNrCb2pO9RuS%!=b+lE8Po[1,-ODc.7]?,;Kd\0%)k[?!K@/0IKLa^eL9/6o;q1\JHY'^eA$;c3LQ3;I7Sle=0"hL2!;Gi9]2PcofJp/V&,P3"2Re+i#pX&,CcS7>;hhuP]GhC)YYGna&5,S1df[p"GB%,MIM"rogYPPs`T=6R8c5j71Rd3bQlD/QNYK[=FGLC/;n`j+SQe3Ja(dVN_(@V?,k9LitsELSrO,P4%V9a)DL[^_;o@jf8Ohm22[ANC-jEff8S`q#D#'3df5B`%j@,.*-pT&5tsaFHT(P3M24=h*rIiCHBSJ+EKg.$\$ROd@)5,#p.3+#SA>)"+/cNJQd:j=,X(lPhqlsZfbPEUqF*%4@#f>\]k_fu^#``XYNhBHm,AV]4)EWefZPd>V%f)oLO.naI\aK<)J4/OYjdo?Q^&ULOL,6FW6aHTdSPB?Bc+UHd"anC[D\BAi\K(p&/a/R$j(B@4'9>lGIoAGLI.9uY021&#[f]bB<;%O]5]&Ui$ur)4sF+2$cQ;6;_`B'`EA%SCuHroH^c!nPAW\X-@XE`[)3oB?u5obX5P[a'-41/#n,):Ccs+@!<'eXSk!HY:HQK4e[lj7'Zp;pHse21IelucGiB+1YVfuEG_XX5o:7V_Btj!q8Q]ja"R)r58q\a@e`s,?if(*1]@inaL5Zqb1u&KfkA1LB7Ykh\2`p\u_eGI*1)U(0l;FWV5JBgIPj7in61_K/27r^$*`U74Y(E/m)GVJkQHdHaB6Wjo[D,d6lfN6DVdnmO!6i9r7>cbABtCS!MmrdAu9Na?ZP9kZD2?;6O73E'f2iML4t46nE??#Nmm3WucmcPdNH@^i-N>.N;.,n6p5d;:X2DZ5fUNEP!u[q5lD*^bo;::Pshh6-PF\X\D9CQlSm,Y_?5OduY2,au!@;pAXPr;45kSpBCeI,7Z.Tm,;D<_uMZilq(J_i2fLB2qA[X\'YV)X"7D?'=FbNSAdGI(VqDf,PZR>Vi7)Ra!g7<4sqiL2,;M;kJt;K/^WShQhc8X9s&;*HZGIg[S:XCFN*@='W1U=aO]/.u_c6D-#;9qE?uBLFmZ*61Sek>1'91G@tQ7f[0^=#%rg^Jq2/UPpQcf,U6!9l\Hc=.?:-]Gt1VE?`pl=B3eEZRkt\/NL"0[%Q\%=g-^1N3or!?ouJG+1un#&Cnth0[5%Z%*^:fq:HlHN@jXhR8,ac&'%b?W?68509j;WUo[[sOV&O$BictCfYiH-Xn3-L39r:NU[o4IgUo+HT$DPn9.k.#+RJr+%KZ-P0\89&H$e2HI-uA-6K3AK:j"n=AnY9fi6]e>7AA7:-9(];3qmbL8\6]Y;lH1dYR:1hh3&a?sUWN7K9k+U2YP!ikruq((SajP92-0Wj;Ej`$CsA)Z#95U4Um&rgKDT5mMnh1oeiVT77tWNGO.D+/"AmDHRhp6^GHF'=:nqA>l-%fb/gM4uJU5S9Ys-.L4VM.eUO2Jo?HT(SpUoOt:MS-5$f(pnVBJu10XZJ+_$Di3Kr+N?FJAS9S\gAQe.Fj9AaHU6d:Lqdi=^s7jZWKC`,J5mh!gSMbmA;aE4H9lt8K^2K7j@;G#IgX!\eS:*cES#&`f&qIUT7bD`plK>FOUQ9'"dG`4ZLU5Pm4*#RHLFS=@I8a;b\c*-mOCZ#YcHE0rC/?OYg<>4%'tU&b]DP:iap[XYSf#I$pGIJqiC3.:b%lc[ZZ8US`]J^ukkV`:*B["TEa%"WSHNo(Rl?`te-#7i_2+*eHcP+L>BTb0XOsNYA_eIKE@k6EQLLrhTX?#t,B(S$JZXo^F/5>(,jJ;4+8Y;!FQOk_F^7;A2i^VR](V3)IU^=;2+6Hm5!k0:6`Dd)U$l"^:QDZ^a`po"JA(e!t2Tl`K>&fj!ELWCSL<]mGdkn8&W=J:9O:NL0Kh41u4QdbbL7baos&H;._]ija=t_VE:/@7[:/QhKo:+!HY"^jf.HXE:W+S5H.U+)uMQ7*[Y[\ET,)S!7g=?'M`ELJ"<2_:ldaGA(-^en`m`hq*+0JcuN*?cA>*Wdd5sVi5efT7q(mLqIRB#fBH.DWbj+cZY:?J,924.p8=.;2%G3>d8/?_H&71?EibfbsCRonC>2MLlI&XL_Sk>Z,=J^%2nTj(ASj\'B2+W(a;;'O=A2S:W7-PuUblMa4ccq<.4e]30$m2W`-:aON(NEQ;;'4e*eOnh'TYhD*uSgVYD;2GWY82>]Nghc;7)`2/`SB88!QYX$o%_.+7h`h@pqlH]r>nQM#`YKt%?D#991PF#_TCg;cFFSXoQ1tr$-%]KZi?H#=(iG'jT>4Qtqf7>uiW63&[Xc1?%^VV\\S[bWJ4R]F#"I,qD6X].%dVI$?$btFo[qK[JWPr1S,ClhM%jVRBejXm9ej$(1P-[9Kk%\n]A_QH5BD9DGi>4(O8p/qc,<3#sWoB:[kW*L.(/4MuTb%*W2Z\l*>\LLA%e#oM*MmuDQ*[cJ8*)Z39H16@SjPs-1%2Ia))\'[/:?o8q=Nh#)4W9#f$7XQ]B''8c6,Kl:^@3ahq)B#hGe2:BS]m<@'h(@g,OA/rW7jWH1p2H8o]F)i\St%NRU6=CJl+ScB7#IIWkBU+]%R3B'G&rWQSM(YBQ]dCIor;7FWe;RB0;T^QB4PUXKQG8rW7cqVc)oC6C-@'42GePQ[?c"](=]0]b:)O?;2!YgE?4jqf&RNK1YrUS@PbG\c:)F!>1h#Pm9_fXX!I5Y3,Y%)hd!MA[,IJn>:pHBQM792Dmi"$::jM:\!3$b'6V4_QQqcgR^LXu=glKdn$J?@:TA!4cU@Dh.8P@@>.X2]=-:Zj,*d#'rp*-&Mt)X'>tF9Q0f?&Wkp0-g]*P@>:>1kj'D@h3-R?U2D]HkUq\"I=@U$q"[:iK2&t#&s@aGdT#tArYJPip6Tap'M)nhJu5LV1uL.uP'\[HVO=Cm]2$Uc/9hq>"Zoh=X-oG1&1lCA$'nMTV#kfng]jd@1>T!H+8=+eqGG3HLB?;&bF-8X[!)L'Bp!>_([n_A;3YG9N\3b\&*8`h4darq()AnH&Q=dAu+.0&_`djh6R4!j^SC2j3nK*nPu@ZrbK6SG)E-5HVh(AE]i73rKDP/Y$=+XNn,229T9DQUi>1;ogJ\jfgOM1[cSb%S=`33+VPEI8.dhi\ND^]X3to?aSV`H)Bj+Nc<'uom1jLf[&Be2X4;r;GR\6[Jp%cn+dQBMF\EKo!/VgV[9V]L2]5`#Q3NtkP\<5'81eg;ooDd\=^nd;n<;5.`RgAhEABXjho\^%Q$&E30:jUR72;&,bak6m6g:`8W\%oQl64QDAt*mG\h9Par0P=Q(TaT@\9^rq)J+8m`_L:5l#hNW[hD2P>KmW?qUp-g:8#m.o*9#C9B:1N>q7J6/HE-&J'#iFHZ)i^fq%B[IJtF09^hTW.N!dBYK$V4J^9amWp_B.>^78qNY>himBfmI]i0T.LG@AERW=Js"?BA@L&85rNGj?sYt+aINo/(:&>e76RrO\9+5)[[3913n=$T/KM$Zr&^fUPAYomHYojD3S;Ku`7NBa%D1D4\_k!rGZK_A56T@pO%p);.8CpG06+Vdp9VCQ;jq$@eGA`olPATmBtepmN?Lh`P>4m\hr?dBPAU)=fZ*3JpZ.B7W>GmcL7Sht$,_IMqeInMgQT(/D)At87@%jr9pJD"r,<['h660HL0!%[WCA6)d]qt&.MdVl@jG,_81hgC@%/s5i%!_C(O"A1^=-TQ71q7[2.d7]+Ra?)mXCF:tB>B7"hH6[2RJ6=8e.^^S*m6k@e";@qY6&"%n@>(3pdg@?(jT[lpSGK!/J7Q/Eu2ls[kUZC_]0GeefigbY!o27HZG_^-EEJh;/t^\_A:8Zf>]>=CM[c[;0//%22?MFW;a>I_k.$&8#ql'28Nk4g)\A[ka#q&s,.=bhB;.N9Q?,)WJ)ZEqtKQSagVS_Il],%\I@[ah8ZWZ=nL2A>UA3t=5AhL*`Va[hOh^7..,OUPFK&7be+2#N?cVr*WOI3V_)hErLXrcV*1-/N`.UnP&C8`WD:i=7nu9Z@bc>.?Q@a9>g0UD0?B[(XDl`[LZca8[dei7e].Rc*_!9s=ba4)8j'KASpf)N=[b*Ao=_3S^0%hlL(7O#`NI^?k^OXW7A#asSL6iRaBtX-*^0ONRr6RB_k"Pu_Zk;2Tc[_K6PH7#RHs;#<7e2COa>qIiP0tKfAl#ll,dRpX\*FLNo=k#Np]HV92j\JHrnre=DCj1,0Q9?S^(-7jV!Q!]VdnZUh@M,F6VH]ME,s[-t&<7u&56>mb]L.i!+>b4jNl7(.`I>SYNnfY&(`^FiX%4:=BP+!`Hsa&KnlLLsAn>h_3'`.@a7<@(V/t["=3s7ick%h\R*.jCn4"`Z/F;9Z^a4;VgLgpj+r:G0#tsbm*qXUK.s#*[]KF-Ts8Cd+>5aYAY]_\MP)pD"@:%d7]]D,i8asQ?AZf6TRBOM6tS`HbrXi7Dk=)-2sFsTt*A,)"?//c1/gQX'J;6f/)+X\"]M-5+b%SRMq0,+3H"s4Fp/g@eR[bZg%"q?UUD/D!"(Nq,J:9$_9$$]8!b7,D6<]k3Y"E:rSHTh-u$nBqJi=k-%R):'Nh@S9PqAd)e;tT5,aeH;^JGQsndIKG!Ijn;^Hh2`b8V;8hn/ZlFNDo[Oqj#nZ$9-+qWpiO/mh;a'Ai7LD?f"1+JA2:TYM,mP0,@&>1R%6gsq.u^))'^O[,j[Q@GDn`m>?h-Ak7<#d3phb=;\Y9a_PHB\I=$u?9b/:-r]E>jG@dl;Rm)-[Q"T:noX+i9Z%93gR/UO07u"^k=4r^lcMZ'fPGcXlSNdTOA+5KL"ZI+*1m;oqS7CcnQCm,nC^K43KT3D;>+9fN1HO?PR4B2I%.(g4d>F^__q)q]#_o>$C`/&B7*'r-Zlki6F&H&!$`@GA5aGFij.Sk7UddcdrNroGD2es@X[MAe=)^(7G9%>MYE)2*L[L7gbV:Tc"VX91rdL^NTSJ!B:-h)DASLQB:5D)C6Q]*Kn0[rRMRu)>=(_/=PC5+69qqnT%4VV4L+fjD++L<*PiX9-#o+2*m8Y/o[HMjb&(jF"'D^^H,sdD3(cs_sI#PRPnXV>dj\S/^F-G,!RXIgG>&+b<5.$OTn7*i`V]!6k\!1RRY7.-$GD?:(n[m,iFYV908ZVd0aH?J=]Bbj*:bPA[A=#"n"%"bIHUX\75b$e!P]ZYu]LaX(SM(K@W1(;k[&pJJ*>O2$5aR,'FI_Z.ub]+>%/)!KOOeN1&F+L_i_%s.M]p\FR=-;K7[S#<[MO:Hg70HoM"^U1Kqh4BD2>k1Z#PQn:\Z"+@*4tB>pUgP8K`#B1G1a[bYONEodK>r,MQ]dI/>*INfMfOs3?efX/C#nhs`Y0eoHT@No\3;Vd^e4Bqrr0taOS!$8E[=YM4HRUHAp8staQe='D0CZcj8RBTelMHLdMU@K9fb&"O6B_\-W%Y$0QBODod2!Y@]X)sjQ;n1AhRmuZ,EIY>=EUPm[4U3a-Nto#oaBBT4YAZ8:DNLTdr9/:1f`J9X:bU9bAAA.*f0RnZ?P10opArYFIJI0:I+`]Ok>ZrJiYl5Fu?9\\!RX.IIIO`ok8lNpi<<9G'JD.W2<+K.tZ:;RV[E,[=EHS_o>#RSu4p1Ld/=gkU4eCtP]/*KgQCiF@f>gWVb6!O>ZG46@;Q;_,cdZfApEKqhn3UdkYjJ@'`d?T'JBF%ZK%8U8l=fN*)aI2:.lbIY<%5i>ef\I3Y#0RH<\m8]hM)N]l1.[te-W$r7C+.Qoj+iC@0%o]t`hb#5@2$m]"jS%E]IAlSFD$+9n]_`rdC9KQc>5it?Z4&sMu_+o]E7a6$2R!AOU`]%Yr=5@'UDsR,VO>aL'NQZ)_A.g1U,H4M),]g:iHdYo5_.Cp?+gmm5c`T(R^&ae37EB>A`S"Y?Y`XV6obcUo-uH2.,1M"rnlhX5=q`b=&"@c_#OcWJ#0+69>&bC',b.fR-;Rn]@WY@+p&X4:OWg*.:Hona)A)OK9:c&B;Vp"ak:D'SE=(#RfQljgK?._Mn,8Yc7\XAIbtg+Z$cL8DL4..:A80%\+npAs?DY<+;Ud@ECS82Ua6HbH3+lCtjpi^M6&0fKZaRasW&n`WU/fokP*_6UnGJI1;8h-*lBa[le'<.jhLiB["*hQ@GVZ40OH%3)Q!bjd!Y3s?ob/sc(>pW-meV1r(_JsTg1j2+gO!]9GmR"nD*;sLbq"0P/M4EgDin$VT84ZNA8q5h4iS:Fc,&k=SaM#I7LY&>SV2N6]Tc4N@(u^HPd$5J2r"]r7jZ'OU/k\bHpd3al"Y$5AL^YA;Vp7pRs"3:K;uCdM<5md"hHrW70ha$qS-W5j[;lZ#CU&,fe(d-d[UX3'(qSU28$:[EM4Fi&FX2\o`9I#_F<%_3YY]&,N!c6IoP?q$N"i^@$s9a7$nRi^)/EX),u[PAU,q1-Bti[_1+"6e*@H@c(%BDjFK1D]Q=GOCf[)9DQ((erJuueL-&gm8e3ghpm0M\8S4-e,kmoW.ca11\,,]bn%I5@LMR3>ZKIQ5FWSTT&%^!V=W'm!\]phZrVMJMNdf:n+j2a0CgFnHJAG%nmH=/Xs+B)'Dt;J(8[^SE\e-??]g^K>[Jg6k4@jG27Oc\e]s86Ir4b#The9f]_IJPUcao7ANP-o@9A.q'asf(Dh\*'Leh/MA36!MnhkD*#j@u?'M[q'ccm=KMaqg-/T,(,ZJ0AK5`BEOj67sAk_n-`OoU6j2$O7h0H5IV%*Uc8`["t,\3?S=-#7gl2jEq&\1-a2CXY:[CYXo^KDRf0jq#5OOqTbd:UW.I2",#,&$\OBl0FC>JUSkO<\V@Gk#l5*O1WbiSBZ];2or@)Q7%R]b5>$in<65>FV,_%Z.$#jf),i$f.qkPX5q:lp$C_5E[.8Z#mGt*)Jo_ht5Uo^mm1"jDpU=XEst6q%;9;(umH"rV\]O+-XlAjFGQU$?MD%jqJZ;<5g@['J@5Y%O6QM:WGq5b9)H1VNU4kom#8a,,J8:pTiVrfme%mcNmh7d*E!2Rb;(&ed<-MDBJ8qloM@G[7P"24N-$=WTC@BULt%M%efC)`,:%%m5g]"om/O`%p0CVd!>ah7"l'Z0;Kab&J/&9Q]d:N_2ha##2.nh4Y_mtRLNrS:RQfQ%9sa#p.NPBB];/N(LMs@hY(\DTZCp!Z:20a?7%=(Z]]>o(a0,1m=@VpLgY9(PYPF,(i`>&qOp(k1VaFTf]q'tibXf"JR^iYV+UtXlj$b)[WI7e@8L`"B`XWp$&X#t$l!)3q57\r&n)#h9mgt!oZ;Yc/sOdaL[g9>^'m/3(WGPF'U2aa)t_.3b]@[R:!\G.ABc92Su63EE]H!2ap9dY'Z//X:]X!aJ\)lQ(bIi^)n>.=[%c@iJ]b@X%3Q0m]WlY"Q"O]>19eYISB@=3<'ub__.Zh*'GQ/?gL%VmIh"OM'>W35e(LrE\DVBU_MI1gBLqfKM"!47,ouj0T*c@n#B$RAThfKW[\V5IBs:mrmPsPNTqE[k+sl-UCZk1(*pV?]kMt]HTaTA=46U,jd*S/5d>ftn*KR6nM'u^ilnl//@PUSN8DjhE@]K,6X;`\J7'ol(cj;.qioG$DfI!MKV?u`M1E#=Wl3qeO(.BB8p";9hK[E^.=@WdJE1&>35([6>Dl%t%j36YC0BgDFSG\10l?aT54nON.D`$9qfKe\Sft%M09\A>"f'88jb,ZEL"IOfG%5a;C*^Fgh8mdJaFEE*DM0q-4$O/FBT]6c1:G]U$Z0-G[nkQ=KZGAt3_RPLF)qPj%AF]=fX-^f+/&j!E?ZS<_HYB"WX#Q*.rTiB-[^_E".@Lf->"R_fFf%OTu!N\q4;Sh0Oai%MP+dmkVg^Di0hnlL,EQSJ_D:9A!p4.E_jO]d"YpenM%ljblDfpT-S$"O!-1r8rRKVA.dO>pcA)eiU9`ndSTOV!$BaGJT8i6tONd=GY?:.p+8XMh@HSMLJnXN"%nA#d,o\iVafFufkZbu2_f4U!-[.EL)ERAN2E_#-r]`#>3ehR.>m_@j4\Vfb%)h`6NY"'PTs3aeJ69.2cYs%/Z*58ce04NS'S8`!Ij]4:F]@>!:r&/F_`[ERV0a:pR^8_]3M\YU"/3nW8\"Tg3Xulb#5K5P%%1d`/)oY%A89pI4>KG70/#BS*cS)E4JY$F7*o@s!9Odp$B0R.cc=ng,ic[&%h7]RGB&dtG,h>f+I2#(AA4g)TMhP%)EBPXSECELYMSWpr$ermI1/'aNQZUK8DCsNPfL%7@85IM&;PT@6mF\O[Tm^)BUOHY/9@[Z`+]U.c3fa$*Q1Q8t(TU6Uuq005Q,kW9dV^f7B;f.pbU1f('B%\l8e[Om7ir6%u?Dc=bX0[7H`5lu=A?0371lVu\C=F(i=aYU:[t3eWPV]a,=T[X:Q6UZqh#\54Pc01q+YQ@5q7ggNZi+Oeqq(iIk.:N`Y"9KuQS0bY=&Z6V[O(h4rnLKc3+(?Pe+U*tJ*7JU&#p=N5U-&Q?FX#6s"4F]VqeRBP)N]9FLG$"%cQn/1b'mF>;@[da!FYFm0S2-0Fb"+:i#Up^,IUk/ZWrcqt\=rj[,%GJX-f&ep[_qfQcLr'&o;!t6fNg`g+=,TkKI$M1*I6H1?=`[gG0O]A2Lt"Ts!50JVtRq>CJKLRV\O.2_k:1IFFSU[#,ita?aP-H]oATj/#qJ,cW1_%RI>:ckno>4ZH$R?MZO%*(8AC4KD1.VM&bI!X_3M/22bMKWO"SsC/49g1`sQj76>g;>h=Sr;aWCCZW&FQ4fSFihr+D`o`%Fe/1g?2ch/-CkY1W80UkqPMq/K\OlrGiG$gL)a>(q]2B\!'RR'+-bqkm'uRtlVX"oCP*%_0<9h00]EVDK1Be]XFpH+i%9k8P=7F7=YbK]Iot+Bgi)]d'3j,GF^/]SEV*=rN05^/`:4i[APT/MaRMFujJ/de?HXk+OTg#/fIS&db8/!]<3C<'MJdKdYkr`6mu=PcHiPm%jURresdBgI`LlK@-ao27khrPNfH-ike(J^VX^XQmqQIO4gCP]e*sLKiim!(j65I>X1-Tlb#$ts0/dG8LJjHP=b7]+g_drQ1Y7sCN+(Y!].8fS$eZ$18\d_*gGR$OB0\(QjQ3uHN*M+g+"/<-8?F'uAFi!bM'-OInWnJ_k`4k;2uuc[N=0"7]2a_6lR\Vac]%8ZB[LkJ;FAp1*CR!Dqf?SL.&i1aJ4>XKK!tZ^0%/5G'bco;-97j7T'PlAlBdgp):i'sVi.b)?kq2*2:\MQ8\+3j/0Y;Wal\bU2cLK!T\LTM^nYkc8GQU2RO)qG;jl"KhtiqLNm9Y^2ZXPA"DZSd5n_:9Hb4^8uNkYkWG&>S*)Wfhp^j%LNS3U6/Yk<;nV965T:/lhi4-AB.ZpR&WXM&8<*\FnT#fG&?\q@@Qfh9?LN;lP9WU<@=UT1"s8sbO3\ac-=LVa_((?'MW82MGe?$IAi`monPD*!WTAV%CHL2@Yp5\W8@r:u_.E:ol^7%Cfa-/_d'=!NupM9PVr=2,KffITR6'MSsY[j#!G's/]arq0pWlB0[Nq<*.Lf!E&6]X]Jm[7Nh5];jWKS\@9n@(>NT;BsLF9<'LsjQ].sb#M(@G>t-enWdge@8*<2_0gOb].iSaH+_eH\"eq)odXqF^?&hZHiu#r$J,5$CQ0`Xqg:=^aH67-R5jZ+bS"&%h*P!:1&3D36&9tIBE&!L>YL>EVigm58>r=.SFYVA^Ki0SSA;F3OA%]`A)V?Ma\8gspC:=^PYJf4Xs/NN73*[^bY@lD_8b%oU5M-@b=S$!$kUt?O(snMgnlVpI(nS7l\!!=@Z2.Z;P?'db_[9Q=EcR5g8^L0qjaeS$_=qc'PC0_1Br)F='/GoWhV[0;L73*)NqV3J$M_U\\+cgLP[S@bB_CT9d^@TlO/I[7_9?Dt[`k@r@OXNBk7iF9A-<0_#)]W=dS)3KMP3i)OVa_Da8rk%-Lo[aW)@$/EFT\X1C_;rDi91#1\fIL=@TGRW]c6Le9seO;"Hq#4_s`5qiu\AXMCmdN\%LeH^d)S5b='sg0Q>.?b-o_F*&2E'#ZDaAA!Ut+Vd6<:"g>/;"eYVuerr$eP5T!6\%ci)9&H3LQHcG.UXl2m/9M=q]DZ#7GZ/MW(M77s'mP;`9L27tDjrOV*6T0i@4,><\_(-6&bi0YPSfA)4(pmTOCknksYP#I@NQkH7X.5Uckcqn#V&5dFr#*^*-B!oN"1b)hMI\%O4!(kpK:2&=GPHK(ba8T)Rs-=/il)#CUaULr^O*:FnZ,bRPbC]M3j7-R?:AhfSr6-bR3Hiu%+A&e#$lFsmkXEq6l"XOf*!+KAHEZ!603Z"ldF'0hkd#V\oQ4t\PgfK*fNI%XE_d-*@dq6OQafdAWZok8qs)fRsFDOP&kC%3uKD66232h00Jsq'68QS#*.XHKmr)Hl\OPDPk]*QnHYpM.KJ!d_u`=MeZVbN?D3?2#*j*Q/+XOKqj/oKVtX.0qQbIROMfp1^+J/f.qIbt=aNB3]2\.G"oX0iAe=pX+!GW#P,NuRf/IC)S39J6*R,l&&m?76>pB1Yf<2NB6o"6oo50UZFWrs.LDibl2HSTY9N&9DVsj(('4)F4D<[C^N^]Vm)%$a!gcA`>WVgM(o6(.%9Vof6\8bh)5a[0UO/3&FT]87L(cnafD1::j1/14%15bE41*@VZ_dW=pYqh^ILD_5oJQ&Ln1C!MV%aK1qIHd^>fc(XBm-0H,r*IW3XuU+!LS#B:PWka@p;$9XN;Z;$Bd(JtuNb*AQ]&(Yu'oXR`P5l=s)TP$F;EE_2m!YbRaeaaI%\=4Po6pN%aa1;2\11P/=30,MBqaj-rED]AGs4QV.k5nNG*aA&as2fbrHuimb6B/FB@<)U!6mImE*0RQ";int76Yr_eg-,g;WI->7A+f"EaMN06W^P+U,G4elFEF"iXtGMg`R/A+DY7,YVB<_*Q6Y-NZNqTn2;/MJXO)lspN[&=ESU,>uW3Uq]J*rG^E.&rI=QK.S!MN>jiK*ITmBkYN.Jb8(Fo@+h+ia+Em!hD_=lNN^c.\IC`7[n7loak)s:bt7LcAXJ+U9pF56&O8N5H*UkOf3T34?f8#'CfE3-o7p`%C"bkmUK?GrX/9nrQcnrZs6rCigiDSa4mF%6?Se0UP#B6,f!AmZ.bepc@8I\Jip'dB(E]c3)fckF832+(,J[E>t<1plDYrSI$!MGO*ct8(PHR1OHl@aJ:Y;km!o9:&]4qO7G-kj%s^5Znii&q4AjO/fc?BUj/(ML64W9#3b88Zh?RRrVN?/D778O.+uD#e<['#-dVBiOa*rM35Ak9(h)AQ*PY*gqgM+S:o[YE"`HBa9_e)e-0)aHoe[Ca5lI468DcHQX,hi?`i#UBc&*Fc;U/NFU*9#tLe8aKI%\?0,ANhK_Eln8F`*.*3o0i>"hXBGX(F3!%"S#.s@IAWq3]-tM-JK]I>X3tDD[4DCRPDC#ulLB&#dN"Z5d!%;#B$Z^fom)6L`GBBHY#]fW*k<4Yk_@M=dHtD5^jsDJhqq3(DBCg4#D?A]p=AS[?YNL,c[\IkDi-s,IrRA,;V/t"Z"FWRI0l8$aZd%=3A6h70hP4bScA`kbosXTWQt*eE0]iP:Kul1X:.'_%IkjeUC7%R7;7YJQHGZ@HB9unc_2ucc-"0\KoDO-Ll0a#8bM=\LrH\&F9eDF4lS\A6Hi.*8o&Z?R"Yr@0ZD>oo]*R.8`9j+4OmtK>pMm6AZOO[*BVjUY14nU)6o3rNcAlMYZ)o_6CB44l"A'+(aRbVHE:#knmIbrbbX_9d&:\YL3_f1tgTf@*D6nWI'ZnlJL_G#(\5"4bRlmRDib:M69Y\nYVT!CTaoVeYT_TIJg7u-Bg(FsOj!mG.g8OB'WG6RD\6+?+rEikgmQQ*pcK,\jOj*(3_B_^oP-.e2;Up9Ed9AkTP=QbJn*NEjuU_9\b'59PG'l9?-`*)#Pe@:3I#6_HsI8c6ET;$[%I9o+$>\op6b#(pfGrL*bS_$E7`Sr3mG5D0R*D.?%e^r(Y7kLcE)A99V`HOrsc)Ooo7^`_W4P+M8X:\H9OMI)Zgkh^<.7"nX8H:B#434P4'qmL$Z/a.E"`il$#BKI4Vk*::_O=_Nn$FR#&?$V=H)RfGTp=NZ^KO'f'5W%0f(Q"h"1qtot\n`2M\D;+F[9HZ><'G6_p)48OMKO*"8=!Nb(hLVDKD[6Kk]3m19(MM3EIFJKcWTC]Xp51kbug?]4,&$>B%b!43el"n`rZ)9nIkBuY?2:>eaF2*251PpF(9AGt/7hTn/c0bTT,mo*O>b(Hk2n4c?Ij[^^`_k"9H"t2c+cF6pJP8.B:%%.[d';?:\K,b4JC-3OJnnE8JYq[Y"WTO=+WcBOQnk01Oq1WHKtPp=?23bk\R.BCD9ZS@$I:3bcBcmc"NDG-q4r!`>o@*@GKDBLhO5g04(GUjj;^BQW#n)/]8ot$2PVJ)YC74e*8KNQd,3-bSgn#R(Ia`)*l)q?e[FL&J3>$"=-C",_SN0!%Sb-'I1OG$VR"l)q-Ogp5rlA?smB3hS-BliQck?DqsN-%(VC7-ocTrsaj2U2!Y%`j)"epJEKA!MU^-p/1?I9XE/jnJ0[Ic^[tA+HVsXH?%.20^n]];$nsF-l"M/1s:[#se0KGDGaj\d.n4&pd&tG:3\Sj&O(N[=f-OLN$W9_@Qbagc.#(RH,FuQbh`([e?C21C^^%HiA"@>/qlQmV$27_$@f0"df>WJOf#k:1h:diqEV09aq;4VJ`X3NH-oV%QaK'Ls`3E/crC:3_q$r&IC`*1,$b!^gQAT8%7@POR8/%)Gp;?ii;?%@9f1Ts_Ch:uX9f+QaMo%>=nXq4u/!e;YR,dK.[%4pMD0Ie!1)0Ji5R,"Q4mbh(]m#P[lrW:KlT(\'Si8&t?R.Op%SB-38ThtjDI6e=K6$-UB!%iH&^fQDZ7gh^kcLT@[C606g&FVeA&h6MTl*M&(g\Xs:-lMQ$VTflqY]^R%"E0)t+nPdulCie"fliQHs)D=pBFJDC-#G`.)]dWBX^1[b=mDGm5$G#B#kLEkta2H5]#]pJ-RFXMBiXA,g2YU8-e\mbicoAMD%VUaH&YH>r\b:I+VSk__hXd\$Cbc8<1#^NV!nRE:8bANqU$!X;pq\'0&sJ0,8k\?F38LNiWV%TnJmo\Dp+aXX8ht+Y]_P,)')<:$*=4Wjl5I8uF+2FF>!1Is%rtQIr"URPe<[3Y!U^$bQX`/Q9iH^R'GHlSC-IjGUm=\E0H&QE@k*tpVLVM(bW%@oJ[T!Se1Oamc&dp0*-qDl[/F^P@h`9s"amoUC$^mYZSPIn!fUnZ'$MGKd=JB2eetE3pL/K+$;Ym*4cOi8Me;,;7m8Z#pDR-ZHZf_1]Z!(/,bVpl>$Zno+?@QWr8+UPYH4.M(-?o/*4E'/1>PtJpnE"iQG;/Yp)mN2fnF#7U>_`E+nkU;MsdVK*sZ#F=-<:1`Qa/dWr5?U`K=sO$A3ZXNuVhVj70Vs*?r+@Sre%"f*O[q$<^N^h?!/ZOMB:gk`n;&0,stLOGu0[rN(,DnS0CoXiT]f`s2r;HX%0Y^a.?K]4!W]Pdh3ODs1r6q&C)`NeIn)EL8mqF8QHoaDUfTriH^O6kgMpBDb*"-YYl3<)7(WI^qnoaX=MX*=+?3!)(LcfbCnbjk*_HG=E*bkoWg."*XFq@G2CJk>CH9\mAT:BR$Xn+P)]ZLm76mRR5WoQYMD/$f+e>sBe6rZ5:d:I>ASDL@/%_4(-'[Uf!?hb6?2C@k@<9cgFahdO.rr@;6GRc=gD"7h\47ZL]*9Ed-pOY[djDp!Ka,-g+#^U3\_qLbLCr2W=3k"F-F=W6[=%[\X`^>"bl]A*`[,'Kr($e7\\Dg1f3hmOJl=i=E^0)4;kJojT&=NrunkG`Xb-`b'P=!WG&N#)%j5dG^?B@:FZC17tm,U"k=tC\U9-FN"0t0K.GdGbb.Sq@CNm.JV4!I&h^*Li-?kqju,Z\!U_1rGrOtnSo.rkDdT?SDHP2fV+[B<,b4kf,;NH0l"";5+_j`.'LtFj/.F1\Cn_;%?Z90m$SR4nP&NHN^L&.G[7^-0n!BVDpOHtbe1"m/2KtP$m@mLaF;Jrrh%VaG1)?TnHp@.E5OD)!L6mVK)N#:k(Z2*0Qf,C[)i<9os>2EOE*VM%o>-V3#j.eK*@r7YRP%CJ?`7M6bT:JFCF:U8E*?"h\e>8?p/0+/KBR'aNZ`O&+A;.gU?*N4<:$l[(m^!9gl[0B4AX)jbjDM>"M'_IlN5Kl@5f'-pUU3#[r1?:"!;BNg5g/-B8sj(dL;43%LsEct>!H@>c73:FS3WaS4nenolX>][RJ.C.*L7Y-iW?Cn`K:#k2`gJ#4[0pIN;a^Nm.I!*g[H7sV".i?]E-7]5s1@"UWs.o!Wk^@"`=7s(,gol@dlL86IKYncI67D'q&_`T1<((pou#MkJsQ\&AdaoW/K]C]nA8,AOsBlL.AV%adG6Bo73,_fUqK_N8M[p#&bh,2-B\e3o_Y[!S685`nPM[eo<^/'I9L3VF@.d>GlDOBMOUfe@=ZA7fS,4'BFZ@:]Fa##9Ej*U6^HP&&E?$cMB'H;%S?E0(+Q=3@koS-5J6pp=>'ogVj2\%=!dVYaCI4c00jS#5aH446gp6]]Leb#[C=oPlhlD[,<:H906g_i&@;Pf/I$l9OA'>J2Ud9uRe*$Df)@W?I#@/d8dn-:bUa^G_pudNG9O#]l-rO]dh&NJU$D+!D/uX[r;Q"$oIf@;&Ki+A*sqWWY4_;de>^4>@B1QW!2Ob'5'7M0:#s`s*\.^Z!!X->O+*Mu:W_(gqQ^-H7`E!J+HY+MVt2A01FhqrZ)[Jbr%[,n2r0!eOmX^i-]f]XS\_KIZJ33bcL"Z5Nf:?_Pp6.+$QTCOb57qFfO+`cR!e>ur`'8m\[^VAXMF1X<0.89eR9db-#<">H/?LjmuE&;djt81k.UQ.o+p9`Fbk!D#JT9fA)-NHF&,P7:5&.;`'b'l\1r]1B49^V"XU4iU"XOD)XlNfkZHPADC:j=*KH?V+QjEfFZ$.7a&\:hBK_K(q]LBm;F_CXVLB+1+B#MW."l519@U+0j,#jh_Rd'##IuJ([N7q5i,7n2GI$?aMn0C-ohTA%:c7QJN9-mjD#V^T>V%(O&jh\G((%6EOF67Oj/pqGV3Y_%P>IBN&<65^TnRHWF&&W%[(2b4,ERLCI[eF$hT8TphsRu+a?*8^pmeM`]ZFS5h79DORZr._aY?sq^E@uR-JVqOI>m!POEC0G_nrZiQ@7lg[LO^N'[$S_TVADfnSe0]rh"+`e(F\aI!#GAB6m7XmpXBT%4fsQO,p68O=E\n:I'd%,ttk&0L'omBr5h+pc5Um%+YPbD@NAWPKAd-S1i2KBYA"]LF@sP)?uBs(&>NLCch(RQ@$:RiQXXb=[dntI?[M1O4fZ[31I2lBVD$2dI_T=%qa`AjS"q1dAjWd`g^8SRQL:,Da$/>n<**8?lbdupn&,\I.E/(6q>jbXfl?=NL:X1Cu@dR9Wjg'62LIVbQE-a6SSY27046T8I\%tf^@,.RPK+\]ZdrW%^sgDB6MJ=\t/d&`B7bpesP0l2"_E*HjTtZ,qkX9:*hatn5Pbp+9D*?]0A6k+]]*V_5?K0[DrjnNtH4iB&72OX^V]nhE#-I2pH&pn]$qr1$o>I?ajg7;cq,@C>@lohO1Oe6c,OKc_oFFkE:iHUYa%L6cB0hMkJ-kP2JqY4'Z[q'qe\]JkPnZM]Gl8MO%/C8Z's,IHAk%me,D;cn>;Og7J%QTZbGE,W1M#B;Wh+Qk`>?4&Ik6j(a$7=]%<:#;KpaXI^I0[>)ar`JoXr5uUdn8,+490=UUpp4)'`dJLKU?H)N/8WP\aW@hcLh=Y$]B7:&"He>3%W;4$TJ?!0Xh)k+dJ.I+f]13QSh2$7%@EOh0^]gI4+-Rt4ASKCL`(U1)F]]F1ZeN63?7XU6i>-/cj^09&OU7UA1hA`k\Q3MjE/a6ibK!U'6kO/a?rMQ#/dd#bC_".1H2^>7$*NrLAKTLhI"n6WS*.K@dnT04,UV!`uNH8U+fu2W.`j$1kE(neYWJ"pM^%Yb=CurDlcGK%FgJ[ltPBe52SA_@2@+\^P\I8/^P2u2[!7Lu!g9MoHKWod8$r&!B!A!I&*u3Jq48]o5]&[QV)K2Ld6EFPUXDfid80eiRX?cjf#Xjd'.g3WG0G=L`c%O(IHt?8B%1Ss@!uunqK2!o<6Jl:)o:neln:%@D+R4B,7=6^(CUFfB#r)uuecA$'0fT+"Ng`,GmBm'3*?M@I,O?$0?-N\,cq#&VO<('K9L^k$)RGUC8:R72cm6U&rA*n,dAqJJ.FPR'%BO(@L,99pYT">s6d/*^_`Kd_EAqll.+`;l)@"%%b_FnioYeUV<"1Cp/VJuc^r2ULoOMVTS$e(nTC2RN2`Y2rBl\4>WbJCr*KXo$!0(A*^E.[I(a]@+\8s]iC(tmN&X8$5e8eK_#WupO:g$j+)f>k^Yui]'+`V*RbPoQ8!e=r-^Mt5ZZKKd1/$pTh8u`mqCKf(QO&WfPE%N-IJ:hMe?O%l$7O8>$o\A'0G6`DGVirMl5sQ.p6*VdP<&P5aLeH`_J=9mK\::G^3\h]ei!W%CnI6c2l;5?s(lEaCgEYC%-1K5#2Ldj]J8:hsp%U(Zmi7X%+RW>ZFlGUbSL#PMIF0SWgmUlY!K(b]]V_khWhcK?k1l)]"KTRsVacf8n<&cMK-`[!<`G<[H-4jrnKA5hgYP:56Zq0EUC@'SVU[ZJ\%mPfZT3&S"^,%H\4]nS#GL5gprJi2P=$oR=^c3afb9(#5p^_pTLsl\rUIk:HUV[u\1hLQAf4eZ2P'BaK4.mE1MU3=-83,b'26\4;`,k2n/1D_2RbE7%:?I2]^'!7H6TmQD#<7b%m83tPQ#IRP_"@`q'kIW"-d3pAHA<#$*?1GP>E--I]/,^=&6ZUK:Kna*V@'bAD'6]>nVD1>AIbEE`%n>h*ba'5fL?u_'2`613et=epYlpBlC$'#BQqA*G6qug(aKE!bDQsciYaiT"2%29,b@MU;_gn$@%*gY.]1Eb0B3pA-Z2[!"*[G&LiuA#anr[Cf&2gG!j6?00h`Qk1jZTpPY*-BXO1QjB:K,._JNuQ-r7("&Gj#a*g7V+L;biR(cQ$N\b;STR-S8%HpbU':D>iCRNhhV_YJP:isgdd,I$oN9Iphb(P)#'p0aL)8&hipEY\*Wi?O5!-hmVh'%"Q+F!/E46-[ee<&$_4(?rQ-3RS^W4%4P.F&bbqj[sY_&HgQ&p+/6l('`4J>l4>Z6U%3.ZsL.VZMnIAe0;bb)20!*Ye6chWc"]#,,!Si6".*h77'U`d:38g:C"6iTL"c:!YH!ZGoJ@:J4O.kD<,@7hj4J6#oL^64l,33"N#AbICK9CPULO*(lI\'5o:Ze#pp-`CoXthjPAPj)F.+)1(6\4/@GfN_,_bUNJG;,?2q$%c?KS4hg)J7RGL77K(Tu];VqCs*j1;3s'GZDBPUp.eQ,W[pCZY?^:I".@3_(&M0`:ukdHiSL8C1@oe3tu"!g9m%iUE[2o&V.-Z%?JE,Wj=fJ]Ja_4\uTl^qn:qL?=kRS8MKKhH1r6s)fs=X7nh4g^moW?4@WJI2FnZ=?ujb78WlCB\]9P`c[p1%JEMN>2!l>Uj6#i`mQ-7`WdG(rLVN%"&$h9:l%\91E9n7d>)FsMdmNk0JfJ:3Ti^)&]*Wa8:hn36%H4B`^uscr-P^n31DVD;3[I@048`;%K^kc,micnlQ#j$Tug*[Hl*]]b>'dUjQP\ml4`bi`.0;88r-'P7cTO\W8qF".e()BZ?WY0iiD%BoC#M1Sbg-jHU&N:gCV@Eq#1BR+@\qg8/`q$^6n\;FH3siP6]rCZct&^BqBH:8%r.l&3\s+r;<_:tD&,WiUqY.jM>3)cN1llkX9ekf[`>tTKM5*]JiD=),8eB_#Q(+nm$rZ9i,^N*0.N(4'S+,"8*"EH@<6aI?[3#/0O"1$WSFal[-fFMZ(s2Ej/N^gKjk[K`)R\VU`[PTO)]kMFq8JC[6K5-TU8:rmkXqm-iek!&P6S$(/)8W70*r3OAIb9fk@Wo&>hO^pd

YYpH80gnn1_r,E?]C-/&"sEN$6%>NJHDaaHp;$N)]Mquk(m%#Mnc@eU0!kl>BEWV^Y2[mh.;]ECJ2e+^i1Jh%aF9'c;8apZG!W&Y&UcRCB!sgPJ3>>(RgF?QnR7/[SL\+krg=0Qe1;NROL/V$B$;HarDTdL_b:E#!-*$$pe&:jE^g%UR(5TZAb!QN!2RgDDgam]P-mhiHgr&:\:RE$GgA4VPSuB5?Pg@$+pa:,Jnfe74b.@,UM,r'r<_,RhBX/[gM4o*H[ROE#Ok9PZKu(O4-L*h"OKhd,'UE19"Y\erU8X>e_5A#!<7:1aqblZoJ@3ngV'GSn4:nS#H6Bk(V8cYSs#RMqHMARTG'kp&[@R?2j$A\\>#"XjhKBeO#R"56H!W=N4#R@'4T[-jE+"0Sta8mUO4Sen;LB]oZ#3f._uSH*SnP'i=!7&CiD]#N1)#sQTfSJ&1.t^HVsNWB:2YClaSK=U*:GF39=7!g$fd3/:^U:`X?aMZ@9SAn3NjM>3(UZDb"P9BAlN"KHN6;aCd2%9PV_iW3sM:eHl(Mr6"^4q0t$IA+@D_g`sDt2NMCkM`M3a4_V;4t9k`b*BIW0=#e-p"ilF&RJVgag`po%%-%(.GK0W0"_EXY*/6p"!)F;M1Sd;3`.%CqBp35Ka3sY"Ggd$Ou&>9(h"ULbtM$rB7L?P5=jEpp1l1I3S\pQlJ!TCVQ9_T5rC"^A!l9KG0"'3:i?O&;QP_S=R%k%JO*09ltaaOXdH]5H[\"`!aQ`ml]@.U\/E*QI\VjQ#/0pF)9YNulA,t)?V=j7#9"XP)2L+eaGYbS8Wd)$bu;'8-tS;&GJ:@D43pE+@'r"qM)!VL0#UO@Y'iug@"m\B<7pmI$#@@4S2*7Xc)[+,Ho]I?&LRK^P5$=I5.5JfTJ-5h[Y3D^8VXcapccVbA1E'_T:+0>D`;go,4E`=qY[:Fa!$k5c7LV#8M8L>UC3"TUXJNNEA+qt()Q,lLYBMotHJe3cLJ.`tK8nONTL-R$j!`]Fs+9Whh<'rs]*gBDf"@/d`"XOUMWCk];Nu`rHLWW>Ue.W'7qpm]R-;X,UO6p=5&,P)YhYRSPN;;gk8^Zq1qQKf0F%o?8&.oSE1e:L14=mcX,!g\[1Y+8K@BsLj8[(]Q#Q'YpM@/j(T(hk^k-.#EL#1ifSj4!tUDAe\\0.N2p#_(d7#;Z`)`6XiQI]D*$RKbki"R>hLu%mdIU'GLMFkOP'-4=28"Hu`BO..!0-<:<1gFkL9HK-P>DOFNPhdI%,ZNJG/dsNrDKM'B_9l\'OemYeJ4TD7r='&fM$T4f"T_.<`2Q!udN\]=+3UHV4F2\_P6.XWZ%(a!m^Lr"Rh@R1nD.*Hd\aCF%?a#u_?C#g!JV0Q-:R^Nki-Pg15D*=L=J);p:E].h=Jo^+'`dVto6`biBjrg=[LPH/J?b6=AoC^755p_%j&$t5%\a.[B3"o$.,+E86Q865hA>T@T?;i-7/jFOM[FsOj6)-k`GG+eafHT.PUKdREc50mRS"FRV`C7rPN%8EQI\JlmG,1r^1-DErJR8JM(Z/S?6aA-DT)qIlk]^8ZhAdYUqZ[?A0+T_t+E=D"qb8ILUqu*PD6IRe"fS0fBmskU]Xqmj2aRC(2rbk:ll?Jo,QJdA/.Vg(`(J%D9bZ5lS!66/u"S@`#*A)n7*.1u]eF0b`MeA7G#Z^Vl#'PX+JF!Ink-uZ[UWgDaai5+)UV&.Za_I\Urg.sZ1p:ZD&#,u`&)RJsQUkf=5\Mkjd-?0>','SC5UZ>6f)B$TDj/T[j7"Gl@0FA=6\e/D!u,r$C#e0Cp&rk@eF?72L8ZUKeNfc.Qt7g6'9ahED=goLf8pQ/c81MK4(fo559]kS(V3*l%2MhN[54e-or67W%?dqmrb+^mD$:2(X4pX\'jjG&<2LZ%?c!H^L6Qk*(lAlXf?W"bUUi4*l1YoUsp@HN0S71>28G?3[8[?@3m%hiTJO%W!eH[F[]<-9DLh$h@jX8Zgnog`rk@^X.s1uF1@>JF,7$sq7rJXZ?nA/bT4JnlId@G"biEWL[d\VJLsY.UOpW,([>kq_&I)*2.;+%JW'8l6Mi7Q^mE#GYNg*@U(bDSb*2fq%%!ju0H]Mc#_L-Ohm$olqhs9Yn+9(Mm6;JC0A5F7aG&\lu;`t-Q)8u$.6tkGVbaVd%V3mC$R5#Yd,>eqR7+LL#d\`hF4^[a+u_M``;Qb<8;WmF!I4%@1*^ZOZ[*OmTp>#fU!'mW&L;dp;$$g#(SO^iLsh&oF0FM6i0LZFj>WB"\'0*=(.5,gge1r@CJ@&"4fuFk<:8HVj/#bJZT!oDIS&X6QL$@NW-Ynum[Zgu_;&m>KgNX&La;,%/VV^sI2_3ug)RnU"/>!Un6WGcPt(?L@;?e*\*Cst;28J;k8Q^VciF?I@LX1_Ot,$,?9I(hi7!qF'b#)*BJqa6gi.]j!rW*ca(r.B)WaFg`hPk1gVbBdd#$D-/jTdl*%5gMdJ\ko$]\KAi=6LF:<2-Qe5bKks((IrGRlXhok,[M6ZY5u*5Tian02I';H4H.O=m"0:!k(hU5'T/F)tMP^kGLGXM(%7&))D9=T))E:B`0ZOu::R-rX^.7tcB7n7ZUaU;ZT(ammBa7`@IScF?:?.s2SoG3-'?Ks6(*Bm.TEe5JQ,ddkZB'`Sd-L:oR&#a7H'b6Em,gha5SksqmjZR1,R-,7TP%4aI2bSk'MX`_`[LZSRtg_sRmRu(/^^)P@tW79)j^-)qrSNqVl1++r.Wn(YCh@\C^hoPfOne@RZ%QfNWBOp+piI'DPPZ8-LC[5q"Yi4-*8eoUsTM.(IQq=u9,6"=.^Z^5gIO)>?W-E1*,9h.=MVRqN!Z@XXo!8=bS?9S(05QtR[9)l7"IC6BiU-q^4n7R>:N#;eu3[ZX0!IY5*B>87[1>[ZJH.eUB9JY:gU*DkFSk3FA-(4*QM&G.CFopQa]`Cc`C6cFeS$6DD7ME'6T)sW^J(6o2J'jtkoduHhj(Mr#3gd7l'jI#H/.TGc%Jc@XV`RN7eFb74V"QKc!m(hpJrnRb482:C:1sLM#R:,JPE3f-*Id+655Wd9\p@amPbn5p.K8f^F95hcP75u2*>%(nJs.CjA`uZutD8J+qmRf^T96B(Wf(Z7BX+aeT09bY-BZE-RL;k47DM$J8q&iL!*ra*\9'D@1K5#U6;9thW1"O#d>BS_KrW08[2M!A8'k"1^C#NW6'im%'fJJ#gG^-aKHQmQD[5WejTY1*Va1:NXd%4"):X;^S'C]5NN*&8%3sJsP`e]`@l]7IP?_0CID=1O7^J+Lp(r*7Y`j']u\uAS]-k_mSc(%>Zo**Pugqh-8MA/_Fp<*XG#ggS':]r&B;Ad_8IT)5969g82?2[Q3jn?`npH>%(Hp[bQY-Wlo&4RElfb5#9$M"39.@Fc"<%`rPQP'$TcIK?D!+Qm:.6cqELZG7i.T4gOUN.*L^8Y]23d2@LeiU/f7QlUlJdm1H>T[SB)%#<7204tQ[0lAa_3u:iXRWm'.>$SNVno78,GM_pA2pQ?/Pu4'jJ'#Y>7a4A,E\`lE+V!u-?7Y=f&VGUGK)/t[A7,KbOo7*NPs7\cukLGW[aTs8o:P$3FK1(2q&L85/F8[E+Pamm*/_+NC'oZkU`D"*MS6Sqq!)J,8QUR]7*NVX7POVL6(,mN$i7Z9;5EJ'5bXb@6=c@!dPCl0\.#*>Rb9O@:BC#R1JNaXop-3eI3o.l'@XRR@.]_^RDBBdt[-+G&-F"njPL30F`-Qt%1j$m`c[H)E<&aMSI_13(`dhr4WrA/W7-[&n:n\jr6`5Du9=!f^/$>/6.7TC`*+4krWG([t],IW"BU"025fGR/W,WqMOarmT.TM=7=sY;SJte>NBppB6TW0-8d2IfJ.B/1+,mHKa?SS4($gHKsPQ`U+KC5AH+DVf0RA14U/=[P;'AabM7PK'02C,r1/bm0K3J&/+>GFcO_\.D.,T&[H@QfCW\N!Z$D[s3V;qFpp2VMOD&>@4^41$^f"PC89bl9p6*K%BD$15$3,,+D'lW0'NbjU_6]eRn9tC(1W[AI$=Y6^R_6)^1lX'f5YS/Pnc927$7Ue)R]3En%g78oBSrNNM'bh+DX+2D33!rAJAhh'6/shXhZ9"5/Nud@#$o"X+IAJSmoq\9$GaN<+*q^.EM#Z!?X4R5^`g5ic&3/9DWrCnMF6htQHt;6ZfUp'H%9HmXu''DKefZ*Q]!@,8f@^4EY:-S?%Yr2rkGe6-)V7o?f67YJpKN!W)Qr,pT:5s<0CsLOHO_s8*<@n&q#W0c0qB$(?Df\I<\:>]_a^[6Zh#=IaY@#%TUXlhhJ;HESt-sL*f\pi!5bQ5=49R%K64HlAS2VSl<+CC`/b9FXd>kX/.].FQqX'*ZT@%^!#+QfEo7D9BiMEK4oZdSlsDe^KsPSd9dHj8R#7*rHY87h$kZQ2W:0,&;[]NUhL"+2,/ma6O"G(Of`3M]%8II=@9XG!4s)/jRQX>+?jK?09a2#EG237)%DUmj/ZTu0A8Z!+Z1Xr/VOU4+;b+9Ju9WA;J@7tBOjh^,7$hr#?dHR@*L$o]>1?-B?ur1RrJI<.)6Hb@/gejT*+i6Yj2f,k`=-`Q1c:Ho!@V2S!\2qqHj3&<4R2#C`8b9"gG\H="\Ut9e/oN7>%l<`3HCcB[\CBroU51"1geJmJ[:[E_`dD1$;O,&Q$X27l^<,Dh]c9@J-8aBc0UKg'R%2)4_Yr.Xs]iGbn2dPii\e4,8qsZ]r81M.4[a=b`h7$SsSa2gR9,,]G#S.>\5da,ERI^EA#n/6X6*;oREtG<;6FRW^e_;::QI:WnG#g5OerabA=So-OWq?^+U76W7<5So(G?=;95X2W)5Rr`@4(.mR$sMJ5$^5GZ%0]eipoFJ4?Hk/?3lpQ4`UfjaXU6MT2n+,!rJcPa9>%:>s3GB=[$&'*P*dcEikP<#sC:5I,g178^"6'6J>L@f)&6pdRsN?oi_Z\'eKSJ\I+XJ6YK^CXmSR$b(PM_%3_4p#@3Me3SSiEjH,hIPY!X_qrYmG1K('+?X:0YiE8!J:Sm^m'rQ7?T'.]kWkekWQUt`_S;E+Km\H^cQr'pY*q6G#V;rCPbGnT,c97]Pe9a6iPq].Tn!k9!F(Sg7(([L#.*8=VHd,V\aAMN?H;YoM2k_dctqaK]DU&n&p%>BhpZnaeU`Ae!s;,J`2/S/tWX+*Q>jqTr"I7LUu*/$tgn$_gm^;'DB@RiI`E)X[ADL0r2!o9bJ$=kA`.,#9Fk$XV-Age/+IkLpWTW,"!H/%@r5i1H]rDR#E)qkCn&,dF1*=@'J/:GQM_Uh`4m3`K$D'o]gK_ok<198B-\Ok6F8T\W]?W8^EuK,W.[.&L;ZpW$(JR*Ha5fno7T6/;2F/Kf!]r`DM`H95^0<1J%NYgu.bmoGkr!Z"[(hp[KH>;(V0>4QWE`@g'&X<7W@@d2>[,*>G1rO-M]rK1?O1Ik'V76WU\hPpZGIu!"IGL'=2jc6-%@sT[P26/K6g9EWu3JU.B-TQ'mCQi4\0nG+oCJS?aLff-7I$enqc$5k+$\2H^gUV]&kCpX2g+7%NqbSi:gN1QNS.S=>654O7gqDQA1NK=NZ`.^V$%39X/[VB@l!4WoH%OCXaIWH_Lc9Ui<0-h1i29n@uV>13Lgll,Dr;1`[,9)3Z<,R?.h5Q2lLksKbJg/?u>Z=V4;*T$^NH#"uM=@^>e=a,kbiM<@UuVl5*Nb5E%^=F`r(N_:EOaqPjW'<7G!?]pQTB<-WhM[&\iSAh]fd/-P9$,TTUVfu#["N6p.IB-GuA_#S`Pgs>)c2-2J=lhHf#GS_'(tB>pYWW,Wdp+n!-6`0L:R`eh9`YD/f'GnXNMQH2cO8UU@q4?X;$ifD1]F;Jj*,*R-(ZuLq+\RMK]9tKG+AiRD/g1C+V8OF4k=pO[7,sPZH>#I;hUV+kI=haf.bSiP([uo\6OF/f8FH>u4"t8>O9n2HsJ[$q:?/75l0V+stSl8"KCeA5f@B5'JT$\eF8_QsLdXSu/e*"6K!=G%Wj[+hQm?0Rb4o[D`Nn@l.-m@ofS/[)NLc8fh"[Z)'2_ANN/10ooQIc"=N2mjVqh6"L5#SWg-Ebf*9HE+nXb/kP$>Lar[+2+0cj29j*6?=W'_p>W@)-^/hA,OV,g^$qV%eLe)K('?\PPXA5M\nnnS>it^'V-rV2\pDHa00$,DXYWu/V`HF_i^N2lnTTgjlTn.Z7>#:$P4cEE%LY/&VJPlFG`gdOC9FDF<7e"e0o],*k[B45?!/p#;)^m*hg#X`*As`^W2fr!p=hI*a*';!67b"5@=EGFX#A4?4@apDN086Y;4FlTM3]p^$H@p@bu&adO;VQ*So24+4[,BTiKTlJ::-rle:GA02BUn16I7tm`h#*X"4EV]X5IG`RGM2'3HNFZ':d+E4!8$jIu'^AJd`n(0Y]8;q2PkT6#n+o37/V+1QE$tG`6ANFN,>S7A\5m8qG>u#)F91Uh+8gP+/;>aVVQM[MCK3[529HC,KR:N/"M(s,_=RNEWl&Ds(>9U%>.Wnd&)h$npbbuLBC)#ZJU%MbaPg5\;Wq1@lFAF.OW/>bcRl]J`jX7\I*]mA[2GPo*<8G_5,)@]qN23-sMB@!&^:h3`1i9tOU*=ATO\\H"MHjg`)8!_>bKCW:6R!%(W)?;1KJT:LE"!0:;R5b\42nB-M6SphX!/gST-P2JKs[;'$\bn+cRM*s]*6B0NonFHb[SSjKR$9[f[F_u0Hun0dPqt_k>iShahIZ5`:Q(S$tUc[;b*l*&CfTn/;Ee[L-jU2M6S?Hi(tAt#*XegDf>Qn#7W8pZ\LY*Fk)@7fL5PW$YUA6qABf&.2#*."S(@]HH&RAf'&8O914GXFu17kR>0:b$UC5b)GS-HjGA&SBg"8]rS'd22"?I:]ORN-\Ei,D[#I)"[%*lTM=p.@,<;$9ET/H*:lRF-i_=:d'W5o.k*CjZ9+*$^7I7Laq#Js%<3X\8Yi",NIhdCq*9]MNem_Tk\#akG>k+!JbQ1dRc!F2U^gc1!^+;qO+-9OE#!q^kpOobnDTHZ>u/2gHd,3SEql`DEV>>H\?Omo4+>DBD4$0`GQAeC^>)+k#KQ.h25jK?L&`C-_=Op1SDd+S)5(E32KdI3Y/_/eMj=]uh(Vhup2c]+K26[Y)%+s%;ZZH2U$/;q/PHUOcglAJEL=Ii;EWO&L*=1E=l[tl>i)\2+MJoTdMIp"rml_EH,HMHNk[VG$N>e&g'eqdlbX!q(`.k?`g;^N`H36,=W5(s85XJgFZI&SMn^Q]&+Ut-kg-8_ZU%6&`Pb4cmKcmje4qXrdYeE#H=\n94B-5*e])N5&aJlL+]%b\87JnSHM7fr;`0Z\/JI^rp+dGq8e3+dZTr%C*5LlMF9n8b#r>e8A-c(G8mO!Jf)YaGk&jS'6?4QO_YnA`"!`;45C`jA_3]I5cES0CFBCJ\h%N]XTY'`Gu@SKMZVCE4o9#f+EBrlqN_\'gZ>.:@%VIqS7aW6=V62i6'L,.>DF8/!<,Lbi''#1Ul&)LX3`P;bAE`N1]42UtB"oXm5>(O(:br;u)@Q:N8n@XHDoFg;")`M&6\uQsso%/92Z'g[N:IA>UKC#kA8^H+1ce%a2VlID8:f0SPNY\gQMI!1g-\O6MYsdK9bKliO\(pPA#CpKndQV-nlbta=]#r$>Zin2U)M'69qDbe54q$2:[oR9:NhBap';cM4ECUdLl4fo$io-`m&14<)MMPRn)R/VK&ZqeW[L^Zq*MVLo,1['5Ua.=H+%,mrJ]X2%"'#I`kkO_$'`Z._23NW;Y5oRZS8Tl(q)]6C"iXASfG9%JS7C/_d7^a5T2TF:I3!sm1k=9R-hKX9i`8YJN8MY4SQn"1)3t,ho*k#Nn`^da2<3$P%AP$i\ngL5\a'nXqY$!K%RZ((]#,^mE>$M%);;aWJpu#jaO08u&rEpu='8`?;Dg@O3LheRf@I/IXRU3+?0n,-&#K\Z&"K9SZ&P\u4rFS6e+eQ6bD@(TSZQ0ttiW&*7#iZG_@2I\nEV_8/K9o(a&bm0V*bH2Gs\TJ*?`@ptKk#07Ei3&6JJ=7q8JZ6*JRU#P50:(M+DIOBd9*#%>/08*#hP@+qKM)7C\I,&SE6B2r0qD^`n;K@bueSFl_c-/?)2?9bD"q_h`f>P42u03C3S4c$)>N8rU:L0&euA[KSrd06IE(M7d*(^$#NL6'beT5*Z(NC?8coId(!CVJA_HY@5:35qFi!Ri9?*N%*E+;Z"0;R+cqSJk^kRJV+tL3UBHAD^cdht&UH4++Ei@*JlSWWKqZ<9^_D>ITTF*mk([9'dP2"RNahVu1^U5+!'.hALN,`M=F2:10_1DQro-82H''mI9hnu:[QK=2`#s=5d$b46"38%6Pit)3@ZTd?bss0a`"O`!Wbe/,6D2F/`ZS(s@b4=d\O]$cXHdBE^t0X@g2XOi"uZ4mNG$X6aT-(&LM.>:S?KbENu+X-oulEC&[aJEYM^:C`!ENgA1=R)1Re<#a,ld]#$ci1*Q8c_qb6eq%t2_F]\(:3BK#ra]^NK@\:9Qp`*$]J0/f,.S!kNFbDQ10:oh$CiL`HX`C]^Q'b>?'-4'>+#n)ohD6PO.i>WNP(K;*oG/7?@ciWjP^&Y]8`&VuREZ':t-kpUa`P@8[TbLtVZ-:q1@iCoEF4NOOn!V`0nksgod@?T-U9Kr!,`WP)GKG4SY"Nq@-6:qJng&gr_M"%GJI@r9>ZVV26,VG$F`UIMkH%oc;3p>!_e3j]VPa'N_`(7gDfUOV7d0hYA.-j>)XQ^_#Va=ltRGJSBTJI/-/V%0Ro-Qcdl[e(mfc*i;Pf@k0#6OF!UamT`Nu=d(*T*L#gH=XqhPX^mnE5$1X.&dcI;4!NuLT[P<>8W_Uro7/a9kZ_H;?N'9K7\9B;0J0Oh_]CReg,Fg@.K.*Zs?9]Wc)F\Wj#LoXgD;.1X/iPbI4FR"dr[%4_NeV5#/u_F_(T-urk-+qu.Q0Vb9C69TanZ!aBr.'Ja5.T_$?&$a2``"(p)1S`0GX%Kup^&\7$q!F]#i]6T#Hqtp>/lk]*s+Mga6:(rW'\q)RMA.^+fC,AkB.Nfr2pRe.8N!Gpl1C8RX9N[CRfOA%V6g@F++LhW>/gV?k!YMqVct'%Hm-#l1g=eYnET:ou$43Lp-((>4[]iJ*2+5CsX;O2cgUsc%cpm&3@4kid75Y`[;!dCb(c@C0fl^D.7=r>h(gKa5X$VZ*.,UF28&+BUCIBD:A7J"5E]O5u-[)=1lG[?>e1ZXe_MfO!UJNZ_e:qFbDogl&A>\(G29\K)C-h]J[D;QXF[Y453eoPRPQn+5d5@:BBEg8d9a#imA+k?NVn6GBlGRGt(I&)Ni)MHqsjCLH%sS$X1>99hI/P0M)g@3'qa$QO.-nk:0gKlF<3D7'NpYfj22?d"1k\gs1TrPsZ*hJNBJ^;O?unOV1LMG(QY:$D'Uu.&$u].)*ta<\/nm'kHof*h;G[WYj_C5GqhsKTDRuT)?`=,rLNl&eI+>55WLfJ_7^A4mDH-Eb.US'RWlt!V*r-@-,ZJs,9DH=Gs?jP4N$E>N;:EVohF^/AoW)&gEWV#FD&9&Ir=+*mimjL]OcYR*_[0"d3.Y\"tW6J1#g8T0cj[iBs"1)O`]SPO.)6>1S`[f/B81@-^9)l#hH&kUX-24,+=>"sG%Y+WmN5rfRffB(]^@gsjGR-P=UsgjXD+?kN_GO[-9PhX#P2rpH$LH:0D=H;PWcV7UWfP\+V[=BXds)d'NWSfJmPQ4V``oY(HFcKdZcYL'E7T=%CVigW.JBmI$!aeGc%0enK2NPd(TVOIoEO\*l?iXEN,Np5H7li\c#%m'iP"\.*MKMC$Nr0@pGjY4K]PX33S<9`Go2]X.*)Y,3IZEIo_krQN]1H;@E,2O*R>3P2ie%(c=Nfh=!*a(4$QL8GMG1D88t0mr44kEmK$+s5Z\AK@c#*M!rKq04`c?s.>4W5p\3HAleko01d!/+<6NQl22(O0/\:Se`H*rqJt",5Y0[?Zs`Mo,Sq\*2OUHVbbS58E3$frg6!E'R16)Gp*!pSq&2`L^/.]oB-4lKD5qq"XGB:2+.KW*rLH.68iiqY$+)<#I"DT^&@Mr8oEI0#AQCn<&sljG.YOOed#]0(&UO3kK#OOYJ.ZSVJ!D49FPBnUJd-k%`aD[Yf^&f))-7$ZVRX=:cSW+3YFF1k&SD0c0"#,r_Q!ErVRBF"\))(Gt9bD4g7XV9*NiQ+_K5C\1C`D(oK=XR-Dh`GOW#BmAJ]CFhS\iI1#ntTNDENe%[$k;B<'5%DY?XtX"PA>f`RHup>pXdPOq*=!U^1KS\SQ!ffS*f^TTp$+7<%6'^r@BspiN!*-FYti75ENJLJPGQ"B4Fbm[XCsQL#/T:mDI&O^iXrl4GkQC;880>[&,f&L-3Z5T\,7VMEb`QnAEr#Uk9tZI7GqQO^fUB&=HS'7j$q8S)Qb7>cr+\[#4'l:=&#("KV@E)J9V2['1rEO"9R!S6F7*9!>$Og5n&SQ.!-8%VtL71,n^c_8]98`LbMXm"Ysb;'7lm7M5l7R]/*P/5T8W%%+###!D&1O2!G.kQluE$`.oiC&4u6k;$^S60VAuNd4eAt5Tqn9ar#]]R2o*^Pdo?I?r?QHG&.>glg[#\pmhTf8t&he6o"bhOSSrA:VArD!Q?.[+6FCb@ph#?Ut-Z31=_Nd#X[0*@iYTu'NHVf\hE/GR"?.Xkl"'42j'D5gO[,E_#DY,kM>>d3'5M@.h0TY8WTa/a5r7I9$N#:*ZX(++SDFtbn@V-OAj4uH-s6L$rf9TBs^E?(`UUfRlaSWL9ksW)3/R57s+*@cPjJOM?QEF)c$@ouqXaXTrmFWGU-R8SK;4eKP5H2Ei7FsNOQ`0^)u"5:H[TB\Zl]^p#_jf8Aca)$!Y=:k(a)ADW.KSn-%q'gjWJ"(PD'S]P6;T<1/'Dr/5fiUaRM<_Y:mX<:4UIh+ijt39qamZ9u3T9hWR2?[Y*B\at4C?$Y9E^%bCDh!X:=?7=Y$>O9$k[?-sF=qoI9:ofd;;-kqMSX^[>f!@'ZWm.\@eSE)ZInJm`qcVMFgL]]q%\FBr.OIiW@<&a%-CFU1D&Sh]T`ICnRdVBTu12:t2uf]3o,J&VQ#K"nQk0JcM)kM%$W]6jU;N9bT9K[2D&d7j.B`2h2qXcNdM;,)jVEEL*==1@C<,e3J[s22eTWb&)muUW1).#uB5cg[Tjk#r54?!ON%mk42[e4`V&QE[:aPF\7@jeR1Q?EO;e7WZUWDF=MlO@i4\lI<&d2>/FU5@WA,#1_$3jOs$=mD-LK6rSSOqq&"C@d4A]4&XiuE!JR%P2_<>XodU$)W$!2"dfF-`(jQ0&#"j@7ZtrDis"9H&b8^#pm14oh/18E0Yo3($pTd5a#TAs05C[;/^s%,;fWuH';AkGSGN:4G5bh?1+=%4Ok95u]-e1GV<_<3&.fF>8r5tK'U9A05p7dU+Z..D7&1Hj8M*b="@Of^1FWG-,_P0/TP:*o,Sknsi=k;L&%>\8#;VYDG_e`l!,;E31mniD[gh0o:P]6omiX"YBb^D[+V\TiM-<.eKd6p,qnI*[.V_RPS3u:_NJ'ZZM@"lepBVk'(b\D2&hPr7PQ_?r,uP:B#L4==Y`fJo+Z(o''dekBP#*i*8BE=q,XbR):%V:(]b?I6+Nb()K/R4MKA:f.g^gUmprID%O.gq]!'kQ`$V0PJc%4eb&oiYSegJ_+h,ILm&5"gf-A2b7rn\.K`8@^p%[ck5DX%g!7Z^'XOJuWOR7&n,!#On9Cg).%V@5jWam7XkNPP5PMF-9s"63F$B7bQ5$V5#N,WdWJc"uBPr(UTI!+Q*C9[jBX0an-.&Z:Z\GB\.*-4Rus!PqQE&dd%8S%c\R6Vr!$U0qBa6NY^&H5IX>F#b!SUIoPF=WOC!*C(;!Z?IM_ha_tORmn#AeXcAr?rmYbV1'*,lk#NV?m&o**8,R?Dj&%k]L<2'[$d4+h4"057KR:r*[&&L_1d_?%D0d"$le'[f^0.#gN1IXo6<@gR4'V_r7p#]JKG3uUC+gD)QUOCt^E8)DKH1fS`C;RtqUdV0Vh,nd!/sGBOj^q_Kh*fLI_6Kja>Eghi@[^;!1*R,FckS#I`Bt6'?!KV/r%A]ngM(MZ0M--O1jeI:lMA#Vm@tMd9PU+Z`.hB6X=!`?rs&.@?d[j#_kIDYCg2;N^%N\gR"Gm7Tp9ahd2O)q2f9k!k?=^T@76pCZUB1[5pRZXMaU*W6fl6+(geYPp];Jp`Of9uSmd'CNc,#Y&)doQZW%a/%^_pF#LZ")F87fC\)q/jW,Ci\p\&Ko2#LiQPRIU,`KLT@eg`?+cZ%=+W);@-$j0?L!lbqhY7X3Dr"AGHWq?#&>">L5Y(f"g,bYN,6/re$Ts-Zd75c;i0JGjd_M8Z)onQ:lIc%:]HP[QmIH_HB"Y[Y=%=O3QZ5\e@+80+lQh%/YjXRrL>1]+JZR)?;Bnc<5#4C0ORh3T$fHFZb]KE,7*'iD>l.\?'13nC*C]L.fQ`PNKdVPMI5,SCDH3/t"=F(VR^W3nCMpDat'#Lo]@K9&<P_T6*P1#s?^KATXT)bphKp9N>EPaQV^qRPhaEu'.fs6dCJC#B=Q':pE@*KU<#V4(`EIs;[Rr!`o7=R$OQd#8.5%K[?&4%^YNUjS@m!RmR?hr4:F0HKd[oL'7D.r+1FI%T0(dcM*%,]M;C)KH"=I#i'>(K/\^o"85JNHt4=YAi[Hn#Z!V$%"n_%pN<:GRpIV;CmL7i&ZlY%?T#*s+6$.5UqLpYg.7.Q2ea@BgY`(3_#`D$I=%'hT57*e7T3>fS_K)un-qJ\Pr,OF85+[H\s'd,k;E=!=ORg[#(#DXqXka_b5//RbFhi&(=6\]tu$$IH8fOGJd(de]HFUZi(K+&SfGcJk'O">ok6hNi77j!GC3.MI5K[IAC;T^;b,=ou?+tjmL6)+Xgjrd^DF/fs)#hm`5g1\WnT`r\5BhkOc[8KSs)+$0qN*tHE\`7PS6mP<"S$M6lBJ@a9clX@OT"Z=i8#$m,\LuR=G4TdPJrpaHk>YhLB!.*#*(E6(`7#OF8;:*soGQ]M2N*/g^n\251$cG+8]=sNc$]u]:C@E\fVcCeK@pWpjlJu=^dHU@_FD?R+fSb<(^Ht\6fSJE[tjOsT8*Jj".nA4;T=?p>UI%LA=AV$Jf0.i=pejc1CPASlq`+,JULc(fRKuocf&5naWK%`d#4b,C`A.KU)MBZ/+(a&oo>u_MKf8f.7D?7+YZdjOr9(5$ckP\.:Doq9=Fr+*WKp+)/RUn`$)#`Z:F#s,ONg@M9J=(jjMLCM$>\t>^!*+%/f.r%4b[?#(ltTXfjAB/$MSS-1bPZ/32<:26rCV@F68c-Q_I4/8I$C4"]%f+'7rL4ME5T&"%6OoeO`6Q[e5-bpTn.?cd[J-*5l:&Wl/SDjh\CU#Y7q"PB6TZM;d)=cY\TMW&l>P6g2LV,_=c^]OYK45m+V>JlI<"$"[Kg,UJ_+lqIf5%\Q/#Ul7lj6Rag,loZMm0REHC#Ec'\`Gb[Df)AO2INq+$-u:&.'9Jt9CoOHX-kk\4-S_>)99"b%S+9LOf86#b5HCW6BUYAu.pn"Z4P#Q?S8-.^)tfAJcRRYS]/lsr35%^2pfOK0=,VDAI21X%[[CG]jd@Id.[AobEDQ>#S>tlBe_O(d_ccM/'X/-WSZ<5'%TRDMqjb&a'.TVZkE4D82K'pRqT"sI*>?Ti)DHmfB:!@KfI[t0N`1V)SVDuj6$#(.3f8-3oMA9Y(9Jb?K"X"HQ?ZN.X5#/04S@A)[QEWN'm;n3TR$#1!TfY7O3^nT*L8gF)s1*dn$k57+F]G4nBQeC`dBScDiuf1k-b"CL,ba`P4m@/QOf)LdIM9KHf]WDcE^4q'T7r2.M:C/\Y\lhM&@:>.@L;-%HD$j;0(8P^P#=CIS!^15XFg^9XWmnl<,R7HL&=!dSp5[a=GNg*(r:D^Dn_>-W<0R4\r:OaWK3i%JL3afSW)V1+'+qUWU"OR4f'WU*o*`ZQM>Z;Eb<(%io$G^;-_*CD^56>r-GfZRf6b8aEu?T")H]+"uC$EJHQOmPZ+8\DGm_N7KUf1%](+A1>H$^B%/6@0[IPGJbaq7l]j_75X`Cf*/A'/:KS(^E.5-g+:%I*JHS4B-a_CQ8ls4n"'\HXk[R\$LclPFZ9>*mOJ3`6'_;kHpA4^!Y3)3uZPEcu1J&XT2trm#4>gW+pMnC=WC0YJb0t,(4>4$mcJ3U$br];FL@-k-Fj?gXmq/;,f@9X&mde.Z0-JFg#E+aP9/__Gfr$\M.)LaTA0";so$Ijs&_4`6_-WRX0*%=.X]lbSq4X(1#@r:^_t6![3L=BRbq!@JYK#J*d3PIufToPGLS7l51PG1CXIP:m8[_84q4Fr>D@Up=,jV+IZ:t_P%N0A\s^IaT""cp=TVAY@6u6M6;5ZU<>/iY$EcK=DY1Bh!<&Bof.dE8btJ',Jb^k%u$'\!qRNG8KUl!MnFk!b)EcV_@6$^OMR+r1D+7sfGf"@3#>\%XHGC4em()pGj+0g)l]9fd)f)>nN6euLD#.fSEmW$^LsP@CZ;>k1&,>`6FiaaoIa@&kl*c)*oj@6Ka:LtL9d\,TrHd3`1WP&1a!P.IN>q)B'fJ-#:7d_1"fetS/Co5*F5^(Y?G>obe)*Y=XKB+@$*p?&G7Lk'd=?b;mD.%%$XRZN=4/=,uO1%E[<1QK<>EHhiKmrg;:Mur%[1LZ>a6Va]jcBj#n_4mLH^9`.8HS,lndc5>"'/%^^[%!#'^,'YQoU^kJ0!5OWI^hKOnX0Ns@RWfD4cciUd6U,L\"Uj&fQVn^./slW*Y[a#g]t7UA!-:UfaS4OI)8PY!E@E5"s'n@geR#"KXG9NUn^p]+4s#75"A4sL,/ro556A52rj001?ue!A**muVDs?CBe[S)'f\"%U""38%Crh:b;IN`5:-qu%YnM*Zlj'<"s1?(Z.5eD?#%S96)?2kL1O2N:Z%,b3$O[-$+ai&M65K;9Vjd('"8ihSAYUMOTpXG'.->*7`O47EefE]-od^#BMM7'-o?S?D<]tXD!a.7Z[ge&infL5eep#UL'gUd7i67m[Y'g;EE@@'.j[!K/?*2SYP*mO[u(mKMGt/Nj(5EQ9-I(&5.p[RXYb>Ok8i=5[aEHK2b3(;>Lr86mbg0-:RU'/7XAVJJ6GqaWJ+:TU5:Hf:dP4a7G9Y'3MU$=hKm4g2M]dDr"F0#iYY]BL8@[;0gV!Pq,'%)2l_g0qNhL>o60I0]_!uRC1<>DCb-igJiE8Aj%d7+2,T+J`fb^65AS=G'mVQm0(,g?9Pm7TgQ?eg@HGo%T>BW1>)HIp2A8eH_[hL0/U\[>3/-m>t-WcXFqPYi`W7f%t_Q)?4FnVM??>nbPjA$?B3Yd-U2pn+`uQbQFudmJd2gk[2#OOd+"HK6fK)!ARAdo=b4I9cHqj3r`an)pf')eQJa48]?nU#k?1%,R#/.4/"r1c#eUAkt<.GEN]O@.1%$,##ona>rJ/7(^D"U+e`5INKt$8X0_n$0bE[7^&872sCDHa`n5OP7@pKN3"e\1Cl:>Yh?F\r2;>G_,H>@$afVVmfQt2)@8rf,"f^!:!'(Mb#5QAS/qOh"/JfC;XMu@a$_7,,1U<8'2%]p5$E`a,^?8QZc%pkQkp6UDccBM*jX$V\rdXG:Nd%[`0mU.=s?V'M80&k+>Iu;UeDT*tj$TYu@:Nd60esa]/$;k[aMjrMLOQB?*&`3jr`9PJn"4mJoWC:uY&8_[m.6@R1;&_MTmRU?q5Y*;"5[!ukaSi$t.U_!X;.#>eD33ohoXWX[V`,Z8b&1FsB-2D[[]7QJQ^,p6)2S6JcZ6,c:!OOicZA2one'T>Tu"UPTo"K5]N!76sp$nrp^5D?$[DT7e`m:@PXU7N5s3V4.6;_hek#$bdC+>41]R?o#IJVadVPfj/gXSl&ua%AX:$j!k1YXjTr^O0jS-+L@Im/S"9LXI4H!C8t-V%fjC"@,C@OMXj_6j+/(9gD)lT;lp4,%>+%(m-*k$47W%WE,7`(hOTtJg$9a@?HpbQ6;t)@#0\3Ja\5r&(<$:LNk*R"U]BHQj+m4N";\9rA_;\G7msTr6D$/]a+af'aSrY@Ye23-n'lUM@)m$LkN[*Qgi;hV\a1pZn)!6[Yl7epR!!kO]l")O&p+-O)#tjo^%>u9hPcUKGmWR5+g>j&.0J81-`_&<'-l$AC&aN<`'tcr,GA`=Q&u4NiO/L-,PZgtWO='s#^5D"Sm-i>Z!LRP4Y*k"_@7L;0>s-p,g<=@1[N",=cej-aX&aZ?q4V,C^/66i^g..Sd\Cr3L.X4/M#A%+OZ\'F,A%[4q4j@Wfl6ks:\9cg=SXoXInJrQ&$p*%68!2s(9&=ZH#(NH.GGfbeoXMhS+qs^WMk#kTZCFeO5uD2K/'7LE4S[EI44RbfM[P0_@KNqICp@j[4mD"&S^q91T[5)Ai5X'hbGq9I0a$[?KTrLC,5n0eF#CH^fHcoOS%M?%uI7FRD1"%#lnGa:r`.4P#*lZoSU.;2@%sEOd-$#`(Uk@mLf*"a&e5lC8H]_nC$c3ALhKaaqN;#IMSH][&`"B%X'Yps$L__Ne:luk/+C$76_IE^4e`=X,k2c"sr\t+5L>!i/kR7NSihQl"&J1s?:67XaVa4SW2Y7Oe_5W$4PR**q_/5u.1$`nCos1QQmp8R$j9'F&d,^`07'C^gVY`>Tg0"2d$l\)p2%[c?pA*eEOLTG-UGdZC8ZJ59HC:_42U50daZZEGG"]&S%u5B4)Hl-sM0YEYMBqID;1L`ir68G-OXOs>k]D'd[p[Ym_M`3^F@AGTgrQXU#P/0k)`j9D=GN'$-!.bmOp;,ep8/FN=S&ZkDb9cK"C0KA#:ru[Qfc\U%j\d%e2&VnuDup>ucl^pBT9CGu@/#B_&#Ac'5VER6Qu:4m5K37oP?94t(qmd@gNn7]YCEu__kdhO`@0"iZ7$\!1GnKhNFp8t"$TR=W@B,kdsT#l658&C=)h3!Io:3=;rH4rat,+@FNP?@Ztqoj[m2r_aReP!H>Z$tQ%n?N`O]'-tX1`3@WD,0^Zj0MDQWJjf.6U!lF;'G+!DO8E$:d,glsjl,.XYlTCqe5InA&Ch'<&CNrd^i:R'AjsMVW+\H?"V=U90PPm(L\;aA*[D-p+TqlM$?oo>:j!6gJ[2d0p:-/+4:o:Motl88O5:2uWVrD;hOcKP.8UOXLVb6Cf3io4XsgBFLD&pmf.33o:Fs0A85!;&;:TTYj@"&c_MX1+GQ+f]Tdsm.Z.3!U&K!,>b3=Poo-jDUY!#+p7VU3I6_jT%Q="%J>\;66AE?Jh72R.n$8Y/iU.rO]T#)HBcV`biN:&ko&L&>KL/R*$*"Sj80EKu#a$;2,$:*tO@!I_OED0BH!*?q!t'5&!Nscba&]:SUj-L:fnpK(/DqXl#Dl:S,^LL=[*l4=(5$f_g))/6[7)dXJV2`SD)uWpbGZ7?K>F/GA<)2Q0HP55l/OK-W7qur+V`XF."G$bg*lD?=[\)tPNaZjL3$_8G1N6#WZEO96al;%cZdFEmom*\3TgYcd'p,m[mf4<_P&aEf)Q3\OS;l4'G1JGDI*h\]H7+0SEDU&N_/WHO8hhE5+lmLXm<&g2'WS>?4Ek[sfBBf68=crFD['EZ'L,>=e/*Pc.Hk@0P$b'g8Q?=85L?\CRNf@U>,6_Gm\J^a\lP2rW",e_fD3'mGmJLGi)DFUY>p$k^8AK@WYZ-GH^!-=s\5q["?h*hbrkH<`*odgYGpf^Y^-UER;6nj%"np-#8O3t6I'+4KMPWg>5Bhbs*9S;b=*kbk'8Si^8*hM"4r>'_[kup[mCa&H2$d>mAZ1B"K/Hnh%Gp\7oWS@$^,h!s0l]p10Na(hGOpUWtPg=YME-hKc\!g9.OXS5s.0ln:J[*EtnTT`Y/<1iKE*3jI%LPah#_ZT:qlKkd,1bI*gu'gc)_[*7$9gQKK7JA\/*$C\n+J&V\0#(88$dm/.ai"8U),,o)"J$$M-(mEVFYke)k/#A%oN/qp5`/1*N)-/7-i\SeeSf+^`e->l@#8QTN!'UBHVWB;(5X==rneA3?&"P$IT4l*n.m86\D%SHt`r'fHk\\^?jHXO01sQB%MHChm!)UVl2bp4j'K(KH?3#p-THWhKYOa(ia[3)jqUG&H8t#4!odE!9]l?'QOd*SZ3RComAs`rn$L%m6f"VIF16rPaC?[P/u!0@tXR+kd6(1paE-l_QnUCWl@^H/DR*`':tcZYTQNq*%uLQ&aUmJg[/*U?4,u@3o>NA]XYa\.e0_W!>XgiqWGi1qH8N(K90snHX9.5B=<>69@9P"H,V'?:EW_=ZU%\"OnQZ#4aX37=S-hq@;BSt+A:I*6sT7U%%/;H6LBK9dBA)!VR@lQ#N[GAh!dDh'Wo3Tk)`1iHJ-N1pMa11p6<_EJL'&UGJ'ND#/Ltm@%?Jjq#05)`iUA$gIOQ'DUpB,cL=DDR(HETXms;_or*F2%kRuBQOdmWZ)Ug6u[RghHl4H>I\@GPlRSWDfufRA@X[+@47q?b*"2i)Uo((Rugp1qQdK^Q;ThOLI3pW#T7],N>TPofL+g-I0UFVqoeiJ"*;.Md4^5P@SJt?3['NF`m/f"*>8+O_s@oM,1b4>.9X`o#&Zu-g?>B0)^1SN+mL^Oi7&XLZ3^QJi.8X]Qc*;(+(lbDrD36O1X8@bcaGgL6"1+0%8%.Ybj.G3"+gf2YR['YcgHhAFKF5h[M6VHE46Fu?Z=$K]9sc^FL^YR53(p>Pt9uJ-ldcd(n-E[\D]/\0H)k;"&UjMM[T4jgnu0etZg*7,Atr'slZ0Hn.r5]N@jWPK@s9`%;"a@b(h@6T3X\f`^08Yra&dgN9cO\gfF%r-m3f7NH2=&O,qO#D@'IU,OnQG?D6-0>TIiV`QBj@F+`6!U(P`]+O]t;nF#Y%P>)!cdf*u@am+pd$,J:X,CX&P?)UjpG)S]PV/S.=5]af$N(rrU*a\5rEC3N-H^N5jLr@$WMjOf-"TE*X:dR@TbG-kho6U9\,jMUmIFnq(;AEoeU$D$"t1-:7MZFG3A5kH=H8Z@'_+%]d`'X8"FJoK$)TWk\Jm%`>iRHiYH>^*SI5DaREolZ1>WSuDkR<:c6-]InAX`9W&D45IYnE,P*,9b/"eBO8Sqd^uK=oKLc)Lk8:9N'gb$/P6%oBndc2*cgt":upYP+\0T13`ZtrRjacr(g4'0G4KoU[&Qth$0=VX(%`N&l8;%$O0h9SUfcPe1!TiBiYfWnZ1CR905i[,1Rt#;tDa0a7#MIJpk4slui4q<*\EY*_TQq*#r7OVKp^.PX84I^h5j!m7Uis;a2u/1Q9$@!a[LZ_Q@17t\R&[M:;Z\)'Z=PZs'M5VcYSFd$@n__r"eCA=,%2<+.U%+:h+m/=`dS@`!mfRc)&/16O)ETu^Z7=J0L?c9?ljmq"*IHOBL*it%%N.h0h4J3U#(@]GU`1@%HqIt)l)N8JTCR<@OK/\s*=Vpn\O*)2X+eDc]Y;,=0/,.d!^PJS,MEFMMSrPMK/ORjMo3!!0_*50?;`^T^KuL.39'+^cT7.-oW5#HXMFqrnCdqL#cU";.B\cn:0g+C'=^J%$$G.l:=)cAbJBo>L6@T3LJ1-jE$2T^Kq)E+uH#1"WkrY5PtfJ6,Qf";ffkM,c?S]A_'$OuE#Rkim:6Q6I8sG20IM>JL_^=I'-Fb,S;=h]JK@kR-$6l45RVF"0[OD]n9*6n:a]2@-8Mrn(,st6<5nl^c1fP2E'%8ZMN2oBH79(c;1^+<+eP*n]9N=La:dYm"9`[YD'#bSb0a(MN3e!,[WE51>e>,N&%tc9<$3G_3j)XH#'&!m]F^jQ.22f9(:eMmk/Rbai>6"hc[I7EfBSeH*k'ADJ3G7*(EY9`M`X:Zkn.(2A3XQ6)Cr>/C(4ZZGM2Pl*(,*8i^C8iF_;\3Oh-.HDGroMeFQ^f_DJsDW'LCp-F(NZ]iBC)kAoP"ZEr'1q_R&en=hj=Lb.fZ^]7,a0Ar'#>B=%JO6d9WQa.D,F,rR,*`6l_@D&`lJKe(A8+'q?!A#0laH7X5`REUQM4:6n2T6=u'ZYb/XQ23/*_*aZC82c=3l[>5iOb%PM:"c.OMfIJm.J;bJ`+OB#!3c6"K+g*GFic^Yr7T=Gn;P?qhrrt%Ye\:QK(]I`//bU17,r>BHtYKj>\4:%HQ!3QIN2OH=Uio'LlB&S#D-X1C.SD@OPrT$&/q-YoLDBLb%u^^i'D/j3e]I'%feq0kLMSV4`Zs-3UX]_ZIcnLo'Q/#&cd8#WkZ/(-;Wg]Zh-s6g>2<_7,3]W!rjTU%gVlnnC]7`ql(?X0M+-RY0XJ(=TN7an!_fCsNW2MmE]\JsR,,RPiMdG=f(TTj#FW5U%V^(K=0/`oTGRg<#Hup]CU&-94m!\.2&hYZX"IkJ)!,I[@%a)tb]s$PNOG>SkbJ2&/bQDtjmHL1^40Tt&qd58cS&Ha:W!)kTd&<%GfIt!/`"7#"R*"uETnGe^.q:[M`?8+rY*G(IsU3N+Dbu[-TgLf'[fqBP]7HtO!Th,;V*6(K@G_4"T/,7:#VLA"-Dp4XPQt@I,c/g(:347_R$$uFn@(XJEIi!=+SNa-;U#T@N`ub0J-KEB,D%^QZU"SZoF6(ftiHEW$h8^#ln5sl%)X!&`*:R[HG=Q,^3S]B*4AN#i1_=DVWh.`,B*LV<_2_"rFDG![N1[*P%Y]p`??d>)+J5N2G:YN]bSVIQKPMJRY212/8Re#GbGHuW/1%NR%@:UZaS.W5P+*JYAY>pc`'fKK"+tL)bu(ei*N(mCON`V6b;+\OUg7GqJg1qH(W]S(G-H@DX%Ka`M[Y+>.d5f<'>2lUJ`H-\&I]0l:U5/MeUd!^eWLkgU8d,?=DJ29r*P[)WpLA1J!Q",]1Tqmq1KH=Kku(En#6UQB0L_;f1Lj9caj^7]1C.d1)&';#Kq57!gBZDY2ro_%$eb8L^Z)USpbH'77K]8`d(/KII/gq7((#!LP_oVM+O$??;`5"eB4Q[:Ch2Z.tS?LfQ%K@cdX9JWt\[?<\^f]+IrI!YFoiU2;n^"J_;3nmFlZt;5Aj?=u6Kgpl#=c3G^,=!1Ga:[1rX?W0fTuTTDo=g_d*11n=AXI(P@[S&d:d8(A-/!9"6]"PB>GBPE+KX/4k'W11k[rSIj!LhRDe+?KR73Hs8;KMt;G7j@%.iA_l(RYhB:+K-K?9Fi.^OBq,oGr1Tr$A_TM]cB3;g"*]hn=QorHH0DmSfl*KJI[c(333g[&fU0Yg96rFW#uM?TMltA+\o<0:Dc3#U4=4)TAY1mr6gg+0a^a\,W3QrVeYq?Rl!DP,ON#bmIl3lLmSM(3Y<5i"ofnNM3=#OV5BW;-jYN9QmimkJ7N@_TVNK98-/Qtr8@kI_:'9[:;`mW6+.dsgb`te`0c)7CPdBTH93s,BfZa&A@)Q#K%AKBB8d\0NH1IHSEf\b(:J8n0&\dd+sV;(6Li.](`>^b7[$AkH`TMd`h1,@E44*'o,73lC!MS7isjRHf.7oSMQ;BNF[\6nq*'/JCJm3&Uj\T-cZ0`-'%t+HF#mic>cWED7;1N[fC>L1hVPYYn.o:.0q-Td^^d-/k+8866G3&4*E'^[GLEnAeAf#;>!3174>T*.U@:c6epkdu.RRQ>JE6Z?+#sZ`I_3AHrdDNUZ)O6Pr2Xj'SFIeDk((a`lN$%V>&%994\$RiKW&iDZad??K\YCq?_]&=C&"aho&KENh_'#FagMlGT^n=_@E$lQp*Pj:&I_o4kg!C;e^lir\t\DD*&qp"U%72%]m$l,nqb6$7jQ;j6(!Hde_;b3Q;j[j:A%X]2C.Wl8'E3p2BJ[_g?Z[Y;RmeMp64Z"l)*2e%s[B&s5T@haLh'HLsgg01dFl60N!O/EoBBtm5Pcd*p7XW,0AcB_[P1iMfU[rn]9(e)Im=gH!s#lt&*V's$oMq,YkSMS=,qo93n_n[McVTcf$f]I`!P=kCXDXs88KEO@C,n]FP!dhp!?M^J_Ypu)%;LKIJJ3omB*]:W-RgKgr,lT/[U/)3@D)Ut\Ummkb/pGuulpHn[$R!Z1.8_YEl3s:F=5@A,?7J/?_EZGp0UR1T1S@W6u3^[nI96=3%la)A_f$Qt-L<*HD_['L2;!FP^NnMu)1e)2[P_Y1g1t3cf6P`.+'2eSC8JV]Iq%R+enN%EtJc!DmaS?65YqQ,hTbJS70po_#R^:Zf!o\0ECajf1GUKMFb(G=@mA&fuSO&!t4QuTGdb4R8kZb9N*,TH,dQgJbTD#=Y4U(e&"\2L+gTtt:aCeVAapaQAPQe/Y=CRRX17l"6eRsu^+4rK,VSCI6VZ$"Bb?QCGgB1+.r5<&Blmc/5&N7AVAEJ0GUojq)../H>#;M:;@fJVFIj/4]P&Z1]Pq-aW<@'3S$ZZe"Gb=OB^a'iPn;krMSHu4IMB;5pu;2Y_7>:A$k(k#VC24haV7ad9;<(5ZWF]BYa_ATp6Y^<#!Wn%#$Nk8qbX!`^,IQd/E`jO%Fc.L>1%rFN!!tA*0BqDk)AMTd'^l%bJ/e$?pg@RZU7e?HP)I;Qql*Z>Bm5$S.F#XeWR?cqj9'qCZZ]^p?Zl3+e['/#rV]*9iBf:+E6[[[3]LCkVadsp#fj9>7"p0(9"B>0Z\RI;9,*qf1A,AL8+o.Mn(,tUlnIZ,dAF(TcSIOCQ>Bt2f*7bF,5]]X^^a,7gP?TmM1TeR\B8Ns*f>P31(83b-\s?kbLd*<>!&\26!nkTFYq(Nh!,J6"YqDQ6=BITdPf07.LVT"3U:b$a&FtD:8rtL:T$DD4*H`kd@kCGFLm&^+;Pr1t)Bu1lXkXm5kRTo-bh0Rile]e<+uj?981#0*5:Xj6B87VqK/u_%+c"mu-k.E'#8<4`Rk;m\*h]8k;,XHMlQP(olg(K4C4$(?.FLWW\8$.Q6PNX^XuKF:FC,G"4TNA!8rcgrKqhcm,^@E1JF(#UUr]96lq5^&lp>AF5MKWWfR;G;pkp$_F@=15GM*8GAse@*pip>lph(N=D3"d'@a/Ce,%./_hY#*!OiB6D4S"sSHKQlcB4Y-QQ#h\=FHM/1PqobaQ7oc0Fd#XcRa6hgL30AP@6/XmHjj\1EVh(AT*ct=8oArTVsMnan@@/>09+[&>]]&KN];`-*q%llS.*=#nN:7A0!jc.lT'sS44e".6g33^Bm(!EA20`r*J7,8/1r6t)C%GJQUqdB@"IScb!qo"f@kUnXD&R&"K2nm_UOH.,p0Q(Tu;,SUC1hc08_:"lG'r=.@$?AXE$p_;/_RW1<9#MM6c4p%\XJ3TnV4F_J(*$fU!'%oKKh=cB2=Kip8)bQ_'Db0%jL7g>T_`$W.jG[R_&GIFkJ22>r]L(.u+W_h0#F\SpXPTWO7;NiXVKH>jn8F,?UF>l&MSq]b))_\!9Pi0',PULBj(ilL;A=\8JLkl??aX`$2aSnf/W_*sboDj8H2&*ERJP+?B!'q&"_^J331(Zb]$Ep3@Koao9Eb_\83Y:16I%*N(8>@C;BB'jY^*V?okf2p#^-*Y9^VE"4DB%Y".5MZRCtJPL'*N/(;O1[_nIE[iZ37"Hb*Ff,.;g,a70*'&Ld(R\F>XRQr&(2i"Srbrugbl>^M':M@S?.*nt44tu'Mni4!c.Ni>\MPp=dDVO#L9[[4:"ImVX;($7QJg79_alfmka;NYg>;7)ZS."'qE&`D@_3;7@_X4">\<0*CD4Q_k1%jp%;I3j?2dNk(@O2l/)6gB&NUG1HJ>jB>!p`:)79_4'VO=;Tmu'Z$6+$A/g1+o><(-3o,KC`BZR``LPs\MDI23e:Lrb3ck/G^0=YA`uE8lHsPN$XO+aU=:.\;.!FN.9)i^C;63f!]XML=,Cbu;)$%>PE3Z@[a,=J\WS,m?Vd+/paM%<')P7fbopK`_Hg=ib!*KKfHh57cK2WP*+F,p-JR:>&;QI1%Jo&N`i?[6a#uJEFG3)trp@>#YY;(`o.219.Rb;40r7;QFs+Yd;,_R$\MD'.MUl[]ELnHl\pNi7;N+f=a[RW%30%"h,0.[\Dj.1P'0`X$R?%fhYT!D?a4Tbn>A2amLU%OZkk+9Y1/ds?21nHVKRqq@"*"Q1"ud._ZMHd+4!")\6QEI!!E96n\X1-0&"nAcYH\V"I35%(dS>q@iI5e>WV)$-7RRfE3J%&OF7_YsarPt;i(PP'.EWX8+Io]I#ng#`;SjKL+[oU(.76g;B+J3Xo8QJ7$"MS(.87\FZVlip/2g/)EA!"h$LRBKt6fA-L,X.su]rV=dV5n@`j!a96@.",?*$s83!/1s3mX$+P\&C/O:d(I3gjkrJ!bJrK>'V_M,@<"],K;"C4c2N]=RNf-SH#&Ch4N7ng#H>O+T;oIUXC2%+OE?+Q*,b^\n$,.JP*@.=!+qm\Tb:c@L]SCp,(LpF.Z0r=&t4ZRJUh2E!Z0p"9*t)hWRu'lH'JsO18Gd@leXp`ra?Ss7\VUb6@X-to@c1s8='l?Gh.F%m%PF![[/!q647I#Yi;>+")LA'.=S)s[`^t'5a@*p)P[.]U8)t5RO]kU5fa:T:KN`W]%$mu5R2.:]>,OO[LgQB,+(gtuQt#VOZ)IDX059:V!\gLuPbZ6,V'KG'nN6-&4#R1`(4r\I@o-RL&:1fH(L]n9(a4hJ9*p+LUcAR7fPL?a\62)7^lIdrJD1]Nm'Z)u8SK=KpV]9Ml8Pt6`=g?D!?#cc-U.Gg+Y[Sc9>P^W.'j=qVV5mGOO[`,/sp"hoUejsp\TQ\D)KS*KeUcE6'+Gg9lUlI'H++ST"IY12ikaB56^r.X!U"!tR[kcae7fot\'-&$4K=XT]q4/n<\_?nJB4Rs%1/(Ysg_h&W6)C:%O&L::M*tK?\:Jm28F0eQ9K-+g)MAim-s4a+mD'!a(GfeM.&UEnfOCYqU;e2bj&FYtP3JeGZDFrj-=7M8";o\5"Oh0f"pqWG)Dj!!K0Ig+;aoHa(NklX_O(5H6J+"QUc-'$]tlid4-?bd1J5/;F#<`-9_6/%qDV[5$_@O8MjeetDfn_9[;Tn7'UF!V8e88N*;"MJ7k4USUL*O]XP:d_F8+PK1q=?-)>JOp"a:KSZYCtp9Ke1(3"ZYMLI%CUFY_*f[GG^ipk"H.8=*B4`V)$Ym4K9.sM:uH(6Ku+92'FhbYTdhR!C6?XbF_a-eNj(.1rAC(!6eH`r&gA@qn2AckF;6)$ML]YkZ$?B@5f%Or0T[.b@bYV!HkN!>Sdn/^$`\<2+o\E+e&Dm6pF1?uQ^@WU@n&F+O6nH))RR<<(0AfI(&ZV2:+i.$:%:D_c[KM)@A^W3c@ojtMbU+^RXV#bJ;a*dC6$EU"-FTf6hZl?%1S5rfs97`a/Q3hWPUa=64X$Hh3`/71'G&]S24&*'Nj.HTIGk6-R1R!I7.52^>ENAiAi2u;?$OAR*ZS5R-NA;Om.;?&G.?&4be0=0e+%I.m@EfHRdhMo:Gb/C]hL6-'GQj&lBHq499ZIKs*F4`Wd\*ZjF^eXOAA<.0=LZV7hO"'n/o&u&K#jdQ^I(:lQebIF_da2"OT(653s3bA>?$?/;.l&#Llcj8VaF0,?GNGo.=RI8=iGP$!H_X"RT";^Q^8>_HfF9nb8\>(g3E;7[qgR0t]dm,2X43#c?d=Dd#WU1?SIbYEO.6gHbQ0>VpeTK[(%-ujZMq`J($)U(P@d\^\$475s=enK2&i5cs,RN4qGG+i8`d%2_qWC"73T?Q,&8Ps%SF@5T>kj`T?(:HL5E=KRq:@>Qc$[X)0_dE;i8#fPG5W_Q0>kW.J^.V,!"HNMXQ>2O_\<C,jX,JT;%qSB+^Xf\cK0GeajW32qWdAW*_CeR>s=`P2rcNNC1OJJa]qYg@=G$@H(\\/h\qi*Y&;94Uot3f9O;-aeu7P`9"K#/(EF30*'.@TLm(:4;'7h.,0=qt/apnI'L&6hT!)aj8>V]Tem6[I=$!u44]C3k)>J6bhU>C?+UbgEcuTupDh1=B,Z'ZWt,2Rs/c/'-(@9>Ra,[=d8ul<=M?=,F(:\?KeR,?4$CNL,l9#1#Y?fX>Fp"Wd7N&_bG)(o$hbE4.5hSWc%NKQIIpQZJ^n$MJ0EIibK`\jj6U]R[r&`cUk'lX7HJRAr8r93sMMuNHG\,=q^KOJn\;Y@BCLsdB;]8BM>%/d45]T]eQDGtS<%KZAMT=!mH3E\;AV>BY<7sYHDH;X.@Ciqo#g,RbH'jj8E^YTc"r-!dO]g\lKh48`WE6H>HI'*l'Xi*cm4/cS]64t0*CTQ6VPHaZ@TL\r/&ZWMIl3gm9%R[.h_N`:QA?Zo7870R;Cql*@)0Q]#YH$iTGP1Jn@6k;YlJr6RKnB.#?,K)i5C@O0JRk`U*-+t8Pmh8m@DTOR,6k[k3XQ3\/I9<>jC=s4M."gCBc2fN6TB6pJ^9'TB.Hs1D'l[0Kn]-p*(tR]D'm0:JuJ>@H@1qU/[/-H/J\?dEPnEaZ!:I<`R:BO08Pm8G@*f@@\b=M]5;9a7boi4ujR[?W*^#IqJ+:Xh@Yr!X;'%VXQ/;B"j_:b+Muk2bZ(\j&oB#nif=W1X4@GKIVVn%n8MrG?0"?^qL`2@5=VYUm@XWP5A$$,J7$66?ZQ'oiZ>0,S*7lDshDM2]\s8gq10knJ5ZblsKhgJ1Et$$nW2cVRZhEdVa)WEoE@(0i"Yu#q]\qc4@oS9BOf-:LKsQeVO,Ehn66l^s`]"YT/n`aoH3j.Rhda\PjUMsPUNMg@.Udd8E(q@;A#>H",nK:@kp@QDBK9+$-(0\J:mrK%*bj>!c-6ru<60#nWNkfnPDJ6.10?f4m\;4I>bo*,*=H"6g1`!^n1?h''iL5cUplWtS)^TKj]-n:8bCfB\$E(bq.<@/r1Dk#/3s8Wq5,0bXmK3.=uZ9S\mJR%*i@#RPsQfF-%-_<*^2;B::,5Qjpm844Hq#_MWIBqcq<7!s2RZG//mm?"ioL`bK=ciLpJ1pdfY]-_6pK2b5IV$e_+1(b]4ikETo0<&$/&5>DM+V5c6askDY_@^`0:Q0kd$/I"R6M\c='b0+gO[,oM.4BPo[;O?TZjJPh*t[&+kn&)n&sG/nd*+;hSVg:mYA6MO?"I5h1_X8/g3-(2Ln']13!eZ:SKOd?IQ:#le6s'h^DWY_pJH-F?&#;;le!(5FiBq+4bH>/[N=%=;Pb@TT\sf>J+)0/l?S--4t=Ba5JqGC-*FIKH3P2UNm9b22]=q-/%B:ceH;^VU"b2Y0?AV_EB$>kk!as@cY6J4k[Fk9EpUHlWqCj:()Z8MG3@_-Eqs2JFch_V`];t2*W9WC%@h`Z#J`rl!j\4!sJ5LDeP4si1T0/JXie1i#(eo?E(C+B>H)#LL%/uJF)BFp*14?56j53!jgISW'Vp;!q>o5:jd=1*S%J[X*#E2rOKV]2//gD]=@?"R+6?=(VEIs6@($F^MKcbjkd==M?8Kgqr'.QR:4-)S:3t+tO<8?ZWi'macLI_^^N1*FocS5$p#Ef&iLXQSOkQ:lqC8*eb:R'j#SQYpNI_A#+fH$r4T70cP+Yr9TN#1+E(Gk+@)LWBMj85m(Z75g!">3)2Tfcd#lf-`m)C*W=LD9#=tU='.uM=>AJG.d#rhIPNd]hYrd0V2WktL`;L=.&7JlG!F8iX$eE'e(Em!)_7Q.Vl[mX35&461\WcaI9.%sJuX^@]54OJQ$$nre%XVYer*sJ$^B#Y%>/=B9G0^k6(nuSBHpQpQu/B&]Li``Yn;[=\LEp^lL'pKb:nkh.&U=W^1R8kekjrMWh=92US>b4lChpc!>*)IUO-`B=Bq&.NU<*ZiSGjJ:=]G&+S0k%g5i/ZccbdD_>-E>H95*1%%&$A.J.X[^^\Tpd"e;kmQ,6;BJcoDiXt4uk<0-NC_.:2(uNj5Ni!'`*>QJkKr^uJii^q9r;(u'WcLl_q4G[VtMb#"Qe;+9-W6)^Ot4;+iC)ad%*;-plnRcauJ9Y3=l#F*o/Q@]aRO?5T`-LeO=&/,;4*hd->'O2a!9^2nN240)!K>=QJq>g?6H&.55@M7!`5X3Le9?XOo0Cj_D6rY]`uE.*?Vs"5V`sK,m>lDRCg)%coib)N\K4?L'^8"5d[NPHHJ$.6D'q&`:f!7a]3P6J11e2DqdD@7S-c,JruFnVPso3OJS7N(-Xr.^coi&&)Z"YGSk^VJsfHt6@Y/u=Sa^0(U%BQi+W1C8G7i5[cBY5pQJ<++5*cs@']PuFH9Fq1`?H]O_JJ9Wa]A[V[-`4%VO#SflC/IKGl\q#RFdH@LdKpUa3DD2pA/nE93q/)o3mr(%,;f4V5L4-5/V5kHY?AZ1dC3.@7`)\eh_:W5&P43I8T%"*&mFARst9@f-NhSjE\J&9I3X-.>s/Gkb[.#V9N8jPD,3PPY$J!c^?+QjB5nE_"YL)Rt$!(jhpZ\0L^PIGt%f2+[i>V68qU`*p48PYpO3.PZRkYL1fI6c4*cjTW1#jOct$tVHK+S&QX,q+ADe:b)::$45WO.=lp,PeVf<&@$5F7eKK1_i.2BH85[_TAUp>[b;"fa/*0:n#TIn7c9dKgESW=oj%oe'$S$"TsN>W;amr8jhfdSS)l-R0.2Y`Z-,[:mt*`g3YNl5pGD0q9Hr_30%YAReQ@tZgjr\`'rgeEU1=q"T?PS!?iFW7dL#!*d+dp8BdE6_9)>T*CI_@UnqJtd^I`"24#,oDI^-mASha74L1HElU[QE="l6NPrm6t[$+4+VsHEdZP(I1\N<;%=_Xg%!QtT5;F-IQE#G(;9B8;BR%1N+_'*`i$r;,SM$frL]H`WkJ?K+rk*G46bAS;g'0+P_-R`IB#l=pN]!@,O"tp%gaG"n*]0"CB=k!X`+A-3h;j2@W%eo#OuebGb`7OJ3sicfb)s%<\@;l$Y>Rg%)+32:qu.](ot(k]_bVi/lrG3=RjHW**>/qgRF0p4&_6^Ure2cgL=QB@6^NGPjRQ^]#.`So=#jp9Sdgli3$rqS.ftr][OXs%i7`J%OkA5Q1Pphu3*En,IlEjm@P`J)1"3`T6bsJ=+=ecNp!EH@lo]Q&8:cHi(%XU0YO$1];tE5u@2`$!6uP=oH`t^LY"?;%]qZ'm#31gu($ZAn-qjKe._?^+oY,Nj&,-i!2eJY_P(Hl9kG9:QXfh0l_pHQjA^KICu'tjPNaX0sc]0rZMK09%G:AgT:`]BHQaEO>!&PAJ^,H`qdJP`P_Ulr&RRl"p,Bf4"'Pp[PMZk.#:B]MM)FSTgW*96E1=`fni'FjPE<%%fX8WG$&10(g5auBoc,KXEjk#GH5XdFq3%7;/8U"TQ9n_o3qRsaYhp[DCnh=T\DBPV*mdp:ESP3s"oeLXT*[F=5)E.Wf3gq9(u=P[m^fD_.>k%jf93>Xc,5uc9-2I(78hkZrU4LV,f)TOXi:_1LtR,gHql/7@#(WHd?l4T)J2+5i#Q<`g@R#ir)f7#,1Ogiea8f^4"F(R,3Ligi*Hg]&jeV1MCmM$rYQo%87\H9$a:ZHS+D>VEU;TaD'j$:'K3JH;bdRL2H:PTL:u%n%fA8PC99R+L]T4(8i*,GTCDgI@(SM2b/5<)D,NbN__CK!ED6H1PJDmK@;_ql4X8,oNV8Y+XBJZB=RX*ALL6?>G7fD=L$oUB5$E>TMW?g4]Yu:".Q9G_[X3dA.^&74OF2bMCu@j#(kDoJ?7'nnZVeH+UYADjMf&2#B]!bq0:ip2F]o[!t2jB&#Cde=M@6WYYu6KLOBJdR-Q5GV_'Q#l.n19YNBqa0r@o[rt^O3V]4MT!JI[!JSp"S*T4Olm,1Ok[QIZP6YrAqLWX$4mCg`p-.r,"[a^o)IEn)CW7l*T6#GR-[EB'@Id'+c)g?!i_uU5P\-j2uC3'7EK[K*bpJU*"3?^5]X(HhL\i=*/UWFYVmTX#hCGfO4M_Pm!`^T1LWZh-+Vh19+oiho\'1,jb!\@]h7IO.*dTOHfRDjnEJQp?9,a%cBm)]F'I[(<=;OeF'K!G8d-I\1JAs.7.!T[V[8N7oR5hZTB'c;2:J8HQ2.D,qKI#]ruH(/BJO=ER5Ca1O1$5gG_\^-F='!O)lt1On$cd=^@uO(s(6b1ruo2*k^WA?pU0`:5O2a:dm*Y!*-8FK3H^j%`R?an4S)fq)9b5iMdbHWAVe=oH+i)*MT-6^*ce-&QpmNJ, # ===>END WOOF<=== From b43e2f91902ce161e62934c58c863e4c2be95366 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Wed, 5 Sep 2007 16:28:55 +0200 Subject: [PATCH 278/278] add failing test and fix for assignment to self --- src/common/packet-metadata-test.cc | 14 ++++++++++++++ src/common/packet-metadata.h | 23 +++++++++++------------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/common/packet-metadata-test.cc b/src/common/packet-metadata-test.cc index e3e61c45e..edca62626 100644 --- a/src/common/packet-metadata-test.cc +++ b/src/common/packet-metadata-test.cc @@ -217,6 +217,7 @@ private: template void RegisterTrailer (void); void CleanupPrints (void); + Packet DoAddHeader (Packet p); bool Check (const char *file, int line, std::list expected); @@ -430,6 +431,14 @@ PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t } \ } + +Packet +PacketMetadataTest::DoAddHeader (Packet p) +{ + ADD_HEADER (p, 10); + return p; +} + bool PacketMetadataTest::RunTests (void) { @@ -659,6 +668,11 @@ PacketMetadataTest::RunTests (void) ADD_HEADER (p, 10); CHECK_HISTORY (p, 1, 10); + p = Packet (); + ADD_HEADER (p, 10); + p = DoAddHeader (p); + CHECK_HISTORY (p, 2, 10, 10); + return ok; } diff --git a/src/common/packet-metadata.h b/src/common/packet-metadata.h index b193093f9..12223a4bb 100644 --- a/src/common/packet-metadata.h +++ b/src/common/packet-metadata.h @@ -306,24 +306,23 @@ PacketMetadata::PacketMetadata (PacketMetadata const &o) PacketMetadata & PacketMetadata::operator = (PacketMetadata const& o) { - if (m_data == o.m_data) + if (m_data != o.m_data) { - // self assignment - return *this; + // not self assignment + NS_ASSERT (m_data != 0); + m_data->m_count--; + if (m_data->m_count == 0) + { + PacketMetadata::Recycle (m_data); + } + m_data = o.m_data; + NS_ASSERT (m_data != 0); + m_data->m_count++; } - NS_ASSERT (m_data != 0); - m_data->m_count--; - if (m_data->m_count == 0) - { - PacketMetadata::Recycle (m_data); - } - m_data = o.m_data; m_head = o.m_head; m_tail = o.m_tail; m_used = o.m_used; m_packetUid = o.m_packetUid; - NS_ASSERT (m_data != 0); - m_data->m_count++; return *this; } PacketMetadata::~PacketMetadata ()