diff --git a/.hgtags b/.hgtags index 1394c82d5..d0737c2e5 100644 --- a/.hgtags +++ b/.hgtags @@ -41,3 +41,4 @@ c975274c9707b1f07d94cc51f205c351122131a5 ns-3.5 79ff6ad1adbb7b4677759ddf52028b68b0515168 ns-3.6-RC3 39a82d7a0d661febe42e75f26ada79424258e330 ns-3.6-RC4 d55c479666ac6be0575fac695ddf355c0530e0dd ns-3.6 +892efc87a1518fb69b04628c779195aee139d33e ns-3.7-RC3 diff --git a/AUTHORS b/AUTHORS index 8bdbed2f5..03fb40d64 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,6 +27,7 @@ Francesco Malandrino (francesco.malandrino@gmail.com) Fabian Mauchle (f1mauchl@hsr.ch) Andrey Mazo (mazo@iitp.ru) Faker Moatamri (faker.moatamri@sophia.inria.fr) +Michael Nowatkowski (nowatkom@gmail.com) Duy Nguyen (duy@soe.ucsc.edu) Tommaso Pecorella (tommaso.pecorella@unifi.it) Yana Podkosova (yanapdk@rambler.ru) @@ -35,10 +36,12 @@ George F. Riley (riley@ece.gatech.edu) Providence Salumu Munga (Providence.Salumu@gmail.com, Providence.Salumu_Munga@it-sudparis.eu) Guillaume Seguin (guillaume.seguin@sophia.inria.fr) Kulin Shah (m.kulin@gmail.com) +Phillip Sitbon (phillip.sitbon@gmail.com) Ewgenij Starostin (estar@cs.tu-berlin.de) Adrian S. W. Tam (adrian.sw.tam@gmail.com) Wilson Thong (wilsonwk@ee.cityu.edu.hk) Mauro Tortonesi (mauro.tortonesi@unife.it) +Andras Varga (andras@omnetpp.org) Sebastien Vincent (vincent@clarinet.u-strasbg.fr) Guillaume Vu-Brugier (gvubrugier@gmail.com) Tom Wambold (tom5760@gmail.com) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 5dfdbc846..175aa0055 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -31,30 +31,92 @@ http://www.nsnam.org/wiki/index.php/Installation New user-visible features ------------------------- - a) The ns-3 logging macros (NS_LOG_*) now report automatically the node id - of the event which called the macro. + a) Ad hoc On-Demand Distance Vector (AODV) routing model (RFC 3561) - b) Ad hoc On-Demand Distance Vector (AODV) routing model according to RFC 3561. + b) IPv6 extensions support to add IPv6 extensions and options. Two + examples (fragmentation and loose routing) are available. - c) Net-anim: - - interface for animation of point-to-point links. - - dumbbell, grid, and star examples in examples/animation + c) NetAnim interface: Provides an interface to the Qt-based NetAnim + animator, which supports static, point-to-point topology-based + packet animations. - d) Topology Helper classes: + d) New topology helpers have been introduced - PointToPointDumbbellHelper - PointToPointGridHelper - PointToPointStarHelper - CsmaStarHelper - e) IPv6 extensions support and two new examples for fragmentation and loose routing. + e) Equal-cost multipath for global routing: Enables quagga's equal + cost multipath for Ipv4GlobalRouting, and adds an attribute that + can enable it with random packet distribution policy across + equal cost routes. + + f) Binding sockets to devices: A method analogous to a SO_BINDTODEVICE + socket option has been introduced to class Socket + + g) Object::DoStart: Users who need to complete their object setup at + the start of a simulation can override this virtual method, perform their + adhoc setup, and then, must chain up to their parent. + + h) Ipv4::IsDestinationAddress method added to support checks of whether a + destination address should be accepted as one of the host's own + addresses. + + i) UniformDiscPositionAllocator added; distributes uniformly the nodes + within a disc of given radius. + + j) ChannelNumber attribute added to YansWifiPhy. Now it is possible to + setup wifi channel using WifiPhyHelper::Set() method. + + k) WaypointMobilityModel provides a method to add mobility as a set of + (time, position) pairs API changes from ns-3.6 ----------------------- API changes for this release are documented in the file CHANGES.html. +Bugs fixed +---------- +The following lists many of the bugs that were fixed since ns-3.6, in +many cases referencing the Bugzilla bug number + - bug 752: Object::DoStart is not executed for objects created at t > 0 + - bug 767: Incorrect modulation for 802.11a modes + - bug 725: wifi fragmentation and RTS cannot be used at the same time + - bug 782: CreateTap () requires IP address in modes other than + CONFIGURE_LOCAL. + - bug 769: Queue::GetTotalReceived{Bytes,Packets}() broken + - bug 738 ReceiveErrorModel called too late + - Fix NSC improper response to FIN + - Fixed bug in serialization of PbbAddressBlock. + - Fix bug 780 (problem in RoutingTableComputation with asymetric links), + while adding debugging methods to OLSR. + - bug 759: Ipv6 uses wrong outgoing interface. + - bug 770: IPv6 size calculation for unknown options is wrong. + - bug 771: Radvd does not set ttl value. + - Fix bug 606: Arp depends on IP routing system + - pad out CSMA payloads to 46 bytes if needed + - Drop CSMA packets with CRC errors, rescan, dox tweaks + - Add FCS capability to CSMA + - Mesh:Dot11s: fixed airtime metric + - Get emu working again: Add Dix/Llc option, add and use contextual + realtime schedule ops, don't refcount realtime simulator impl + - bug 695 - DcfManager::UpdateBackoff () uses slow HighPrecision::Div() + - bug 674 - EIFS is not handled correctly in DcfManager::GetAccessGrantStart + - bug 739 - OLSR: Strange HTime value in HELLO messages + - bug 746 - UDP source address is not set to bound address + - bug 735 Update Olsr for local delivery + - bug 740 OLSR MprCompute () works wrong: fixed + - bug 729 Enable IPv6 over PPP. + - bug 645: fixes for opening stats file with OMNeT++ + - bug 689: default energy detection and CCA thresholds are changed to be + more realistic. + - bug 733: OLSR MPR Computation give incorrect result + - Mesh: HWMP: fixed proactive routes + - Mesh: fixed FLAME PATH_UPDATE procedure, fixed mesh.cc + Known issues ------------ -ns-3.6 build is known to fail on the following platforms: +ns-3 builds have been known to fail on the following platforms: - gcc 3.3 and earlier - optimized builds on gcc 3.4.4 and 3.4.5 - optimized builds on linux x86 gcc 4.0.x diff --git a/bindings/python/ns3modulegen.py b/bindings/python/ns3modulegen.py index 148f464a8..6bbe41af7 100755 --- a/bindings/python/ns3modulegen.py +++ b/bindings/python/ns3modulegen.py @@ -95,6 +95,7 @@ def main(): ns3modulegen_core_customizations.CommandLine_customizations(root_module) ns3modulegen_core_customizations.TypeId_customizations(root_module) ns3modulegen_core_customizations.add_std_ofstream(root_module) + ns3modulegen_core_customizations.add_ipv4_address_tp_hash(root_module) for local_module in LOCAL_MODULES: diff --git a/bindings/python/ns3modulegen_core_customizations.py b/bindings/python/ns3modulegen_core_customizations.py index d82aa1e63..807dbabb0 100644 --- a/bindings/python/ns3modulegen_core_customizations.py +++ b/bindings/python/ns3modulegen_core_customizations.py @@ -572,3 +572,14 @@ def add_std_ofstream(module): Parameter.new("::std::ofstream::openmode", 'mode', default_value="std::ios_base::out")]) ofstream.add_method('close', None, []) +def add_ipv4_address_tp_hash(module): + module.body.writeln(''' +long +_ns3_Ipv4Address_tp_hash (PyObject *obj) +{ + PyNs3Ipv4Address *addr = reinterpret_cast (obj); + return static_cast (ns3::Ipv4AddressHash () (*addr->obj)); +} +''') + module.header.writeln('long _ns3_Ipv4Address_tp_hash (PyObject *obj);') + module['Ipv4Address'].pytype.slots['tp_hash'] = "_ns3_Ipv4Address_tp_hash" diff --git a/examples/tcp/tcp-nsc-lfn.cc b/examples/tcp/tcp-nsc-lfn.cc index f4cdd0bf4..30b1e2f6e 100644 --- a/examples/tcp/tcp-nsc-lfn.cc +++ b/examples/tcp/tcp-nsc-lfn.cc @@ -42,12 +42,6 @@ using namespace ns3; NS_LOG_COMPONENT_DEFINE ("TcpNscLfn"); -static void -CwndTracer (uint32_t oldval, uint32_t newval) -{ - NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval); -} - int main (int argc, char *argv[]) { @@ -137,10 +131,6 @@ int main (int argc, char *argv[]) clientApp.Stop (Seconds (runtime + 1.0 + i)); } - // Trace changes to the congestion window - Config::ConnectWithoutContext ("/NodeList/1/$ns3::NscTcpL4Protocol/SocketList/0/CongestionWindow", - MakeCallback (&CwndTracer)); - // This tells ns-3 to generate pcap traces. p2p.EnablePcapAll ("tcp-nsc-lfn"); diff --git a/src/contrib/event-garbage-collector.cc b/src/contrib/event-garbage-collector.cc index f3280fff1..8a8dc154e 100644 --- a/src/contrib/event-garbage-collector.cc +++ b/src/contrib/event-garbage-collector.cc @@ -138,7 +138,7 @@ bool EventGarbageCollectorTestCase::DoRun (void) Simulator::Run (); NS_TEST_EXPECT_MSG_EQ (m_events, 0, ""); NS_TEST_EXPECT_MSG_EQ (m_counter, 50, ""); - + Simulator::Destroy (); return false; } diff --git a/src/devices/wifi/dca-txop.cc b/src/devices/wifi/dca-txop.cc index e19363591..eba746669 100644 --- a/src/devices/wifi/dca-txop.cc +++ b/src/devices/wifi/dca-txop.cc @@ -269,10 +269,10 @@ DcaTxop::Low (void) } bool -DcaTxop::NeedRts (void) +DcaTxop::NeedRts (Ptr packet) { WifiRemoteStation *station = GetStation (m_currentHdr.GetAddr1 ()); - return station->NeedRts (m_currentPacket); + return station->NeedRts (packet); } bool @@ -399,9 +399,16 @@ DcaTxop::NotifyAccessGranted (void) if (NeedFragmentation ()) { - params.DisableRts (); WifiMacHeader hdr; Ptr fragment = GetFragmentPacket (&hdr); + if (NeedRts (fragment)) + { + params.EnableRts (); + } + else + { + params.DisableRts (); + } if (IsLastFragment ()) { MY_DEBUG ("fragmenting last fragment size="<GetSize ()); @@ -417,7 +424,7 @@ DcaTxop::NotifyAccessGranted (void) } else { - if (NeedRts ()) + if (NeedRts (m_currentPacket)) { params.EnableRts (); MY_DEBUG ("tx unicast rts"); diff --git a/src/devices/wifi/dca-txop.h b/src/devices/wifi/dca-txop.h index 69b8a050f..370bd7c31 100644 --- a/src/devices/wifi/dca-txop.h +++ b/src/devices/wifi/dca-txop.h @@ -141,7 +141,7 @@ private: void RestartAccessIfNeeded (void); void StartAccessIfNeeded (void); - bool NeedRts (void); + bool NeedRts (Ptr packet); bool NeedRtsRetransmission (void); bool NeedDataRetransmission (void); bool NeedFragmentation (void); diff --git a/src/devices/wifi/wifi-mode.cc b/src/devices/wifi/wifi-mode.cc index 60b0814df..e21e84ba4 100644 --- a/src/devices/wifi/wifi-mode.cc +++ b/src/devices/wifi/wifi-mode.cc @@ -148,9 +148,32 @@ WifiModeFactory::CreateBpsk (std::string uniqueName, item->standard = standard; return WifiMode (uid); } + +WifiMode +WifiModeFactory::CreateQpsk (std::string uniqueName, + bool isMandatory, + uint32_t bandwidth, + uint32_t dataRate, + uint32_t phyRate, + enum WifiPhyStandard standard) +{ + WifiModeFactory *factory = GetFactory (); + uint32_t uid = factory->AllocateUid (uniqueName); + WifiModeItem *item = factory->Get (uid); + item->uniqueUid = uniqueName; + item->bandwidth = bandwidth; + item->dataRate = dataRate; + item->phyRate = phyRate; + item->modulation = WifiMode::QPSK; + item->constellationSize = 4; + item->isMandatory = isMandatory; + item->standard = standard; + return WifiMode (uid); +} + WifiMode WifiModeFactory::CreateQam (std::string uniqueName, - bool isMandatory, + bool isMandatory, uint32_t bandwidth, uint32_t dataRate, uint32_t phyRate, diff --git a/src/devices/wifi/wifi-mode.h b/src/devices/wifi/wifi-mode.h index 7dedd325f..71f3e724a 100644 --- a/src/devices/wifi/wifi-mode.h +++ b/src/devices/wifi/wifi-mode.h @@ -42,6 +42,7 @@ class WifiMode public: enum ModulationType { BPSK, + QPSK, DBPSK, DQPSK, QAM, @@ -162,6 +163,25 @@ public: uint32_t dataRate, uint32_t phyRate, enum WifiPhyStandard standard); + /** + * \param uniqueName the name of the associated WifiMode. This name + * must be unique accross _all_ instances. + * \param isMandatory true if this WifiMode is mandatory, false otherwise. + * \param bandwidth the bandwidth (Hz) of the signal generated when the + * associated WifiMode is used. + * \param dataRate the rate (bits/second) at which the user data is transmitted + * \param phyRate the rate (bits/second) at which the encoded user data is transmitted + * \param standard the Wifi Phy standard to apply + * The phyRate includes FEC so, is typically higher than the dataRate. + * + * Create a QPSK WifiMode. + */ + static WifiMode CreateQpsk (std::string uniqueName, + bool isMandatory, + uint32_t bandwidth, + uint32_t dataRate, + uint32_t phyRate, + enum WifiPhyStandard standard); /** * \param uniqueName the name of the associated WifiMode. This name * must be unique accross _all_ instances. diff --git a/src/devices/wifi/wifi-phy.cc b/src/devices/wifi/wifi-phy.cc index e7bbcd66b..6a4037810 100644 --- a/src/devices/wifi/wifi-phy.cc +++ b/src/devices/wifi/wifi-phy.cc @@ -114,7 +114,7 @@ WifiPhy::Get9mba (void) WifiMode WifiPhy::Get12mba (void) { - static WifiMode mode = WifiModeFactory::CreateBpsk ("wifia-12mbs", + static WifiMode mode = WifiModeFactory::CreateQpsk ("wifia-12mbs", true, 20000000, 12000000, 24000000, WIFI_PHY_STANDARD_80211a); @@ -123,7 +123,7 @@ WifiPhy::Get12mba (void) WifiMode WifiPhy::Get18mba (void) { - static WifiMode mode = WifiModeFactory::CreateBpsk ("wifia-18mbs", + static WifiMode mode = WifiModeFactory::CreateQpsk ("wifia-18mbs", false, 20000000, 18000000, 24000000, WIFI_PHY_STANDARD_80211a); @@ -132,39 +132,43 @@ WifiPhy::Get18mba (void) WifiMode WifiPhy::Get24mba (void) { - static WifiMode mode = WifiModeFactory::CreateBpsk ("wifia-24mbs", - true, - 20000000, 24000000, 48000000, - WIFI_PHY_STANDARD_80211a); + static WifiMode mode = WifiModeFactory::CreateQam ("wifia-24mbs", + true, + 20000000, 24000000, 48000000, + 16, + WIFI_PHY_STANDARD_80211a); return mode; } WifiMode WifiPhy::Get36mba (void) { - static WifiMode mode = WifiModeFactory::CreateBpsk ("wifia-36mbs", - false, - 20000000, 36000000, 48000000, - WIFI_PHY_STANDARD_80211a); + static WifiMode mode = WifiModeFactory::CreateQam ("wifia-36mbs", + false, + 20000000, 36000000, 48000000, + 16, + WIFI_PHY_STANDARD_80211a); return mode; } WifiMode WifiPhy::Get48mba (void) { - static WifiMode mode = WifiModeFactory::CreateBpsk ("wifia-48mbs", - false, - 20000000, 48000000, 72000000, - WIFI_PHY_STANDARD_80211a); + static WifiMode mode = WifiModeFactory::CreateQam ("wifia-48mbs", + false, + 20000000, 48000000, 72000000, + 64, + WIFI_PHY_STANDARD_80211a); return mode; } WifiMode WifiPhy::Get54mba (void) { - static WifiMode mode = WifiModeFactory::CreateBpsk ("wifia-54mbs", - false, - 20000000, 54000000, 72000000, - WIFI_PHY_STANDARD_80211a); + static WifiMode mode = WifiModeFactory::CreateQam ("wifia-54mbs", + false, + 20000000, 54000000, 72000000, + 64, + WIFI_PHY_STANDARD_80211a); return mode; } diff --git a/src/devices/wifi/wifi-test.cc b/src/devices/wifi/wifi-test.cc index f03ade983..df619e5cf 100644 --- a/src/devices/wifi/wifi-test.cc +++ b/src/devices/wifi/wifi-test.cc @@ -143,7 +143,7 @@ WifiTest::DoRun (void) m_propDelay.SetTypeId ("ns3::RandomPropagationDelayModel"); m_mac.SetTypeId ("ns3::AdhocWifiMac"); RunOne (); - + Simulator::Destroy (); return false; } diff --git a/src/helper/ipv4-address-helper.cc b/src/helper/ipv4-address-helper.cc index 597157247..d61891271 100644 --- a/src/helper/ipv4-address-helper.cc +++ b/src/helper/ipv4-address-helper.cc @@ -23,6 +23,7 @@ #include "ns3/net-device.h" #include "ns3/ipv4.h" #include "ns3/ipv4-address-generator.h" +#include "ns3/simulator.h" #include "ipv4-address-helper.h" NS_LOG_COMPONENT_DEFINE("Ipv4AddressHelper"); @@ -200,6 +201,7 @@ void NetworkAllocatorHelperTestCase::DoTeardown (void) { Ipv4AddressGenerator::Reset (); + Simulator::Destroy (); } bool NetworkAllocatorHelperTestCase::DoRun (void) @@ -246,6 +248,7 @@ void AddressAllocatorHelperTestCase::DoTeardown (void) { Ipv4AddressGenerator::Reset (); + Simulator::Destroy (); } bool @@ -337,6 +340,7 @@ void ResetAllocatorHelperTestCase::DoTeardown (void) { Ipv4AddressGenerator::Reset (); + Simulator::Destroy (); } static class Ipv4AddressHelperTestSuite : public TestSuite diff --git a/src/internet-stack/ipv4-l3-protocol.cc b/src/internet-stack/ipv4-l3-protocol.cc index 5b80bc7eb..d42484f51 100644 --- a/src/internet-stack/ipv4-l3-protocol.cc +++ b/src/internet-stack/ipv4-l3-protocol.cc @@ -196,6 +196,7 @@ Ipv4L3Protocol::DoDispose (void) *i = 0; } m_interfaces.clear (); + m_sockets.clear (); m_node = 0; m_routingProtocol = 0; Object::DoDispose (); diff --git a/src/internet-stack/ipv4-test.cc b/src/internet-stack/ipv4-test.cc index 9f38b5b7e..d23ef9ac7 100644 --- a/src/internet-stack/ipv4-test.cc +++ b/src/internet-stack/ipv4-test.cc @@ -94,7 +94,7 @@ Ipv4L3ProtocolTestCase::DoRun (void) Ipv4InterfaceAddress output = interface->GetAddress (2); NS_TEST_ASSERT_MSG_EQ (ifaceAddr4, output, "The addresses should be identical"); - + Simulator::Destroy (); return false; } diff --git a/src/internet-stack/ipv6-test.cc b/src/internet-stack/ipv6-test.cc index 35863b0ad..832728d09 100644 --- a/src/internet-stack/ipv6-test.cc +++ b/src/internet-stack/ipv6-test.cc @@ -135,7 +135,7 @@ Ipv6L3ProtocolTestCase::DoRun () index = ipv6->GetInterfaceForAddress ("2001:ffff:5678:9000::1"); /* address we just remove */ NS_TEST_ASSERT_MSG_EQ (index, (uint32_t) -1, "Address should not be found??"); - + Simulator::Destroy (); return false; }//end DoRun static class IPv6L3ProtocolTestSuite : public TestSuite diff --git a/src/node/ipv4-address-generator.cc b/src/node/ipv4-address-generator.cc index 7caeaaf23..3d908309e 100644 --- a/src/node/ipv4-address-generator.cc +++ b/src/node/ipv4-address-generator.cc @@ -560,6 +560,7 @@ void AddressAllocatorTestCase::DoTeardown (void) { Ipv4AddressGenerator::Reset (); + Simulator::Destroy (); } @@ -579,6 +580,7 @@ void NetworkAndAddressTestCase::DoTeardown (void) { Ipv4AddressGenerator::Reset (); + Simulator::Destroy (); } bool @@ -695,6 +697,7 @@ void AddressCollisionTestCase::DoTeardown (void) { Ipv4AddressGenerator::Reset (); + Simulator::Destroy (); } bool AddressCollisionTestCase::DoRun (void) diff --git a/src/node/node.cc b/src/node/node.cc index 72c85f194..8867cefa9 100644 --- a/src/node/node.cc +++ b/src/node/node.cc @@ -30,6 +30,7 @@ #include "ns3/assert.h" #include "ns3/global-value.h" #include "ns3/boolean.h" +#include "ns3/simulator.h" NS_LOG_COMPONENT_DEFINE ("Node"); @@ -108,6 +109,8 @@ Node::AddDevice (Ptr device) device->SetNode (this); device->SetIfIndex(index); device->SetReceiveCallback (MakeCallback (&Node::NonPromiscReceiveFromDevice, this)); + Simulator::ScheduleWithContext (GetId (), Seconds (0.0), + &NetDevice::Start, device); NotifyDeviceAdded (device); return index; } @@ -130,6 +133,8 @@ Node::AddApplication (Ptr application) uint32_t index = m_applications.size (); m_applications.push_back (application); application->SetNode (this); + Simulator::ScheduleWithContext (GetId (), Seconds (0.0), + &Application::Start, application); return index; } Ptr diff --git a/src/routing/aodv/aodv-test-suite.cc b/src/routing/aodv/aodv-test-suite.cc index f86cb6c57..2737262a3 100644 --- a/src/routing/aodv/aodv-test-suite.cc +++ b/src/routing/aodv/aodv-test-suite.cc @@ -474,7 +474,7 @@ struct AodvRtableEntryTest : public TestCase NS_TEST_EXPECT_MSG_EQ (rt.IsPrecursorListEmpty (), true, "trivial"); rt.GetPrecursors (prec); NS_TEST_EXPECT_MSG_EQ (prec.size (), 2, "trivial"); - + Simulator::Destroy (); return GetErrorStatus (); } }; @@ -528,7 +528,7 @@ struct AodvRtableTest : public TestCase NS_TEST_EXPECT_MSG_EQ (rt.GetFlag (), INVALID, "trivial"); NS_TEST_EXPECT_MSG_EQ (rtable.DeleteRoute (Ipv4Address ("1.2.3.4")), true, "trivial"); NS_TEST_EXPECT_MSG_EQ (rtable.DeleteRoute (Ipv4Address ("1.2.3.4")), false, "trivial"); - + Simulator::Destroy (); return GetErrorStatus (); } }; diff --git a/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc index eb73bf89e..aa0c6936d 100644 --- a/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc +++ b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.cc @@ -117,7 +117,7 @@ Ipv4NixVectorRouting::FlushIpv4RouteCache () } Ptr -Ipv4NixVectorRouting::GetNixVector (Ptr source, Ipv4Address dest) +Ipv4NixVectorRouting::GetNixVector (Ptr source, Ipv4Address dest, Ptr oif) { NS_LOG_FUNCTION_NOARGS (); @@ -146,7 +146,8 @@ Ipv4NixVectorRouting::GetNixVector (Ptr source, Ipv4Address dest) // otherwise proceed as normal // and build the nix vector std::vector< Ptr > parentVector; - BFS (NodeList::GetNNodes (), source, destNode, parentVector); + + BFS (NodeList::GetNNodes (), source, destNode, parentVector, oif); if (BuildNixVector (parentVector, source->GetId (), destNode->GetId (), nixVector)) { @@ -495,7 +496,7 @@ Ipv4NixVectorRouting::RouteOutput (Ptr p, const Ipv4Header &header, Ptr< NS_LOG_LOGIC ("Nix-vector not in cache, build: "); // Build the nix-vector, given this node and the // dest IP address - nixVectorInCache = GetNixVector (m_node, header.GetDestination ()); + nixVectorInCache = GetNixVector (m_node, header.GetDestination (), oif); // cache it m_nixCache.insert (NixMap_t::value_type (header.GetDestination (), nixVectorInCache)); @@ -523,18 +524,38 @@ Ipv4NixVectorRouting::RouteOutput (Ptr p, const Ipv4Header &header, Ptr< uint32_t numberOfBits = nixVectorForPacket->BitCount (m_totalNeighbors); uint32_t nodeIndex = nixVectorForPacket->ExtractNeighborIndex (numberOfBits); - // Possibly search here in a cache for this node index - // and look for a Ipv4Route. If we have it, don't - // need to do the next 3 lines. + // Search here in a cache for this node index + // and look for a Ipv4Route rtentry = GetIpv4RouteInCache (header.GetDestination ()); - // not in cache - if (!rtentry) + + if (!rtentry || !(rtentry->GetOutputDevice () == oif)) { + // not in cache or a different specified output + // device is to be used + + // first, make sure we erase existing (incorrect) + // rtentry from the map + if (rtentry) + { + m_ipv4RouteCache.erase(header.GetDestination ()); + } + NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); Ipv4Address gatewayIp; uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); + int32_t interfaceIndex = 0; + + if (!oif) + { + interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); + } + else + { + interfaceIndex = (m_ipv4)->GetInterfaceForDevice(oif); + } + + NS_ASSERT_MSG (interfaceIndex != -1, "Interface index not found for device"); - uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); // start filling in the Ipv4Route info @@ -543,7 +564,15 @@ Ipv4NixVectorRouting::RouteOutput (Ptr p, const Ipv4Header &header, Ptr< rtentry->SetGateway (gatewayIp); rtentry->SetDestination (header.GetDestination ()); - rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); + + if (!oif) + { + rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); + } + else + { + rtentry->SetOutputDevice (oif); + } sockerr = Socket::ERROR_NOTERROR; @@ -582,143 +611,50 @@ Ipv4NixVectorRouting::RouteInput (Ptr p, const Ipv4Header &header, // Get the nix-vector from the packet Ptr nixVector = p->GetNixVector(); - // make sure it exists, if not something - // went wrong - if (!nixVector) + // If nixVector isn't in packet, something went wrong + NS_ASSERT (nixVector); + + // Get the interface number that we go out of, by extracting + // from the nix-vector + if (m_totalNeighbors == 0) { - NS_LOG_ERROR ("Nix-vector wasn't in the packet! Rebuild."); - - Ptr nixVectorInCache; - - NS_LOG_DEBUG ("Dest IP from header: " << header.GetDestination ()); - - // check if cache - nixVectorInCache = GetNixVectorInCache(header.GetDestination ()); - - // not in cache - if (!nixVectorInCache) - { - NS_LOG_LOGIC ("RouteInput(): Nix-vector not in cache, build: "); - - // Build the nix-vector, given this node and the - // dest IP address - nixVectorInCache = GetNixVector (m_node, header.GetDestination ()); - } - - // path exists - if (nixVectorInCache) - { - NS_LOG_LOGIC ("Nix-vector contents: " << *nixVectorInCache); - - // cache it - m_nixCache.insert(NixMap_t::value_type(header.GetDestination (), nixVectorInCache)); - - // create a new nix vector to be used, - // we want to keep the cached version clean - Ptr nixVectorForPacket; - nixVectorForPacket = CreateObject (); - nixVectorForPacket = nixVectorInCache->Copy(); - - // Get the interface number that we go out of, by extracting - // from the nix-vector - if (m_totalNeighbors == 0) - { - m_totalNeighbors = FindTotalNeighbors (); - } - uint32_t numberOfBits = nixVectorForPacket->BitCount (m_totalNeighbors); - uint32_t nodeIndex = nixVectorForPacket->ExtractNeighborIndex (numberOfBits); - - rtentry = GetIpv4RouteInCache (header.GetDestination ()); - // not in cache - if (!rtentry) - { - NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); - Ipv4Address gatewayIp; - uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); - - uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); - Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); - - // start filling in the Ipv4Route info - rtentry = Create (); - rtentry->SetSource (ifAddr.GetLocal ()); - - rtentry->SetGateway (Ipv4Address(gatewayIp)); - rtentry->SetDestination (header.GetDestination ()); - rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); - - // add rtentry to cache - m_ipv4RouteCache.insert(Ipv4RouteMap_t::value_type(header.GetDestination (), rtentry)); - } - - NS_LOG_LOGIC ("Nix-vector contents: " << *nixVectorInCache << " : Remaining bits: " << nixVectorForPacket->GetRemainingBits()); - - // Add nix-vector in the packet class - // have to copy the packet first b/c - // it is const - Ptr newPacket = Create (); - newPacket = p->Copy(); - - NS_LOG_LOGIC ("Adding Nix-vector to packet: " << *nixVectorForPacket); - newPacket->SetNixVector(nixVectorForPacket); - - // call the unicast callback - // local deliver is handled by Ipv4StaticRoutingImpl - // so this code is never even called if the packet is - // destined for this node. - ucb (rtentry, newPacket, header); - return true; - } - else // path doesn't exist - { - NS_LOG_ERROR ("No path to the dest: " << header.GetDestination ()); - return false; - } + m_totalNeighbors = FindTotalNeighbors (); } - else + uint32_t numberOfBits = nixVector->BitCount (m_totalNeighbors); + uint32_t nodeIndex = nixVector->ExtractNeighborIndex (numberOfBits); + + rtentry = GetIpv4RouteInCache (header.GetDestination ()); + // not in cache + if (!rtentry) { - // Get the interface number that we go out of, by extracting - // from the nix-vector - if (m_totalNeighbors == 0) - { - m_totalNeighbors = FindTotalNeighbors (); - } - uint32_t numberOfBits = nixVector->BitCount (m_totalNeighbors); - uint32_t nodeIndex = nixVector->ExtractNeighborIndex (numberOfBits); + NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); + Ipv4Address gatewayIp; + uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); + uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); + Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); - rtentry = GetIpv4RouteInCache (header.GetDestination ()); - // not in cache - if (!rtentry) - { - NS_LOG_LOGIC ("Ipv4Route not in cache, build: "); - Ipv4Address gatewayIp; - uint32_t index = FindNetDeviceForNixIndex (nodeIndex, gatewayIp); - uint32_t interfaceIndex = (m_ipv4)->GetInterfaceForDevice(m_node->GetDevice(index)); - Ipv4InterfaceAddress ifAddr = m_ipv4->GetAddress (interfaceIndex, 0); + // start filling in the Ipv4Route info + rtentry = Create (); + rtentry->SetSource (ifAddr.GetLocal ()); - // start filling in the Ipv4Route info - rtentry = Create (); - rtentry->SetSource (ifAddr.GetLocal ()); + rtentry->SetGateway (gatewayIp); + rtentry->SetDestination (header.GetDestination ()); + rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); - rtentry->SetGateway (gatewayIp); - rtentry->SetDestination (header.GetDestination ()); - rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIndex)); - - // add rtentry to cache - m_ipv4RouteCache.insert(Ipv4RouteMap_t::value_type(header.GetDestination (), rtentry)); - } - - NS_LOG_LOGIC ("At Node " << m_node->GetId() << ", Extracting " << numberOfBits << - " bits from Nix-vector: " << nixVector << " : " << *nixVector); - - // call the unicast callback - // local deliver is handled by Ipv4StaticRoutingImpl - // so this code is never even called if the packet is - // destined for this node. - ucb (rtentry, p, header); - - return true; + // add rtentry to cache + m_ipv4RouteCache.insert(Ipv4RouteMap_t::value_type(header.GetDestination (), rtentry)); } + + NS_LOG_LOGIC ("At Node " << m_node->GetId() << ", Extracting " << numberOfBits << + " bits from Nix-vector: " << nixVector << " : " << *nixVector); + + // call the unicast callback + // local deliver is handled by Ipv4StaticRoutingImpl + // so this code is never even called if the packet is + // destined for this node. + ucb (rtentry, p, header); + + return true; } // virtual functions from Ipv4RoutingProtocol @@ -744,7 +680,9 @@ Ipv4NixVectorRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddr } bool -Ipv4NixVectorRouting::BFS (uint32_t numberOfNodes, Ptr source, Ptr dest, std::vector< Ptr > & parentVector) +Ipv4NixVectorRouting::BFS (uint32_t numberOfNodes, Ptr source, + Ptr dest, std::vector< Ptr > & parentVector, + Ptr oif) { NS_LOG_FUNCTION_NOARGS (); @@ -772,41 +710,36 @@ Ipv4NixVectorRouting::BFS (uint32_t numberOfNodes, Ptr source, Ptr d return true; } - - // Iterate over the current node's adjacent vertices - // and push them into the queue - for (uint32_t i = 0; i < (currNode->GetNDevices ()); i++) + // if this is the first iteration of the loop and a + // specific output interface was given, make sure + // we go this way + if (currNode == source && oif) { - // Get a net device from the node - // as well as the channel, and figure - // out the adjacent net device - Ptr localNetDevice = currNode->GetDevice (i); - // make sure that we can go this way if (ipv4) { - uint32_t interfaceIndex = (ipv4)->GetInterfaceForDevice(currNode->GetDevice(i)); + uint32_t interfaceIndex = (ipv4)->GetInterfaceForDevice(oif); if (!(ipv4->IsUp (interfaceIndex))) { NS_LOG_LOGIC ("Ipv4Interface is down"); - continue; + return false; } } - if (!(localNetDevice->IsLinkUp ())) - { - NS_LOG_LOGIC ("Link is down."); - continue; - } - Ptr channel = localNetDevice->GetChannel (); + if (!(oif->IsLinkUp ())) + { + NS_LOG_LOGIC ("Link is down."); + return false; + } + Ptr channel = oif->GetChannel (); if (channel == 0) { - continue; + return false; } // this function takes in the local net dev, and channnel, and // writes to the netDeviceContainer the adjacent net devs NetDeviceContainer netDeviceContainer; - GetAdjacentNetDevices (localNetDevice, channel, netDeviceContainer); + GetAdjacentNetDevices (oif, channel, netDeviceContainer); // Finally we can get the adjacent nodes // and scan through them. We push them @@ -827,6 +760,63 @@ Ipv4NixVectorRouting::BFS (uint32_t numberOfNodes, Ptr source, Ptr d } } } + else + { + // Iterate over the current node's adjacent vertices + // and push them into the queue + for (uint32_t i = 0; i < (currNode->GetNDevices ()); i++) + { + // Get a net device from the node + // as well as the channel, and figure + // out the adjacent net device + Ptr localNetDevice = currNode->GetDevice (i); + + // make sure that we can go this way + if (ipv4) + { + uint32_t interfaceIndex = (ipv4)->GetInterfaceForDevice(currNode->GetDevice(i)); + if (!(ipv4->IsUp (interfaceIndex))) + { + NS_LOG_LOGIC ("Ipv4Interface is down"); + continue; + } + } + if (!(localNetDevice->IsLinkUp ())) + { + NS_LOG_LOGIC ("Link is down."); + continue; + } + Ptr channel = localNetDevice->GetChannel (); + if (channel == 0) + { + continue; + } + + // this function takes in the local net dev, and channnel, and + // writes to the netDeviceContainer the adjacent net devs + NetDeviceContainer netDeviceContainer; + GetAdjacentNetDevices (localNetDevice, channel, netDeviceContainer); + + // Finally we can get the adjacent nodes + // and scan through them. We push them + // to the greyNode queue, if they aren't + // already there. + for (NetDeviceContainer::Iterator iter = netDeviceContainer.Begin (); iter != netDeviceContainer.End (); iter++) + { + Ptr remoteNode = (*iter)->GetNode (); + + // check to see if this node has been pushed before + // by checking to see if it has a parent + // if it doesn't (null or 0), then set its parent and + // push to the queue + if (parentVector.at (remoteNode->GetId ()) == 0) + { + parentVector.at (remoteNode->GetId ()) = currNode; + greyNodeList.push (remoteNode); + } + } + } + } // Pop off the head grey node. We have all its children. // It is now black. diff --git a/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h index e8213e82f..5de8ff999 100644 --- a/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h +++ b/src/routing/nix-vector-routing/ipv4-nix-vector-routing.h @@ -78,9 +78,9 @@ class Ipv4NixVectorRouting : public Ipv4RoutingProtocol void ResetTotalNeighbors (void); /* takes in the source node and dest IP and calls GetNodeByIp, - * BFS, and BuildNixVector to finally return the built - * nix-vector */ - Ptr GetNixVector (Ptr, Ipv4Address); + * BFS, accounting for any output interface specified, and finally + * BuildNixVector to return the built nix-vector */ + Ptr GetNixVector (Ptr, Ipv4Address, Ptr); /* checks the cache based on dest IP for the nix-vector */ Ptr GetNixVectorInCache (Ipv4Address); @@ -124,7 +124,8 @@ class Ipv4NixVectorRouting : public Ipv4RoutingProtocol bool BFS (uint32_t numberOfNodes, Ptr source, Ptr dest, - std::vector< Ptr > & parentVector); + std::vector< Ptr > & parentVector, + Ptr oif); void DoDispose (void); diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 3a51d6f41..e3ef14898 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -291,6 +291,10 @@ void Simulator::Remove (const EventId &ev) { NS_LOG_FUNCTION (&ev); + if (*PeekImpl () == 0) + { + return; + } return GetImpl ()->Remove (ev); } @@ -298,6 +302,10 @@ void Simulator::Cancel (const EventId &ev) { NS_LOG_FUNCTION (&ev); + if (*PeekImpl () == 0) + { + return; + } return GetImpl ()->Cancel (ev); } @@ -305,6 +313,10 @@ bool Simulator::IsExpired (const EventId &id) { NS_LOG_FUNCTION (&id); + if (*PeekImpl () == 0) + { + return true; + } return GetImpl ()->IsExpired (id); } diff --git a/test.py b/test.py index 979eaeacd..9415135b1 100755 --- a/test.py +++ b/test.py @@ -27,6 +27,7 @@ import Queue import signal import xml.dom.minidom import shutil +import re # # XXX This should really be part of a waf command to list the configuration @@ -585,10 +586,93 @@ def make_library_path(): if options.verbose: print "os.environ[\"LD_LIBRARY_PATH\"] == %s" % os.environ["LD_LIBRARY_PATH"] +# +# Short note on generating suppressions: +# +# See the valgrind documentation for a description of suppressions. The easiest +# way to generate a suppression expression is by using the valgrind +# --gen-suppressions option. To do that you have to figure out how to run the +# test in question. +# +# If you do "test.py -v -g -s then test.py will output most of what +# you need. For example, if you are getting a valgrind error in the +# devices-mesh-dot11s-regression test suite, you can run: +# +# ./test.py -v -g -s devices-mesh-dot11s-regression +# +# You should see in the verbose output something that looks like: +# +# Synchronously execute valgrind --suppressions=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/testpy.supp +# --leak-check=full --error-exitcode=2 /home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build/debug/utils/test-runner +# --suite=devices-mesh-dot11s-regression --basedir=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev +# --tempdir=testpy-output/2010-01-12-22-47-50-CUT +# --out=testpy-output/2010-01-12-22-47-50-CUT/devices-mesh-dot11s-regression.xml +# +# You need to pull out the useful pieces, and so could run the following to +# reproduce your error: +# +# valgrind --suppressions=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/testpy.supp +# --leak-check=full --error-exitcode=2 /home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build/debug/utils/test-runner +# --suite=devices-mesh-dot11s-regression --basedir=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev +# --tempdir=testpy-output +# +# Hint: Use the first part of the command as is, and point the "tempdir" to +# somewhere real. You don't need to specify an "out" file. +# +# When you run the above command you should see your valgrind error. The +# suppression expression(s) can be generated by adding the --gen-suppressions=yes +# option to valgrind. Use something like: +# +# valgrind --gen-suppressions=yes --suppressions=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/testpy.supp +# --leak-check=full --error-exitcode=2 /home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build/debug/utils/test-runner +# --suite=devices-mesh-dot11s-regression --basedir=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev +# --tempdir=testpy-output +# +# Now when valgrind detects an error it will ask: +# +# ==27235== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ---- +# +# to which you just enter 'y'. +# +# You will be provided with a suppression expression that looks something like +# the following: +# { +# +# Memcheck:Addr8 +# fun:_ZN3ns36dot11s15HwmpProtocolMac8SendPreqESt6vectorINS0_6IePreqESaIS3_EE +# fun:_ZN3ns36dot11s15HwmpProtocolMac10SendMyPreqEv +# fun:_ZN3ns36dot11s15HwmpProtocolMac18RequestDestinationENS_12Mac48AddressEjj +# ... +# the rest of the stack frame +# ... +# } +# +# You need to add a supression name which will only be printed out by valgrind in +# verbose mode (but it needs to be there in any case). The entire stack frame is +# shown to completely characterize the error, but in most cases you won't need +# all of that info. For example, if you want to turn off all errors that happen +# when the function (fun:) is called, you can just delete the rest of the stack +# frame. You can also use wildcards to make the mangled signatures more readable. +# +# I added the following to the testpy.supp file for this particular error: +# +# { +# Supress invalid read size errors in SendPreq() when using HwmpProtocolMac +# Memcheck:Addr8 +# fun:*HwmpProtocolMac*SendPreq* +# } +# +# Now, when you run valgrind the error will be suppressed. +# +VALGRIND_SUPPRESSIONS_FILE = "testpy.supp" + def run_job_synchronously(shell_command, directory, valgrind): + (base, build) = os.path.split (NS3_BUILDDIR) + suppressions_path = os.path.join (base, VALGRIND_SUPPRESSIONS_FILE) path_cmd = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command) if valgrind: - cmd = "valgrind --leak-check=full --error-exitcode=2 %s" % path_cmd + cmd = "valgrind --suppressions=%s --leak-check=full --show-reachable=yes --error-exitcode=2 %s" % (suppressions_path, + path_cmd) else: cmd = path_cmd @@ -600,11 +684,25 @@ def run_job_synchronously(shell_command, directory, valgrind): stdout_results, stderr_results = proc.communicate() elapsed_time = time.time() - start_time + retval = proc.returncode + + # + # valgrind sometimes has its own idea about what kind of memory management + # errors are important. We want to detect *any* leaks, so the way to do + # that is to look for the presence of a valgrind leak summary section. + # + # If another error has occurred (like a test suite has failed), we don't + # want to trump that error, so only do the valgrind output scan if the + # test has otherwise passed (return code was zero). + # + if valgrind and retval == 0 and "== LEAK SUMMARY:" in stderr_results: + retval = 2 + if options.verbose: - print "Return code = ", proc.returncode + print "Return code = ", retval print "stderr = ", stderr_results - return (proc.returncode, stdout_results, stderr_results, elapsed_time) + return (retval, stdout_results, stderr_results, elapsed_time) # # This class defines a unit of testing work. It will typically refer to diff --git a/testpy.supp b/testpy.supp new file mode 100644 index 000000000..ff7deb13f --- /dev/null +++ b/testpy.supp @@ -0,0 +1,5 @@ +{ + Supress invalid read size errors in SendPreq() when using HwmpProtocolMac + Memcheck:Addr8 + fun:*HwmpProtocolMac*SendPreq* +} diff --git a/wutils.py b/wutils.py index 56815931c..8df08b401 100644 --- a/wutils.py +++ b/wutils.py @@ -121,16 +121,12 @@ def run_argv(argv, env, os_env=None, cwd=None, force_no_valgrind=False): raise Utils.WafError("Options --command-template and --valgrind are conflicting") if not env['VALGRIND']: raise Utils.WafError("valgrind is not installed") - argv = [env['VALGRIND'], "--leak-check=full", "--error-exitcode=1"] + argv + argv = [env['VALGRIND'], "--leak-check=full", "--show-reachable=yes", "--error-exitcode=1"] + argv proc = subprocess.Popen(argv, env=proc_env, cwd=cwd, stderr=subprocess.PIPE) - reg = re.compile ('definitely lost: ([^ ]+) bytes') error = False for line in proc.stderr: sys.stderr.write(line) - result = reg.search(line) - if result is None: - continue - if result.group(1) != "0": + if "== LEAK SUMMARY" in line: error = True retval = proc.wait() if retval == 0 and error: