--- a/.hgtags Tue Sep 11 15:09:55 2007 +0100
+++ b/.hgtags Wed Sep 12 18:06:09 2007 +0100
@@ -4,3 +4,4 @@
38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4
08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5
+267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/README.multicast-routing Wed Sep 12 18:06:09 2007 +0100
@@ -0,0 +1,235 @@
+Static multicast routing overview
+--------------------------------
+
+This is brief documentation of a proposal to add static multicast
+routing to ns-3.
+
+This extension allows the simulation user to:
+
+- manually add Ipv4 multicast routes to a router
+- specify a default outgoing interface for multicast sources (hosts) in
+ various ways
+- allow a multicast receiver (hosts) to join a multicast group, to enable
+ reception of that group's datagrams
+
+1. Code location:
+
+- http://code.nsnam.org/craigdo/ns-3-mc
+
+- the main source code is found in src/internet-node/ipv4-static-routing.{cc,h}
+
+also touched are:
+- src/internet-node/ipv4-l3-protocol.cc (forwarding methods for the
+ static routing API)
+- src/node/net-device.cc (provides virtual NetDevice::MakeMulticastAddress)
+- src/arp-ipv4-interface.cc (calls NetDevice::MakeMulticastAddress)
+- src/devices/csma/csma-net-device.cc (handles multicast addressing and
+ reception).
+- src/devices/point-to-point/point-to-point-net-device.cc (implements required
+ virtual methods.
+- src/internet-node/ (several files have added tracing)
+
+- a heavily commented example script is in examples/csma-multicast.cc
+
+2. API:
+
+The API for adding a multicast route is:
+
+/**
+ * @brief Add a multicast route to the static routing table.
+ *
+ * A multicast route must specify an origin IP address, a multicast group and
+ * an input network interface index as conditions and provide a vector of
+ * output network interface indices over which packets matching the conditions
+ * are sent.
+ *
+ * Typically there are two main types of multicast routes: routes of the
+ * first kind are used during forwarding. All of the conditions must be
+ * exlicitly provided. The second kind of routes are used to get packets off
+ * of a local node. The difference is in the input interface. Routes for
+ * forwarding will always have an explicit input interface specified. Routes
+ * off of a node will always set the input interface to a wildcard specified
+ * by the index Ipv4RoutingProtocol::IF_INDEX_ANY.
+ *
+ * For routes off of a local node wildcards may be used in the origin and
+ * multicast group addresses. The wildcard used for Ipv4Adresses is that
+ * address returned by Ipv4Address::GetAny () -- typically "0.0.0.0". Usage
+ * of a wildcard allows one to specify default behavior to varying degrees.
+ *
+ * For example, making the origin address a wildcard, but leaving the
+ * multicast group specific allows one (in the case of a node with multiple
+ * interfaces) to create different routes using different output interfaces
+ * for each multicast group.
+ *
+ * If the origin and multicast addresses are made wildcards, you have created
+ * essentially a default multicast address that can forward to multiple
+ * interfaces. Compare this to the actual default multicast address that is
+ * limited to specifying a single output interface for compatibility with
+ * existing functionality in other systems.
+ *
+ * @param origin The Ipv4Address of the origin of packets for this route. May
+ * be Ipv4Address:GetAny for open groups.
+ * @param group The Ipv4Address of the multicast group or this route.
+ * @param inputInterface The input network interface index over which to
+ * expect packets destined for this route. May be
+ * Ipv4RoutingProtocol::IF_INDEX_ANY for packets of local origin.
+ * @param outputInterface A vector of network interface indices used to specify
+ * how to send packets to the destination(s).
+ *
+ * @see Ipv4Address
+ */
+ Ipv4::AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+
+To remove a route, one uses:
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table. This
+ * means that the default route may be removed by calling this method with
+ * appropriate wildcard parameters.
+ *
+ * This method causes the multicast routing table to be searched for the first
+ * route that matches the parameters and removes it.
+ *
+ * Wildcards may be provided to this function, but the wildcards are used to
+ * exacly match wildcards in the routes (see AddMulticastRoute). That is,
+ * calling RemoveMulticastRoute with the origin set to "0.0.0.0" will not
+ * remove routes with any address in the origin, but will only remove routes
+ * with "0.0.0.0" set as the the origin.
+ *
+ * @param origin The IP address specified as the origin of packets for the
+ * route.
+ * @param origin The IP address specified as the multicast group addres of
+ * the route.
+ * @param inputInterfade The network interface index specified as the expected
+ * input interface for the route.
+ * @returns True if a route was found and removed, false otherwise.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::AddMulticastRoute
+ */
+ Ipv4::RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+
+For symmetry with the unicast routing interface, a method is provided to
+remove routes by index:
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table. This
+ * means that if the default route has been set, calling
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param index The index (into the multicast routing table) of the route to
+ * remove. If the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
+ void RemoveMulticastRoute (uint32_t index);
+
+For compatibility, and to provide simplicity, one can set a default multicast
+route for a host originating data:
+
+/**
+ * @brief Add a default multicast route to the static routing table.
+ *
+ * This is the multicast equivalent of the unicast version SetDefaultRoute.
+ * We tell the routing system what to do in the case where a specific route
+ * to a destination multicast group is not found. The system forwards
+ * packets out the specified interface in the hope that "something out there"
+ * knows better how to route the packet. This method is only used in
+ * initially sending packets off of a host. The default multicast route is
+ * not consulted during forwarding -- exact routes must be specified using
+ * AddMulticastRoute for that case.
+ *
+ * Since we're basically sending packets to some entity we think may know
+ * better what to do, we don't pay attention to "subtleties" like origin
+ * address, nor do we worry about forwarding out multiple interfaces. If the
+ * default multicast route is set, it is returned as the selected route from
+ * LookupStatic irrespective of origin or multicast group if another specific
+ * route is not found.
+ *
+ * @param outputInterface The network interface index used to specify where
+ * to send packets in the case of unknown routes.
+ *
+ * @see Ipv4Address
+ */
+ Ipv4::SetDefaultMulticastRoute (uint32_t outputInterface)
+
+For a host wanting to receive multicast data, the following function is used
+to join each multicast group.
+
+ /**
+ * \brief Join a multicast group for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ */
+ Ipv4::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
+To stop receiving multicast data, the following function is used:
+
+ /**
+ * \brief Leave a multicast group for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ */
+ LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
+There are new lookup functions implemented in Ipv4:
+
+ /**
+ * \brief Find and return the interface ID of the interface that has been
+ * assigned the specified IP address.
+ * \param addr The IP address assigned to the interface of interest.
+ * \returns The index of the ipv4 interface with the given address.
+ *
+ * Each IP interface has an IP address associated with it. It is often
+ * useful to search the list of interfaces for one that corresponds to
+ * a known IP Address. This call takes an IP address as a parameter and
+ * returns the interface index of the first interface that has been assigned
+ * that address. If the address is not found, this function asserts.
+ */
+ Ipv4::FindInterfaceForAddr (Ipv4Address addr) const;
+
+ /**
+ * \brief Find and return the interface ID of the interface that has been
+ * assigned the specified (masked) IP address.
+ * \param addr The IP address assigned to the interface of interest.
+ * \param mask The address mask to be used in address matching.
+ * \returns The index of the ipv4 interface with the given address.
+ *
+ * Each IP interface has an IP address associated with it. It is often
+ * useful to search the list of interfaces for one that corresponds to
+ * a known IP Address. This call takes an IP address and an IP address
+ * mask as parameters and returns the interface index of the first interface
+ * that matches the masked IP address.
+ */
+ Ipv4::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const;
+
+Also, there are various methods to lookup and iterate the static multicast
+routes of a node, in the Ipv4StaticRouting class.
+
+3. Dependencies:
+
+- fix for bug 69 (source Ipv4 address is set correctly for UDP)
+- fix for OnOffApplication that receives data
+
+4. Open issues or features not included
+
+- choose source interface on a per-group basis when a host is multihomed
--- a/examples/csma-broadcast.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/csma-broadcast.cc Wed Sep 12 18:06:09 2007 +0100
@@ -66,13 +66,24 @@
// Users may find it convenient to turn on explicit debugging
// for selected modules; the below lines suggest how to do this
-#if 0
+#if 0
+ DebugComponentEnable("Object");
+ DebugComponentEnable("Queue");
+ DebugComponentEnable("DropTailQueue");
+ DebugComponentEnable("Channel");
+ DebugComponentEnable("CsmaChannel");
+ DebugComponentEnable("NetDevice");
DebugComponentEnable("CsmaNetDevice");
DebugComponentEnable("Ipv4L3Protocol");
- DebugComponentEnable("NetDevice");
- DebugComponentEnable("Channel");
- DebugComponentEnable("CsmaChannel");
+ DebugComponentEnable("OnOffApplication");
DebugComponentEnable("PacketSocket");
+ DebugComponentEnable("UdpSocket");
+ DebugComponentEnable("UdpL4Protocol");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("Ipv4StaticRouting");
+ DebugComponentEnable("Ipv4Interface");
+ DebugComponentEnable("ArpIpv4Interface");
+ DebugComponentEnable("Ipv4LoopbackInterface");
#endif
// Set up some default values for the simulation. Use the Bind()
@@ -103,13 +114,13 @@
CsmaTopology::CreateCsmaChannel(
DataRate(5000000), MilliSeconds(2));
- uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0,
+ uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel0,
Eui48Address("10:54:23:54:0:50"));
- uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel1,
+ uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel1,
Eui48Address("10:54:23:54:0:51"));
- uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
+ uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, channel0,
Eui48Address("10:54:23:54:23:51"));
- uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel1,
+ uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channel1,
Eui48Address("10:54:23:54:23:52"));
// Later, we add IP addresses.
@@ -125,6 +136,18 @@
CsmaIpv4Topology::AddIpv4Address (
n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
+ // XXX Is this the right thing to do?
+ //
+ // The OnOff application uses a connected socket. This socket needs to be
+ // able to figure out which interface to use as the source address for
+ // packets. When there's one interface, this isn't too hard, but node zero
+ // has two interfaces, and limited broadcasts will be sent out both of those
+ // interfaces. We need to provide some way to disambiguate the choice.
+ // If we supply a default route, the specified interface will be chosen.
+
+ Ptr<Ipv4> ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+ ipv4->SetDefaultRoute ("192.168.1.3", n0ifIndex0);
+
// Create the OnOff application to send UDP datagrams of size
// 210 bytes at a rate of 448 Kb/s
// from n0 to n1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-multicast.cc Wed Sep 12 18:06:09 2007 +0100
@@ -0,0 +1,312 @@
+/* -*- 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
+ */
+
+// Network topology
+//
+// Lan1
+// ===========
+// | | |
+// n0 n1 n2 n3 n4
+// | | |
+// ===========
+// Lan0
+//
+// - Multicast source is at node n0;
+// - Multicast forwarded by node n2 onto LAN1;
+// - Nodes n0, n1, n2, n3, and n4 receive the multicast frame.
+// - Node n4 listens for the data (actual listener not yet implementted)
+
+#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;
+
+NS_DEBUG_COMPONENT_DEFINE ("CsmaMulticast");
+
+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("CsmaMulticast");
+
+ DebugComponentEnable("Object");
+ DebugComponentEnable("Queue");
+ DebugComponentEnable("DropTailQueue");
+ DebugComponentEnable("Channel");
+ DebugComponentEnable("CsmaChannel");
+ DebugComponentEnable("NetDevice");
+ DebugComponentEnable("CsmaNetDevice");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("OnOffApplication");
+ DebugComponentEnable("PacketSocket");
+ DebugComponentEnable("UdpSocket");
+ DebugComponentEnable("UdpL4Protocol");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("Ipv4StaticRouting");
+ DebugComponentEnable("Ipv4Interface");
+ DebugComponentEnable("ArpIpv4Interface");
+ DebugComponentEnable("Ipv4LoopbackInterface");
+#endif
+
+//
+// Set up default values for the simulation. Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use. The Bind
+// command 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() at
+// run-time, via command-line arguments
+//
+ CommandLine::Parse (argc, argv);
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+ NS_DEBUG("Create nodes.");
+ Ptr<Node> n0 = Create<InternetNode> ();
+ Ptr<Node> n1 = Create<InternetNode> ();
+ Ptr<Node> n2 = Create<InternetNode> ();
+ Ptr<Node> n3 = Create<InternetNode> ();
+ Ptr<Node> n4 = Create<InternetNode> ();
+
+ NS_DEBUG("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+ Ptr<CsmaChannel> lan0 =
+ CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
+
+ Ptr<CsmaChannel> lan1 =
+ CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
+
+ NS_DEBUG("Build Topology.");
+//
+// Now fill out the topology by creating the net devices required to connect
+// the nodes to the channels and hooking them up. AddIpv4CsmaNetDevice will
+// create a net device, add a MAC address (in memory of the pink flamingo) and
+// connect the net device to a nodes and also to a channel. the
+// AddIpv4CsmaNetDevice method returns a net device index for the net device
+// created on the node. Interpret nd0 as the net device we created for node
+// zero. Interpret nd2Lan0 as the net device we created for node two to
+// connect to Lan0.
+//
+ uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan0,
+ Eui48Address("08:00:2e:00:00:00"));
+ uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan0,
+ Eui48Address("08:00:2e:00:00:01"));
+ uint32_t nd2Lan0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan0,
+ Eui48Address("08:00:2e:00:00:02"));
+
+ uint32_t nd2Lan1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1,
+ Eui48Address("08:00:2e:00:00:03"));
+ uint32_t nd3 __attribute__ ((unused)) =
+ CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1,
+ Eui48Address("08:00:2e:00:00:04"));
+ uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan1,
+ Eui48Address("08:00:2e:00:00:05"));
+
+ NS_DEBUG ("nd0 = " << nd0);
+ NS_DEBUG ("nd1 = " << nd1);
+ NS_DEBUG ("nd2Lan0 = " << nd2Lan0);
+ NS_DEBUG ("nd2Lan1 = " << nd2Lan1);
+ NS_DEBUG ("nd3 = " << nd3);
+ NS_DEBUG ("nd4 = " << nd3);
+//
+// We've got the "hardware" in place. Now we need to add IP addresses.
+//
+ NS_DEBUG("Assign IP Addresses.");
+
+ CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"),
+ Ipv4Mask ("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"),
+ Ipv4Mask ("255.255.255.0"));
+
+//
+// We'll need these addresses later
+//
+ Ipv4Address n2Lan0Addr ("10.1.1.3");
+ Ipv4Address n2Lan1Addr ("10.1.2.1");
+
+ CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan0, n2Lan0Addr,
+ Ipv4Mask ("255.255.255.0"));
+//
+// Assign IP addresses to the net devices and associated interfaces on Lan1
+//
+ CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan1, n2Lan1Addr,
+ Ipv4Mask ("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (n3, nd1, Ipv4Address ("10.1.2.2"),
+ Ipv4Mask ("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (n4, nd4, Ipv4Address ("10.1.2.3"),
+ Ipv4Mask ("255.255.255.0"));
+
+ NS_DEBUG("Configure multicasting.");
+//
+// Now we can configure multicasting. As described above, the multicast
+// source is at node zero, which we assigned the IP address of 10.1.1.1
+// earlier. We need to define a multicast group to send packets to. This
+// can be any multicast address from 224.0.0.0 through 239.255.255.255
+// (avoiding the reserved routing protocol addresses). We just pick a
+// convenient number (225.0.0.0) and or in some bits to let us verify that
+// correct Ethernet multicast addresses are constructed down in the system.
+//
+ Ipv4Address multicastSource ("10.1.1.1");
+ Ipv4Address multicastGroup ("225.1.2.4");
+//
+// We are going to manually configure multicast routing. This means telling
+// node two that it should expect multicast data coming from IP address
+// 10.1.1.1 originally. It should expect these data coming in over its IP
+// interface connected to Lan0. When node two receives these packets, they
+// should be forwarded out the interface that connects it to Lan1.
+//
+// We're going to need the interface indices on node two corresponding to
+// these interfaces, which we call ifIndexLan0 and ifIndexLan1. The most
+// general way to get these interfaces is to look them up by IP address.
+// Looking back to the topology creation calls above, we saved the addresses
+// assigned to the interface connecting node two to Lan0 and Lan1. Now is
+// a fine time to find the interface indices on node two.
+//
+ Ptr<Ipv4> ipv4;
+ ipv4 = n2->QueryInterface<Ipv4> (Ipv4::iid);
+
+ uint32_t ifIndexLan0 = ipv4->FindInterfaceForAddr (n2Lan0Addr);
+ uint32_t ifIndexLan1 = ipv4->FindInterfaceForAddr (n2Lan1Addr);
+//
+// Now, we need to do is to call the AddMulticastRoute () method on node
+// two's Ipv4 interface and tell it that whenever it receives a packet on
+// the interface from Lan0, with the packet from the multicast source,
+// destined for the multicast group, it should forward these packets down
+// the interface connecting it to Lan1. (Note: the vector of output
+// interfaces is in case there are multiple net devices on a node -- not
+// true in this case).
+//
+ std::vector<uint32_t> outputInterfaces (1);
+ outputInterfaces[0] = ifIndexLan1;
+
+ ipv4->AddMulticastRoute (multicastSource, multicastGroup, ifIndexLan0,
+ outputInterfaces);
+//
+// We need to specify how the source node handles multicasting. There are a
+// number of ways we can deal with this, we just need to pick one. The first
+// method is to add an explicit route out of the source node, just as we did
+// for the forwarding node. Use this method when you want to send packets out
+// multiple interfaces or send packets out different interfaces based on the
+// differing multicast groups. Since the source is local, there will be no
+// input interface over which packets are received, so use
+// Ipv4RoutingProtocol::IF_INDEX_ANY as a wildcard.
+//
+// A second way is to specify a multicast route using wildcards. If you
+// want to send multicasts out differing sets of interfaces based on the
+// multicast group, you can use AddMulticastRoute () but specify the origin
+// as a wildcard. If you want all multicasts to go out a single set of
+// interfaces, you can make both the origin and group a wildcard.
+//
+// If you have a simple system, where the source has a single interface, this
+// can be done via the SetDefaultMulticastRoute () method on the Ipv4
+// interface. This tells the system to send all multicasts out a single
+// specified network interface index.
+//
+// A last way is to specify a (or use an existing) default unicast route. The
+// multicast routing code uses the unicast default route as a multicast "route
+// of last resort." this method for is also on Ipv4 and is called
+// SetDefaultRoute ().
+//
+// Since this is a simple multicast example, we use the
+// SetDefaultMulticastRoute () approach. We are going to first need the
+// Ipv4 interface for node 0 which is the multicast source. We use this
+// interface to find the output interface index, and tell node zero to send
+// its multicast traffic out that interface.
+//
+ ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t ifIndexSrc = ipv4->FindInterfaceForAddr (multicastSource);
+ ipv4->SetDefaultMulticastRoute (ifIndexSrc);
+//
+// As described above, node four will be the only node listening for the
+// multicast data. To enable forwarding bits up the protocol stack, we need
+// to tell the stack to join the multicast group.
+//
+ ipv4 = n4->QueryInterface<Ipv4> (Ipv4::iid);
+ ipv4->JoinMulticastGroup (multicastSource, multicastGroup);
+//
+// Create an OnOff application to send UDP datagrams from node zero to the
+// multicast group (node four will be listening).
+//
+ NS_DEBUG("Create Applications.");
+ Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+ n0,
+ InetSocketAddress (multicastGroup, 80),
+ "Udp",
+ ConstantVariable(1),
+ ConstantVariable(0),
+ DataRate ("255b/s"),
+ 128);
+//
+// Tell the application when to start and stop.
+//
+ ooff->Start(Seconds(1.));
+ ooff->Stop (Seconds(10.));
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-multicast.tr"
+//
+ NS_DEBUG("Configure Tracing.");
+ AsciiTrace asciitrace ("csma-multicast.tr");
+ asciitrace.TraceAllNetDeviceRx ();
+ asciitrace.TraceAllQueues ();
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+// csma-multicast.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
+ PcapTrace pcaptrace ("csma-multicast.pcap");
+ pcaptrace.TraceAllIp ();
+//
+// Now, do the actual simulation.
+//
+ NS_DEBUG("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_DEBUG("Done.");
+}
--- a/examples/csma-one-subnet.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/csma-one-subnet.cc Wed Sep 12 18:06:09 2007 +0100
@@ -14,35 +14,25 @@
* 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
// | | | |
-// =====================
+// =================
+// LAN
//
-// - 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)
+// - CBR/UDP flows from n0 to n1 and from n3 to n0
// - DropTail queues
// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
#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"
@@ -58,109 +48,168 @@
#include "ns3/ipv4-route.h"
#include "ns3/onoff-application.h"
-
using namespace ns3;
-
-int main (int argc, char *argv[])
-{
+NS_DEBUG_COMPONENT_DEFINE ("CsmaOneSubnet");
- // Users may find it convenient to turn on explicit debugging
- // for selected modules; the below lines suggest how to do this
+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("CsmaOneSubnet");
+
+ DebugComponentEnable("Object");
+ DebugComponentEnable("Queue");
+ DebugComponentEnable("DropTailQueue");
+ DebugComponentEnable("Channel");
+ DebugComponentEnable("CsmaChannel");
DebugComponentEnable("CsmaNetDevice");
DebugComponentEnable("Ipv4L3Protocol");
DebugComponentEnable("NetDevice");
- DebugComponentEnable("Channel");
- DebugComponentEnable("CsmaChannel");
DebugComponentEnable("PacketSocket");
+ DebugComponentEnable("OnOffApplication");
+ DebugComponentEnable("UdpSocket");
+ DebugComponentEnable("UdpL4Protocol");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("Ipv4StaticRouting");
+ DebugComponentEnable("Ipv4Interface");
+ DebugComponentEnable("ArpIpv4Interface");
+ DebugComponentEnable("Ipv4LoopbackInterface");
#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
+//
+// Set up default values for the simulation. Use the DefaultValue::Bind()
+// technique to tell the system what subclass of Queue to use. The Bind
+// command 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
+//
+// Allow the user to override any of the defaults and the above Bind() 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.
+//
+// Explicitly create the nodes required by the topology (shown above).
+//
+ NS_DEBUG("Create nodes.");
Ptr<Node> n0 = Create<InternetNode> ();
Ptr<Node> n1 = Create<InternetNode> ();
Ptr<Node> n2 = Create<InternetNode> ();
Ptr<Node> n3 = Create<InternetNode> ();
- // We create the channels first without any IP addressing information
- Ptr<CsmaChannel> channel0 =
- CsmaTopology::CreateCsmaChannel(
- DataRate(5000000), MilliSeconds(2));
+ NS_DEBUG("Create channels.");
+//
+// Explicitly create the channels required by the topology (shown above).
+//
+ Ptr<CsmaChannel> lan = 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"));
+ NS_DEBUG("Build Topology.");
+//
+// Now fill out the topology by creating the net devices required to connect
+// the nodes to the channels and hooking them up. AddIpv4CsmaNetDevice will
+// create a net device, add a MAC address (in memory of the pink flamingo) and
+// connect the net device to a nodes and also to a channel. the
+// AddIpv4CsmaNetDevice method returns a net device index for the net device
+// created on the node. Interpret nd0 as the net device we created for node
+// zero.
+//
+ uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan,
+ Eui48Address("08:00:2e:00:00:00"));
+
+ uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan,
+ Eui48Address("08:00:2e:00:00:01"));
+
+ uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan,
+ Eui48Address("08:00:2e:00:00:02"));
+
+ uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan,
+ Eui48Address("08:00:2e:00:00:03"));
- // 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"));
+ NS_DEBUG ("nd0 = " << nd0);
+ NS_DEBUG ("nd1 = " << nd1);
+ NS_DEBUG ("nd2 = " << nd2);
+ NS_DEBUG ("nd3 = " << nd3);
+//
+// We've got the "hardware" in place. Now we need to add IP addresses.
+//
+ NS_DEBUG("Assign IP Addresses.");
+//
+// XXX BUGBUG
+// Need a better way to get the interface index. The point-to-point topology
+// as implemented can't return the index since it creates interfaces on both
+// sides (i.e., it does AddIpv4Addresses, not AddIpv4Address). We need a
+// method on Ipv4 to find the interface index corresponding to a given ipv4
+// address.
+//
+// Assign IP addresses to the net devices and associated interfaces
+// on the lan. The AddIpv4Address method returns an Ipv4 interface index
+// which we do not need here.
+//
+ CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address("10.1.1.1"),
+ Ipv4Mask("255.255.255.0"));
- CsmaIpv4Topology::AddIpv4Address (
- n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0"));
+ CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address("10.1.1.2"),
+ Ipv4Mask("255.255.255.0"));
+
+ CsmaIpv4Topology::AddIpv4Address (n2, nd2, 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
+ CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address("10.1.1.4"),
+ Ipv4Mask("255.255.255.0"));
+//
+// Create an OnOff application to send UDP datagrams from node zero to node 1.
+//
+ NS_DEBUG("Create Applications.");
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
n0,
InetSocketAddress ("10.1.1.2", 80),
"Udp",
ConstantVariable(1),
ConstantVariable(0));
- // Start the application
+//
+// Tell the application when to start and stop.
+//
ooff->Start(Seconds(1.0));
ooff->Stop (Seconds(10.0));
-
- // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+//
+// Create a similar flow from n3 to n0, starting at time 1.1 seconds
+//
ooff = Create<OnOffApplication> (
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
+//
+// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
+// Trace output will be sent to the file "csma-one-subnet.tr"
+//
+ NS_DEBUG("Configure Tracing.");
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-<nodeId>-<interfaceId>
- // and can be read by the "tcpdump -r" command (use "-tt" option to
- // display timestamps correctly)
+//
+// Also configure some tcpdump traces; each interface will be traced.
+// The output files will be named:
+// csma-one-subnet.pcap-<nodeId>-<interfaceId>
+// and can be read by the "tcpdump -r" command (use "-tt" option to
+// display timestamps correctly)
+//
PcapTrace pcaptrace ("csma-one-subnet.pcap");
pcaptrace.TraceAllIp ();
-
+//
+// Now, do the actual simulation.
+//
+ NS_DEBUG("Run Simulation.");
Simulator::Run ();
-
Simulator::Destroy ();
+ NS_DEBUG("Done.");
}
--- a/examples/mixed-global-routing.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/mixed-global-routing.cc Wed Sep 12 18:06:09 2007 +0100
@@ -128,13 +128,13 @@
CsmaTopology::CreateCsmaChannel(
DataRate(5000000), MilliSeconds(2));
- uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channelc0,
+ uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channelc0,
Eui48Address("10:54:23:54:23:50"));
- uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channelc0,
+ uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, channelc0,
Eui48Address("10:54:23:54:23:51"));
- uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n4, channelc0,
+ uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, channelc0,
Eui48Address("10:54:23:54:23:52"));
- uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n5, channelc0,
+ uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, channelc0,
Eui48Address("10:54:23:54:23:53"));
// Later, we add IP addresses.
--- a/examples/simple-global-routing.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/simple-global-routing.cc Wed Sep 12 18:06:09 2007 +0100
@@ -157,8 +157,7 @@
Ptr<PacketSink> sink = Create<PacketSink> (
n3,
InetSocketAddress (Ipv4Address::GetAny (), 80),
- "Udp",
- true);
+ "Udp");
// Start the sink
sink->Start (Seconds (1.0));
sink->Stop (Seconds (10.0));
@@ -178,8 +177,7 @@
sink = Create<PacketSink> (
n1,
InetSocketAddress (Ipv4Address::GetAny (), 80),
- "Udp",
- true);
+ "Udp");
// Start the sink
sink->Start (Seconds (1.1));
sink->Stop (Seconds (10.0));
--- a/examples/simple-point-to-point.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/simple-point-to-point.cc Wed Sep 12 18:06:09 2007 +0100
@@ -38,11 +38,7 @@
// - Tracing of queues and packet receptions to file
// "simple-point-to-point.tr"
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
+#include "ns3/debug.h"
#include "ns3/command-line.h"
#include "ns3/default-value.h"
#include "ns3/ptr.h"
@@ -68,19 +64,34 @@
using namespace ns3;
-int main (int argc, char *argv[])
+NS_DEBUG_COMPONENT_DEFINE ("Me");
+
+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("Me");
DebugComponentEnable("Object");
DebugComponentEnable("Queue");
DebugComponentEnable("DropTailQueue");
DebugComponentEnable("Channel");
DebugComponentEnable("PointToPointChannel");
DebugComponentEnable("PointToPointNetDevice");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("NetDevice");
+ DebugComponentEnable("PacketSocket");
+ DebugComponentEnable("OnOffApplication");
+ DebugComponentEnable("UdpSocket");
+ DebugComponentEnable("UdpL4Protocol");
+ DebugComponentEnable("Ipv4L3Protocol");
+ DebugComponentEnable("Ipv4StaticRouting");
+ DebugComponentEnable("Ipv4Interface");
+ DebugComponentEnable("ArpIpv4Interface");
+ DebugComponentEnable("Ipv4LoopbackInterface");
#endif
// Set up some default values for the simulation. Use the Bind()
@@ -102,12 +113,14 @@
// Here, we will explicitly create four nodes. In more sophisticated
// topologies, we could configure a node factory.
+ NS_DEBUG("Create nodes.");
Ptr<Node> n0 = Create<InternetNode> ();
Ptr<Node> n1 = Create<InternetNode> ();
Ptr<Node> n2 = Create<InternetNode> ();
Ptr<Node> n3 = Create<InternetNode> ();
// We create the channels first without any IP addressing information
+ NS_DEBUG("Create channels.");
Ptr<PointToPointChannel> channel0 =
PointToPointTopology::AddPointToPointLink (
n0, n2, DataRate(5000000), MilliSeconds(2));
@@ -121,6 +134,7 @@
n2, n3, DataRate(1500000), MilliSeconds(10));
// Later, we add IP addresses.
+ NS_DEBUG("Assign IP Addresses.");
PointToPointTopology::AddIpv4Addresses (
channel0, n0, Ipv4Address("10.1.1.1"),
n2, Ipv4Address("10.1.1.2"));
@@ -137,13 +151,14 @@
// 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
+ NS_DEBUG("Add Static Routes.");
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
+ NS_DEBUG("Create Applications.");
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
n0,
InetSocketAddress ("10.1.3.2", 80),
@@ -182,10 +197,10 @@
// Start the sink
sink->Start (Seconds (1.1));
sink->Stop (Seconds (10.0));
- sink->SetQuiet (); // disable output from the Receive callback
// Here, finish off packet routing configuration
// This will likely set by some global StaticRouting object in the future
+ NS_DEBUG("Set Default Routes.");
Ptr<Ipv4> ipv4;
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
@@ -194,6 +209,7 @@
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
// Trace output will be sent to the simple-point-to-point.tr file
+ NS_DEBUG("Configure Tracing.");
AsciiTrace asciitrace ("simple-point-to-point.tr");
asciitrace.TraceAllQueues ();
asciitrace.TraceAllNetDeviceRx ();
@@ -206,7 +222,8 @@
PcapTrace pcaptrace ("simple-point-to-point.pcap");
pcaptrace.TraceAllIp ();
- Simulator::Run ();
-
+ NS_DEBUG("Run Simulation.");
+ Simulator::Run ();
Simulator::Destroy ();
+ NS_DEBUG("Done.");
}
--- a/examples/wscript Tue Sep 11 15:09:55 2007 +0100
+++ b/examples/wscript Wed Sep 12 18:06:09 2007 +0100
@@ -22,6 +22,10 @@
['csma', 'internet-node'])
obj.source = 'csma-packet-socket.cc'
+ obj = bld.create_ns3_program('csma-multicast',
+ ['csma', 'internet-node'])
+ obj.source = 'csma-multicast.cc'
+
obj = bld.create_ns3_program( 'mixed-global-routing',
['point-to-point', 'internet-node', 'global-routing' , 'csma-cd'])
obj.source = 'mixed-global-routing.cc'
--- a/src/applications/onoff-application.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/applications/onoff-application.cc Wed Sep 12 18:06:09 2007 +0100
@@ -22,6 +22,7 @@
// George F. Riley, Georgia Tech, Spring 2007
// Adapted from ApplicationOnOff in GTNetS.
+#include "ns3/debug.h"
#include "ns3/address.h"
#include "ns3/node.h"
#include "ns3/nstime.h"
@@ -34,6 +35,8 @@
#include "ns3/packet.h"
#include "onoff-application.h"
+NS_DEBUG_COMPONENT_DEFINE ("OnOffApplication");
+
using namespace std;
namespace ns3 {
@@ -95,30 +98,37 @@
m_iid = iid;
}
-
OnOffApplication::~OnOffApplication()
-{}
+{
+ NS_DEBUG("OnOffApplication::~OnOffApplication()");
+}
void
OnOffApplication::SetMaxBytes(uint32_t maxBytes)
{
+ NS_DEBUG("OnOffApplication::SetMaxBytes(" << maxBytes << ")");
m_maxBytes = maxBytes;
}
void
OnOffApplication::SetDefaultRate (const DataRate &rate)
{
+ NS_DEBUG("OnOffApplication::SetDefaultRate(" << &rate << ")");
g_defaultRate.SetValue (rate);
}
+
void
OnOffApplication::SetDefaultSize (uint32_t size)
{
+ NS_DEBUG("OnOffApplication::SetDefaultSize(" << size << ")");
g_defaultSize.SetValue (size);
}
void
OnOffApplication::DoDispose (void)
{
+ NS_DEBUG("OnOffApplication::DoDispose()");
+
m_socket = 0;
delete m_onTime;
delete m_offTime;
@@ -130,10 +140,11 @@
Application::DoDispose ();
}
+// Application Methods
+void OnOffApplication::StartApplication() // Called at time specified by Start
+{
+ NS_DEBUG("OnOffApplication::StartApplication()");
-// Application Methods
-void OnOffApplication::StartApplication() // Called at time specified by Start
-{
// Create the socket if not already
if (!m_socket)
{
@@ -151,8 +162,10 @@
ScheduleStartEvent();
}
-void OnOffApplication::StopApplication() // Called at time specified by Stop
+void OnOffApplication::StopApplication() // Called at time specified by Stop
{
+ NS_DEBUG("OnOffApplication::StopApplication()");
+
if (m_sendEvent.IsRunning ())
{ // Cancel the pending send packet event
// Calculate residual bits since last packet sent
@@ -166,23 +179,32 @@
// Event handlers
void OnOffApplication::StartSending()
{
+ NS_DEBUG("OnOffApplication::StartSending ()");
+
ScheduleNextTx(); // Schedule the send packet event
}
void OnOffApplication::StopSending()
{
+ NS_DEBUG("OnOffApplication::StopSending ()");
+
Simulator::Cancel(m_sendEvent);
}
// Private helpers
void OnOffApplication::ScheduleNextTx()
{
+ NS_DEBUG("OnOffApplication::ScheduleNextTx ()");
+
if (m_totBytes < m_maxBytes)
{
uint32_t bits = m_pktSize * 8 - m_residualBits;
+ NS_DEBUG("OnOffApplication::ScheduleNextTx (): bits = " << bits);
Time nextTime(Seconds (bits /
static_cast<double>(m_cbrRate.GetBitRate()))); // Time till next packet
- m_sendEvent = Simulator::Schedule(nextTime, &OnOffApplication::SendPacket, this);
+ NS_DEBUG("OnOffApplication::ScheduleNextTx (): nextTime = " << nextTime);
+ m_sendEvent = Simulator::Schedule(nextTime,
+ &OnOffApplication::SendPacket, this);
}
else
{ // All done, cancel any pending events
@@ -192,12 +214,18 @@
void OnOffApplication::ScheduleStartEvent()
{ // Schedules the event to start sending data (switch to the "On" state)
+ NS_DEBUG("OnOffApplication::ScheduleStartEvent ()");
+
Time offInterval = Seconds(m_offTime->GetValue());
+ NS_DEBUG("OnOffApplication::ScheduleStartEvent (): "
+ "start at " << offInterval);
m_startStopEvent = Simulator::Schedule(offInterval, &OnOffApplication::StartSending, this);
}
void OnOffApplication::ScheduleStopEvent()
{ // Schedules the event to stop sending data (switch to "Off" state)
+ NS_DEBUG("OnOffApplication::ScheduleStopEvent ()");
+
Time onInterval = Seconds(m_onTime->GetValue());
Simulator::Schedule(onInterval, &OnOffApplication::StopSending, this);
}
@@ -205,6 +233,8 @@
void OnOffApplication::SendPacket()
{
+ NS_DEBUG("OnOffApplication::SendPacket ()");
+
NS_ASSERT (m_sendEvent.IsExpired ());
m_socket->Send(Packet (m_pktSize));
m_totBytes += m_pktSize;
@@ -215,6 +245,8 @@
void OnOffApplication::ConnectionSucceeded(Ptr<Socket>)
{
+ NS_DEBUG("OnOffApplication::ConnectionSucceeded ()");
+
m_connected = true;
ScheduleStartEvent();
}
--- a/src/applications/packet-sink.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/applications/packet-sink.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,20 +1,22 @@
-/* -*- 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
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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: Tom Henderson (tomhend@u.washington.edu)
+ */
#include "ns3/address.h"
#include "ns3/debug.h"
#include "ns3/inet-socket-address.h"
@@ -35,35 +37,26 @@
PacketSink::PacketSink (Ptr<Node> n,
const Address &local,
- std::string iid,
- bool quiet)
+ std::string iid)
: Application(n)
{
- Construct (n, local, iid, quiet);
+ Construct (n, local, iid);
}
void
PacketSink::Construct (Ptr<Node> n,
const Address &local,
- std::string iid,
- bool quiet)
+ std::string iid)
{
m_socket = 0;
m_local = local;
m_iid = iid;
- m_quiet = quiet;
}
PacketSink::~PacketSink()
{}
void
-PacketSink::SetQuiet()
-{
- m_quiet = true;
-}
-
-void
PacketSink::DoDispose (void)
{
m_socket = 0;
@@ -99,19 +92,17 @@
}
}
-// This callback body suggested by Joe Kopena's wiki
+// This LOG output inspired by the application on Joseph Kopena's wiki
void PacketSink::Receive(Ptr<Socket> socket, const Packet &packet,
const Address &from)
{
- if (!m_quiet)
+ if (InetSocketAddress::IsMatchingType (from))
{
- if (InetSocketAddress::IsMatchingType (from))
- {
- InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
- NS_DEBUG ( __PRETTY_FUNCTION__ << ": Received " <<
- packet.GetSize() << " bytes from " << address.GetIpv4() << " ["
- << address << "]---'" << packet.PeekData() << "'");
- }
+ InetSocketAddress address = InetSocketAddress::ConvertFrom (from);
+ NS_DEBUG ( __PRETTY_FUNCTION__ << ": Received " <<
+ packet.GetSize() << " bytes from " << address.GetIpv4() << " ["
+ << address << "]---'" << packet.PeekData() << "'");
+ // TODO: Add a tracing source here
}
}
--- a/src/applications/packet-sink.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/applications/packet-sink.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,21 +1,22 @@
-/* -*- 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
-//
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright 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: Tom Henderson (tomhend@u.washington.edu)
+ */
#ifndef __packet_sink_h__
#define __packet_sink_h__
@@ -33,34 +34,34 @@
/**
* \brief Receive and consume traffic generated to an IP address and port
*
- * This Application can be used as a receiver for packets generated by
- * traffic sourcing applications such as OnOffApplication. The constructor
- * specifies the Address (IP address and port) and the transport protocol
- * to use. A virtual Receive () method is installed as a callback on
- * the receiving socket. By default, it prints out the size of packets
- * and their address.
+ * This application was written to complement OnOffApplication, but it
+ * is more general so a PacketSink name was selected. Functionally it is
+ * important to use in multicast situations, so that reception of the layer-2
+ * multicast frames of interest are enabled, but it is also useful for
+ * unicast as an example of how you can write something simple to receive
+ * packets at the application layer. Also, if an IP stack generates
+ * ICMP Port Unreachable errors, receiving applications will be needed.
+ *
+ * The constructor specifies the Address (IP address and port) and the
+ * transport protocol to use. A virtual Receive () method is installed
+ * as a callback on the receiving socket. By default, when logging is
+ * enabled, it prints out the size of packets and their address, but
+ * we intend to also add a tracing source to Receive() at a later date.
*/
class PacketSink : public Application
{
public:
/**
* \param n node associated to this application
- * \param local local ip address
- * \param iid
- * \param ontime on time random variable
- * \param offtime off time random variable
+ * \param local local address to bind to
+ * \param iid string to identify transport protocol of interest
*/
PacketSink (Ptr<Node> n,
const Address &local,
- std::string iid, bool quiet=false);
+ std::string iid);
virtual ~PacketSink ();
- /**
- * \brief Turn off the logging output for the receive callback
- */
- void SetQuiet (void);
-
protected:
virtual void DoDispose (void);
private:
@@ -70,15 +71,13 @@
void Construct (Ptr<Node> n,
const Address &local,
- std::string iid,
- bool quiet);
+ std::string iid);
virtual void Receive (Ptr<Socket> socket, const Packet& packet, const Address& from);
Ptr<Socket> m_socket; // Associated socket
Address m_local; // Local address to bind to
std::string m_iid; // Protocol name (e.g., "Udp")
- bool m_quiet; // Governs whether receive callback is quiet
};
--- a/src/common/buffer.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/buffer.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2005,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
@@ -20,385 +19,534 @@
*/
#include "buffer.h"
#include "ns3/assert.h"
-
+#include "ns3/debug.h"
#include <iostream>
-//#define TRACE(x) std::cout << x << std::endl;
-#define TRACE(x)
+
+NS_DEBUG_COMPONENT_DEFINE ("Buffer");
+
+#define DEBUG_INTERNAL_STATE(y) \
+NS_DEBUG (y << "start="<<m_start<<", end="<<m_end<<", zero start="<<m_zeroAreaStart<< \
+ ", zero end="<<m_zeroAreaEnd<<", count="<<m_data->m_count<<", size="<<m_data->m_size<< \
+ ", dirty start="<<m_data->m_dirtyStart<<", dirty end="<<m_data->m_dirtyEnd)
+
+#ifdef BUFFER_HEURISTICS
+#define HEURISTICS(x) x
+#else
+#define HEURISTICS(x)
+#endif
+
+//#define PRINT_STATS 1
namespace ns3 {
-Buffer::BufferDataList Buffer::m_freeList;
-uint32_t Buffer::m_maxTotalAddStart = 0;
-uint32_t Buffer::m_maxTotalAddEnd = 0;
+/**
+ * This data structure is variable-sized through its last member whose size
+ * is determined at allocation time and stored in the m_size field.
+ *
+ * The so-called "dirty area" describes the area in the buffer which
+ * has been reserved and used by a user. Multiple Buffer instances
+ * may reference the same BufferData object instance and may
+ * reference different parts of the underlying byte buffer. The
+ * "dirty area" is union of all the areas referenced by the Buffer
+ * instances which reference the same BufferData instance.
+ * New user data can be safely written only outside of the "dirty
+ * area" if the reference count is higher than 1 (that is, if
+ * more than one Buffer instance references the same BufferData).
+ */
+struct BufferData {
+ /* The reference count of an instance of this data structure.
+ * Each buffer which references an instance holds a count.
+ */
+ uint32_t m_count;
+ /* the size of the m_data field below.
+ */
+ uint32_t m_size;
+ /* offset from the start of the m_data field below to the
+ * start of the area in which user bytes were written.
+ */
+ uint32_t m_dirtyStart;
+ /* offset from the start of the m_data field below to the
+ * end of the area in which user bytes were written.
+ */
+ uint32_t m_dirtyEnd;
+ /* The real data buffer holds _at least_ one byte.
+ * Its real size is stored in the m_size field.
+ */
+ uint8_t m_data[1];
+};
+class BufferDataList : public std::vector<struct BufferData*>
+{
+public:
+ ~BufferDataList ();
+};
-Buffer::BufferDataList::~BufferDataList ()
+static struct BufferData *BufferAllocate (uint32_t reqSize);
+
+static void BufferDeallocate (struct BufferData *data);
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+#ifdef BUFFER_HEURISTICS
+static uint32_t g_recommendedStart = 0;
+static uint64_t g_nAddNoRealloc = 0;
+static uint64_t g_nAddRealloc = 0;
+static BufferDataList g_freeList;
+static uint32_t g_maxSize = 0;
+static uint64_t g_nAllocs = 0;
+static uint64_t g_nCreates = 0;
+#endif /* BUFFER_HEURISTICS */
+
+BufferDataList::~BufferDataList ()
{
+#ifdef PRINT_STATS
+#ifdef BUFFER_HEURISTICS
+ double efficiency;
+ efficiency = g_nAllocs;
+ efficiency /= g_nCreates;
+ std::cout <<"buffer free list efficiency="<<efficiency<<" (lower is better)" << std::endl;
+ std::cout <<"buffer free list max size="<<g_maxSize<<std::endl;
+ std::cout <<"buffer free list recommended start="<<g_recommendedStart<<std::endl;
+ double addEfficiency;
+ addEfficiency = g_nAddRealloc;
+ addEfficiency /= g_nAddNoRealloc;
+ std::cout <<"buffer add efficiency=" << addEfficiency << " (lower is better)"<<std::endl;
+ //std::cout <<"n add reallocs="<< g_nAddRealloc << std::endl;
+ //std::cout <<"n add no reallocs="<< g_nAddNoRealloc << std::endl;
+#endif /* BUFFER_HEURISTICS */
+#endif /* PRINT_STATS */
for (BufferDataList::iterator i = begin ();
i != end (); i++)
{
- Buffer::Deallocate (*i);
+ BufferDeallocate (*i);
}
}
-struct Buffer::BufferData *
-Buffer::Allocate (uint32_t reqSize, uint32_t reqStart)
+struct BufferData *
+BufferAllocate (uint32_t reqSize)
{
if (reqSize == 0)
{
reqSize = 1;
}
NS_ASSERT (reqSize >= 1);
- uint32_t size = reqSize - 1 + sizeof (struct Buffer::BufferData);
+ uint32_t size = reqSize - 1 + sizeof (struct BufferData);
uint8_t *b = new uint8_t [size];
- struct BufferData *data = reinterpret_cast<struct Buffer::BufferData*>(b);
+ struct BufferData *data = reinterpret_cast<struct BufferData*>(b);
data->m_size = reqSize;
- data->m_initialStart = reqStart;
- data->m_dirtyStart = reqStart;
- data->m_dirtySize = 0;
data->m_count = 1;
return data;
}
void
-Buffer::Deallocate (struct Buffer::BufferData *data)
+BufferDeallocate (struct BufferData *data)
{
+ NS_ASSERT (data->m_count == 0);
uint8_t *buf = reinterpret_cast<uint8_t *> (data);
delete [] buf;
}
-#ifdef USE_FREE_LIST
+#ifdef BUFFER_HEURISTICS
void
-Buffer::Recycle (struct Buffer::BufferData *data)
+Buffer::Recycle (struct BufferData *data)
{
NS_ASSERT (data->m_count == 0);
- /* get rid of it if it is too small for later reuse. */
- if (data->m_size < (Buffer::m_maxTotalAddStart + Buffer::m_maxTotalAddEnd))
- {
- Buffer::Deallocate (data);
- return;
- }
+ g_maxSize = std::max (g_maxSize, data->m_size);
/* feed into free list */
- if (Buffer::m_freeList.size () > 1000)
+ if (data->m_size < g_maxSize ||
+ g_freeList.size () > 1000)
{
- Buffer::Deallocate (data);
- }
- else
+ BufferDeallocate (data);
+ }
+ else
{
- Buffer::m_freeList.push_back (data);
+ g_freeList.push_back (data);
}
}
-Buffer::BufferData *
-Buffer::Create (void)
+BufferData *
+Buffer::Create (uint32_t dataSize)
{
/* try to find a buffer correctly sized. */
- while (!Buffer::m_freeList.empty ())
+ g_nCreates++;
+ while (!g_freeList.empty ())
{
- struct Buffer::BufferData *data = Buffer::m_freeList.back ();
- Buffer::m_freeList.pop_back ();
- if (data->m_size >= (m_maxTotalAddStart + m_maxTotalAddEnd))
+ struct BufferData *data = g_freeList.back ();
+ g_freeList.pop_back ();
+ if (data->m_size >= dataSize)
{
- data->m_initialStart = m_maxTotalAddStart;
- data->m_dirtyStart = m_maxTotalAddStart;
- data->m_dirtySize = 0;
data->m_count = 1;
return data;
}
- Buffer::Deallocate (data);
+ BufferDeallocate (data);
}
- struct Buffer::BufferData *data = Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
- m_maxTotalAddStart);
+ g_nAllocs++;
+ struct BufferData *data = BufferAllocate (dataSize);
NS_ASSERT (data->m_count == 1);
return data;
}
#else
void
-Buffer::Recycle (struct Buffer::BufferData *data)
+Buffer::Recycle (struct BufferData *data)
{
- Buffer::Deallocate (data);
+ NS_ASSERT (data->m_count == 0);
+ BufferDeallocate (data);
}
-Buffer::BufferData *
-Buffer::Create (void)
+BufferData *
+Buffer::Create (uint32_t size)
{
- return Buffer::Allocate (m_maxTotalAddStart+m_maxTotalAddEnd,
- m_maxTotalAddStart);
+ return BufferAllocate (size);
}
#endif
-}; // namespace ns3
+Buffer::Buffer ()
+{
+ Initialize (0);
+}
+Buffer::Buffer (uint32_t dataSize)
+{
+ Initialize (dataSize);
+}
-#include "ns3/assert.h"
+bool
+Buffer::CheckInternalState (void) const
+{
+ bool offsetsOk =
+ m_start <= m_zeroAreaStart &&
+ m_zeroAreaStart <= m_zeroAreaEnd &&
+ m_zeroAreaEnd <= m_end;
+ bool dirtyOk =
+ m_start >= m_data->m_dirtyStart &&
+ m_end <= m_data->m_dirtyEnd;
+ bool internalSizeOk = m_end - (m_zeroAreaEnd - m_zeroAreaStart) <= m_data->m_size &&
+ m_start <= m_data->m_size &&
+ m_zeroAreaStart <= m_data->m_size;
-namespace ns3 {
+ NS_ASSERT (offsetsOk);
+ NS_ASSERT (dirtyOk);
+ NS_ASSERT (internalSizeOk);
+ return m_data->m_count > 0 && offsetsOk && dirtyOk &&
+ internalSizeOk;
+}
-void
-Buffer::AddAtStart (uint32_t start)
+void
+Buffer::Initialize (uint32_t zeroSize)
{
- NS_ASSERT (m_start <= m_data->m_initialStart);
- bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
- if (m_start >= start && !isDirty)
- {
- /* enough space in the buffer and not dirty. */
- m_start -= start;
- m_size += start;
- }
- else if (m_size + start <= m_data->m_size && !isDirty)
+ m_data = Buffer::Create (0);
+#ifdef BUFFER_HEURISTICS
+ m_start = std::min (m_data->m_size, g_recommendedStart);
+ m_maxZeroAreaStart = m_start;
+#else
+ m_start = 0;
+#endif /* BUFFER_HEURISTICS */
+ m_zeroAreaStart = m_start;
+ m_zeroAreaEnd = m_zeroAreaStart + zeroSize;
+ m_end = m_zeroAreaEnd;
+ m_data->m_dirtyStart = m_start;
+ m_data->m_dirtyEnd = m_end;
+ NS_ASSERT (CheckInternalState ());
+}
+
+Buffer::Buffer (Buffer const&o)
+ : m_data (o.m_data),
+#ifdef BUFFER_HEURISTICS
+ m_maxZeroAreaStart (o.m_zeroAreaStart),
+#endif
+ m_zeroAreaStart (o.m_zeroAreaStart),
+ m_zeroAreaEnd (o.m_zeroAreaEnd),
+ m_start (o.m_start),
+ m_end (o.m_end)
+{
+ m_data->m_count++;
+ NS_ASSERT (CheckInternalState ());
+}
+
+Buffer &
+Buffer::operator = (Buffer const&o)
+{
+ NS_ASSERT (CheckInternalState ());
+ if (m_data != o.m_data)
{
- /* enough space but need to move data around to fit new data */
- memmove (m_data->m_data + start, GetStart (), m_size);
- NS_ASSERT (start > m_start);
- m_data->m_initialStart += start - m_start;
- m_start = 0;
- m_size += start;
- }
- else if (m_start < start)
- {
- /* not enough space in buffer */
- uint32_t newSize = m_size + start;
- struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
- memcpy (newData->m_data + start, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart + start;
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- Buffer::Deallocate (m_data);
- }
- m_data = newData;
- m_start = 0;
- m_size = newSize;
- }
- else
- {
- /* enough space in the buffer but it is dirty ! */
- NS_ASSERT (isDirty);
- struct Buffer::BufferData *newData = Buffer::Create ();
- memcpy (newData->m_data + m_start, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart;
+ // not assignment to self.
m_data->m_count--;
if (m_data->m_count == 0)
{
Recycle (m_data);
}
- m_data = newData;
+ m_data = o.m_data;
+ m_data->m_count++;
+ }
+ HEURISTICS (
+ g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart);
+ m_maxZeroAreaStart = o.m_maxZeroAreaStart;
+ );
+ m_zeroAreaStart = o.m_zeroAreaStart;
+ m_zeroAreaEnd = o.m_zeroAreaEnd;
+ m_start = o.m_start;
+ m_end = o.m_end;
+ NS_ASSERT (CheckInternalState ());
+ return *this;
+}
+
+Buffer::~Buffer ()
+{
+ HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ Recycle (m_data);
+ }
+}
+
+uint32_t
+Buffer::GetSize (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ return m_end - m_start;
+}
+
+Buffer::Iterator
+Buffer::Begin (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ return Buffer::Iterator (this);
+}
+Buffer::Iterator
+Buffer::End (void) const
+{
+ NS_ASSERT (CheckInternalState ());
+ return Buffer::Iterator (this, false);
+}
+
+uint32_t
+Buffer::GetInternalSize (void) const
+{
+ return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd;
+}
+uint32_t
+Buffer::GetInternalEnd (void) const
+{
+ return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
+}
+
+void
+Buffer::AddAtStart (uint32_t start)
+{
+ NS_ASSERT (CheckInternalState ());
+ bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
+ if (m_start >= start && !isDirty)
+ {
+ /* enough space in the buffer and not dirty.
+ * To add: |..|
+ * Before: |*****---------***|
+ * After: |***..---------***|
+ */
+ NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
m_start -= start;
- m_size += start;
+ HEURISTICS (g_nAddNoRealloc++);
}
+#if 0
+ // the following is an optimization
+ else if (m_start >= start)
+ {
+ struct BufferData *newData = Buffer::Create (m_data->m_size);
+ memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ Buffer::Recycle (m_data);
+ }
+ m_data = newData;
+
+ m_start -= start;
+ HEURISTICS (g_nAddRealloc++);
+ }
+ else
+ {
+ NS_ASSERT (m_start < start);
+#else
+ else
+ {
+#endif
+ uint32_t newSize = GetInternalSize () + start;
+ struct BufferData *newData = Buffer::Create (newSize);
+ memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
+ m_data->m_count--;
+ if (m_data->m_count == 0)
+ {
+ Buffer::Recycle (m_data);
+ }
+ m_data = newData;
+
+ int32_t delta = start - m_start;
+ m_start = 0;
+ m_zeroAreaStart += delta;
+ m_zeroAreaEnd += delta;
+ m_end += delta;
+
+ HEURISTICS (g_nAddRealloc++);
+ }
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
// update dirty area
m_data->m_dirtyStart = m_start;
- m_data->m_dirtySize = m_size;
- // update m_maxTotalAddStart
- uint32_t addedAtStart;
- if (m_data->m_initialStart > m_start)
- {
- addedAtStart = m_data->m_initialStart - m_start;
- }
- else
- {
- addedAtStart = 0;
- }
- if (addedAtStart > m_maxTotalAddStart)
- {
- m_maxTotalAddStart = addedAtStart;
- }
- TRACE ("start add="<<start<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ m_data->m_dirtyEnd = m_end;
+ DEBUG_INTERNAL_STATE ("add start=" << start << ", ");
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::AddAtEnd (uint32_t end)
{
- NS_ASSERT (m_start <= m_data->m_initialStart);
- bool isDirty = m_data->m_count > 1 &&
- m_start + m_size < m_data->m_dirtyStart + m_data->m_dirtySize;
- if (m_start + m_size + end <= m_data->m_size && !isDirty)
- {
- /* enough space in buffer and not dirty */
- m_size += end;
- }
- else if (m_size + end <= m_data->m_size && !isDirty)
+ NS_ASSERT (CheckInternalState ());
+ bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
+ if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
{
- /* enough space but need to move data around to fit the extra data */
- uint32_t newStart = m_data->m_size - (m_size + end);
- memmove (m_data->m_data + newStart, GetStart (), m_size);
- NS_ASSERT (newStart < m_start);
- m_data->m_initialStart -= m_start - newStart;
- m_start = newStart;
- m_size += end;
+ /* enough space in buffer and not dirty
+ * Add: |...|
+ * Before: |**----*****|
+ * After: |**----...**|
+ */
+ NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
+ m_end += end;
+
+ HEURISTICS (g_nAddNoRealloc++);
}
- else if (m_start + m_size + end > m_data->m_size)
+#if 0
+ // this is an optimization
+ else if (GetInternalEnd () + end > m_data->m_size)
{
- /* not enough space in buffer */
- uint32_t newSize = m_size + end;
- struct Buffer::BufferData *newData = Buffer::Allocate (newSize, 0);
- memcpy (newData->m_data, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart - m_start;
+ struct BufferData *newData = Buffer::Create (newSize);
+ memcpy (newData->m_data + m_start, m_data->m_data + m_start, GetInternalSize ());
m_data->m_count--;
if (m_data->m_count == 0)
{
- Buffer::Deallocate (m_data);
+ Buffer::Recycle (m_data);
}
m_data = newData;
- m_size = newSize;
- m_start = 0;
- }
- else
+
+ m_end += end;
+ HEURISTICS (g_nAddRealloc++);
+ }
+#endif
+ else
{
- /* enough space in the buffer but it is dirty ! */
- NS_ASSERT (isDirty);
- struct Buffer::BufferData *newData = Buffer::Create ();
- memcpy (newData->m_data + m_start, GetStart (), m_size);
- newData->m_initialStart = m_data->m_initialStart;
+ uint32_t newSize = GetInternalSize () + end;
+ struct BufferData *newData = Buffer::Create (newSize);
+ memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ());
m_data->m_count--;
if (m_data->m_count == 0)
{
- Recycle (m_data);
+ Buffer::Recycle (m_data);
}
m_data = newData;
- m_size += end;
+
+
+ m_zeroAreaStart -= m_start;
+ m_zeroAreaEnd -= m_start;
+ m_end -= m_start;
+ m_start = 0;
+
+ m_end += end;
+
+ HEURISTICS (g_nAddRealloc++);
}
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
// update dirty area
m_data->m_dirtyStart = m_start;
- m_data->m_dirtySize = m_size;
- // update m_maxTotalAddEnd
- uint32_t endLoc = m_start + m_size;
- uint32_t addedAtEnd;
- if (m_data->m_initialStart < endLoc)
- {
- addedAtEnd = endLoc - m_data->m_initialStart;
- }
- else
- {
- addedAtEnd = 0;
- }
- if (addedAtEnd > m_maxTotalAddEnd)
- {
- m_maxTotalAddEnd = addedAtEnd;
- }
- TRACE ("end add="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ m_data->m_dirtyEnd = m_end;
+ DEBUG_INTERNAL_STATE ("add end=" << end << ", ");
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::RemoveAtStart (uint32_t start)
{
- if (m_zeroAreaSize == 0)
+ NS_ASSERT (CheckInternalState ());
+ uint32_t newStart = m_start + start;
+ if (newStart <= m_zeroAreaStart)
+ {
+ /* only remove start of buffer
+ */
+ m_start = newStart;
+ }
+ else if (newStart <= m_zeroAreaEnd)
{
- if (m_size <= start)
- {
- m_start += m_size;
- m_size = 0;
- }
- else
- {
- m_start += start;
- m_size -= start;
- }
+ /* remove start of buffer _and_ start of zero area
+ */
+ uint32_t delta = newStart - m_zeroAreaStart;
+ m_start = m_zeroAreaStart;
+ m_zeroAreaEnd -= delta;
+ m_end -= delta;
}
+ else if (newStart <= m_end)
+ {
+ /* remove start of buffer, complete zero area, and part
+ * of end of buffer
+ */
+ NS_ASSERT (m_end >= start);
+ uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart;
+ m_start = newStart - zeroSize;
+ m_end -= zeroSize;
+ m_zeroAreaStart = m_start;
+ m_zeroAreaEnd = m_start;
+ }
else
{
- NS_ASSERT (m_data->m_initialStart >= m_start);
- uint32_t zeroStart = m_data->m_initialStart - m_start;
- uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
- uint32_t dataEnd = m_size + m_zeroAreaSize;
- if (start <= zeroStart)
- {
- /* only remove start of buffer */
- m_start += start;
- m_size -= start;
- }
- else if (start <= zeroEnd)
- {
- /* remove start of buffer _and_ start of zero area */
- m_start += zeroStart;
- uint32_t zeroDelta = start - zeroStart;
- m_zeroAreaSize -= zeroDelta;
- NS_ASSERT (zeroDelta <= start);
- m_size -= zeroStart;
- }
- else if (start <= dataEnd)
- {
- /* remove start of buffer, complete zero area, and part
- * of end of buffer */
- m_start += start - m_zeroAreaSize;
- m_size -= start - m_zeroAreaSize;
- m_zeroAreaSize = 0;
- }
- else
- {
- /* remove all buffer */
- m_start += m_size;
- m_size = 0;
- m_zeroAreaSize = 0;
- }
+ /* remove all buffer */
+ m_end -= m_zeroAreaEnd - m_zeroAreaStart;
+ m_start = m_end;
+ m_zeroAreaEnd = m_end;
+ m_zeroAreaStart = m_end;
}
- TRACE ("start remove="<<start<<", start="<<m_start<<", size="<<m_size<<
- ", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
+ DEBUG_INTERNAL_STATE ("rem start=" << start << ", ");
+ NS_ASSERT (CheckInternalState ());
}
void
Buffer::RemoveAtEnd (uint32_t end)
{
- if (m_zeroAreaSize == 0)
+ NS_ASSERT (CheckInternalState ());
+ uint32_t newEnd = m_end - std::min (end, m_end - m_start);
+ if (newEnd > m_zeroAreaEnd)
{
- if (m_size <= end)
- {
- m_size = 0;
- }
- else
- {
- m_size -= end;
- }
- }
- else
+ /* remove part of end of buffer */
+ m_end = newEnd;
+ }
+ else if (newEnd > m_zeroAreaStart)
+ {
+ /* remove end of buffer, part of zero area */
+ m_end = newEnd;
+ m_zeroAreaEnd = newEnd;
+ }
+ else if (newEnd > m_start)
{
- NS_ASSERT (m_data->m_initialStart >= m_start);
- uint32_t zeroStart = m_data->m_initialStart - m_start;
- uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
- uint32_t dataEnd = m_size + m_zeroAreaSize;
- NS_ASSERT (zeroStart <= m_size);
- NS_ASSERT (zeroEnd <= m_size + m_zeroAreaSize);
- if (dataEnd <= end)
- {
- /* remove all buffer */
- m_zeroAreaSize = 0;
- m_start += m_size;
- m_size = 0;
- }
- else if (dataEnd - zeroStart <= end)
- {
- /* remove end of buffer, zero area, part of start of buffer */
- NS_ASSERT (end >= m_zeroAreaSize);
- m_size -= end - m_zeroAreaSize;
- m_zeroAreaSize = 0;
- }
- else if (dataEnd - zeroEnd <= end)
- {
- /* remove end of buffer, part of zero area */
- uint32_t zeroDelta = end - (dataEnd - zeroEnd);
- m_zeroAreaSize -= zeroDelta;
- m_size -= end - zeroDelta;
- }
- else
- {
- /* remove part of end of buffer */
- m_size -= end;
- }
+ /* remove end of buffer, zero area, part of start of buffer */
+ m_end = newEnd;
+ m_zeroAreaEnd = newEnd;
+ m_zeroAreaStart = newEnd;
}
- TRACE ("end remove="<<end<<", start="<<m_start<<", size="<<m_size<<", zero="<<m_zeroAreaSize<<
- ", real size="<<m_data->m_size<<", ini start="<<m_data->m_initialStart<<
- ", dirty start="<<m_data->m_dirtyStart<<", dirty size="<<m_data->m_dirtySize);
+ else
+ {
+ /* remove all buffer */
+ m_end = m_start;
+ m_zeroAreaEnd = m_start;
+ m_zeroAreaStart = m_start;
+ }
+ HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
+ DEBUG_INTERNAL_STATE ("rem end=" << end << ", ");
+ NS_ASSERT (CheckInternalState ());
}
Buffer
Buffer::CreateFragment (uint32_t start, uint32_t length) const
{
- uint32_t zeroStart = m_data->m_initialStart - m_start;
- uint32_t zeroEnd = zeroStart + m_zeroAreaSize;
- if (m_zeroAreaSize != 0 &&
+ NS_ASSERT (CheckInternalState ());
+ uint32_t zeroStart = m_zeroAreaStart - m_start;
+ uint32_t zeroEnd = zeroStart + m_zeroAreaEnd;
+ if (m_zeroAreaEnd != 0 &&
start + length > zeroStart &&
start <= zeroEnd)
{
@@ -407,51 +555,433 @@
Buffer tmp = *this;
tmp.RemoveAtStart (start);
tmp.RemoveAtEnd (GetSize () - (start + length));
+ NS_ASSERT (CheckInternalState ());
return tmp;
}
Buffer
Buffer::CreateFullCopy (void) const
{
- if (m_zeroAreaSize != 0)
+ NS_ASSERT (CheckInternalState ());
+ if (m_zeroAreaEnd != 0)
{
- NS_ASSERT (m_data->m_initialStart >= m_start);
- NS_ASSERT (m_size >= (m_data->m_initialStart - m_start));
Buffer tmp;
- tmp.AddAtStart (m_zeroAreaSize);
- tmp.Begin ().WriteU8 (0, m_zeroAreaSize);
- uint32_t dataStart = m_data->m_initialStart - m_start;
+ tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart);
+ tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart);
+ uint32_t dataStart = m_zeroAreaStart - m_start;
tmp.AddAtStart (dataStart);
tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
- uint32_t dataEnd = m_size - (m_data->m_initialStart - m_start);
+ uint32_t dataEnd = m_end - m_zeroAreaEnd;
tmp.AddAtEnd (dataEnd);
Buffer::Iterator i = tmp.End ();
i.Prev (dataEnd);
- i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
+ i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
return tmp;
}
+ NS_ASSERT (CheckInternalState ());
return *this;
}
void
Buffer::TransformIntoRealBuffer (void) const
{
+ NS_ASSERT (CheckInternalState ());
Buffer tmp = CreateFullCopy ();
*const_cast<Buffer *> (this) = tmp;
+ NS_ASSERT (CheckInternalState ());
}
uint8_t const*
Buffer::PeekData (void) const
{
+ NS_ASSERT (CheckInternalState ());
TransformIntoRealBuffer ();
+ NS_ASSERT (CheckInternalState ());
return m_data->m_data + m_start;
}
+/******************************************************
+ * The buffer iterator below.
+ ******************************************************/
+
+
+Buffer::Iterator::Iterator ()
+ : m_zeroStart (0),
+ m_zeroEnd (0),
+ m_dataStart (0),
+ m_dataEnd (0),
+ m_current (0),
+ m_data (0)
+{}
+Buffer::Iterator::Iterator (Buffer const*buffer)
+{
+ Construct (buffer);
+ m_current = m_dataStart;
+}
+Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy)
+{
+ Construct (buffer);
+ m_current = m_dataEnd;
+}
+
+void
+Buffer::Iterator::Construct (const Buffer *buffer)
+{
+ m_zeroStart = buffer->m_zeroAreaStart;
+ m_zeroEnd = buffer->m_zeroAreaEnd;
+ m_dataStart = buffer->m_start;
+ m_dataEnd = buffer->m_end;
+ m_data = buffer->m_data->m_data;
+}
+
+void
+Buffer::Iterator::Next (void)
+{
+ NS_ASSERT (m_current + 1 <= m_dataEnd);
+ m_current++;
+}
+void
+Buffer::Iterator::Prev (void)
+{
+ NS_ASSERT (m_current >= 1);
+ m_current--;
+}
+void
+Buffer::Iterator::Next (uint32_t delta)
+{
+ NS_ASSERT (m_current + delta <= m_dataEnd);
+ m_current += delta;
+}
+void
+Buffer::Iterator::Prev (uint32_t delta)
+{
+ NS_ASSERT (m_current >= delta);
+ m_current -= delta;
+}
+uint32_t
+Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
+{
+ NS_ASSERT (m_data == o.m_data);
+ int32_t diff = m_current - o.m_current;
+ if (diff < 0)
+ {
+ return -diff;
+ }
+ else
+ {
+ return diff;
+ }
+}
+
+bool
+Buffer::Iterator::IsEnd (void) const
+{
+ return m_current == m_dataEnd;
+}
+bool
+Buffer::Iterator::IsStart (void) const
+{
+ return m_current == m_dataStart;
+}
+
+bool
+Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const
+{
+ bool ok = true;
+ for (uint32_t i = start; i < end; i++)
+ {
+ if (!Check (i))
+ {
+ ok = false;
+ }
+ }
+ return ok;
+}
+bool
+Buffer::Iterator::Check (uint32_t i) const
+{
+ return i >= m_dataStart &&
+ !(i >= m_zeroStart && i < m_zeroEnd) &&
+ i <= m_dataEnd;
+}
+void
+Buffer::Iterator::Write (Iterator start, Iterator end)
+{
+ NS_ASSERT (start.m_data == end.m_data);
+ NS_ASSERT (start.m_current <= end.m_current);
+ NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
+ NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
+ NS_ASSERT (m_data != start.m_data);
+ uint32_t size = end.m_current - start.m_current;
+ Iterator cur = start;
+ for (uint32_t i = 0; i < size; i++)
+ {
+ uint8_t data = cur.ReadU8 ();
+ WriteU8 (data);
+ }
+}
-}; // namespace ns3
+void
+Buffer::Iterator::WriteU16 (uint16_t data)
+{
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+}
+void
+Buffer::Iterator::WriteU32 (uint32_t data)
+{
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+}
+void
+Buffer::Iterator::WriteU64 (uint64_t data)
+{
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+ data >>= 8;
+ WriteU8 (data & 0xff);
+}
+void
+Buffer::Iterator::WriteHtonU16 (uint16_t data)
+{
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 0) & 0xff);
+}
+void
+Buffer::Iterator::WriteHtonU32 (uint32_t data)
+{
+ WriteU8 ((data >> 24) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 0) & 0xff);
+}
+void
+Buffer::Iterator::WriteHtonU64 (uint64_t data)
+{
+ WriteU8 ((data >> 56) & 0xff);
+ WriteU8 ((data >> 48) & 0xff);
+ WriteU8 ((data >> 40) & 0xff);
+ WriteU8 ((data >> 32) & 0xff);
+ WriteU8 ((data >> 24) & 0xff);
+ WriteU8 ((data >> 16) & 0xff);
+ WriteU8 ((data >> 8) & 0xff);
+ WriteU8 ((data >> 0) & 0xff);
+}
+void
+Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
+{
+ for (uint32_t i = 0; i < size; i++)
+ {
+ WriteU8 (buffer[i]);
+ }
+}
+
+uint16_t
+Buffer::Iterator::ReadU16 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint16_t data = byte1;
+ data <<= 8;
+ data |= byte0;
+
+ return data;
+}
+uint32_t
+Buffer::Iterator::ReadU32 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint8_t byte2 = ReadU8 ();
+ uint8_t byte3 = ReadU8 ();
+ uint32_t data = byte3;
+ data <<= 8;
+ data |= byte2;
+ data <<= 8;
+ data |= byte1;
+ data <<= 8;
+ data |= byte0;
+ return data;
+}
+uint64_t
+Buffer::Iterator::ReadU64 (void)
+{
+ uint8_t byte0 = ReadU8 ();
+ uint8_t byte1 = ReadU8 ();
+ uint8_t byte2 = ReadU8 ();
+ uint8_t byte3 = ReadU8 ();
+ uint8_t byte4 = ReadU8 ();
+ uint8_t byte5 = ReadU8 ();
+ uint8_t byte6 = ReadU8 ();
+ uint8_t byte7 = ReadU8 ();
+ uint32_t data = byte7;
+ data <<= 8;
+ data |= byte6;
+ data <<= 8;
+ data |= byte5;
+ data <<= 8;
+ data |= byte4;
+ data <<= 8;
+ data |= byte3;
+ data <<= 8;
+ data |= byte2;
+ data <<= 8;
+ data |= byte1;
+ data <<= 8;
+ data |= byte0;
+
+ return data;
+}
+uint16_t
+Buffer::Iterator::ReadNtohU16 (void)
+{
+ uint16_t retval = 0;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ return retval;
+}
+uint32_t
+Buffer::Iterator::ReadNtohU32 (void)
+{
+ uint32_t retval = 0;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ return retval;
+}
+uint64_t
+Buffer::Iterator::ReadNtohU64 (void)
+{
+ uint64_t retval = 0;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ retval <<= 8;
+ retval |= ReadU8 ();
+ return retval;
+}
+void
+Buffer::Iterator::Read (uint8_t *buffer, uint32_t size)
+{
+ for (uint32_t i = 0; i < size; i++)
+ {
+ buffer[i] = ReadU8 ();
+ }
+}
+
+#ifndef BUFFER_USE_INLINE
+
+void
+Buffer::Iterator::WriteU8 (uint8_t data)
+{
+ if (m_current < m_dataStart)
+ {
+ // XXX trying to write outside of data area
+ NS_ASSERT (false);
+ }
+ else if (m_current < m_zeroStart)
+ {
+ m_data[m_current] = data;
+ m_current++;
+ }
+ else if (m_current < m_zeroEnd)
+ {
+ // XXX trying to write in zero area
+ NS_ASSERT (false);
+ }
+ else if (m_current < m_dataEnd)
+ {
+ m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+ m_current++;
+ }
+ else
+ {
+ // XXX trying to write outside of data area
+ NS_ASSERT (false);
+ }
+}
+
+void
+Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
+{
+ for (uint32_t i = 0; i < len; i++)
+ {
+ WriteU8 (data);
+ }
+}
+
+uint8_t
+Buffer::Iterator::ReadU8 (void)
+{
+ if (m_current < m_dataStart)
+ {
+ // XXX trying to read from outside of data area
+ NS_ASSERT (false);
+ }
+ else if (m_current < m_zeroStart)
+ {
+ uint8_t data = m_data[m_current];
+ m_current++;
+ return data;
+ }
+ else if (m_current < m_zeroEnd)
+ {
+ m_current++;
+ return 0;
+ }
+ else if (m_current < m_dataEnd)
+ {
+ uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
+ m_current++;
+ return data;
+ }
+ else
+ {
+ // XXX trying to read from outside of data area
+ NS_ASSERT (false);
+ }
+ // to quiet compiler.
+ return 0;
+}
+
+#endif /* BUFFER_USE_INLINE */
+
+} // namespace ns3
#ifdef RUN_SELF_TESTS
@@ -460,6 +990,7 @@
#include "ns3/random-variable.h"
#include <iomanip>
+
namespace ns3 {
class BufferTest: public Test {
@@ -687,6 +1218,13 @@
i.Prev (100);
i.WriteU8 (1, 100);
+#if 0
+ buffer = Buffer (10);
+ ENSURE_WRITTEN_BYTES (buffer, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ buffer.Begin ().WriteU8 (1);
+ ENSURE_WRITTEN_BYTES (buffer, 10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#endif
+
// Bug #54
{
const uint32_t actualSize = 72602;
@@ -718,7 +1256,7 @@
static BufferTest gBufferTest;
-}; // namespace ns3
+} // namespace ns3
#endif /* RUN_SELF_TESTS */
--- a/src/common/buffer.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/buffer.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2005,2006 INRIA
- * All rights reserved.
+ * Copyright (c) 2005,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
@@ -24,6 +23,16 @@
#include <stdint.h>
#include <vector>
+#define BUFFER_HEURISTICS 1
+#define BUFFER_USE_INLINE 1
+
+
+#ifdef BUFFER_USE_INLINE
+#define BUFFER_INLINE inline
+#else
+#define BUFFER_INLINE
+#endif
+
namespace ns3 {
/**
@@ -36,6 +45,51 @@
* by creating new Buffers of the maximum size ever used.
* The correct maximum size is learned at runtime during use by
* recording the maximum size of each packet.
+ *
+ * \internal
+ * The implementation of the Buffer class uses a COW (Copy On Write)
+ * technique to ensure that the underlying data buffer which holds
+ * the data bytes is shared among a lot of Buffer instances despite
+ * data being added or removed from them.
+ *
+ * When multiple Buffer instances hold a reference to the same
+ * underlying BufferData object, they must be able to detect when
+ * the operation they want to perform should trigger a copy of the
+ * BufferData. If the BufferData::m_count field is one, it means that
+ * there exist only one instance of Buffer which references the
+ * BufferData instance so, it is safe to modify it. It is also
+ * safe to modify the content of a BufferData if the modification
+ * falls outside of the "dirty area" defined by the BufferData.
+ * In every other case, the BufferData must be copied before
+ * being modified.
+ *
+ * To understand the way the Buffer::Add and Buffer::Remove methods
+ * work, you first need to understand the "virtual offsets" used to
+ * keep track of the content of buffers. Each Buffer instance
+ * contains real data bytes in its BufferData instance but it also
+ * contains "virtual zero data" which typically is used to represent
+ * application-level payload. No memory is allocated to store the
+ * zero bytes of application-level payload unless the user fragments
+ * a Buffer: this application-level payload is kept track of with
+ * a pair of integers which describe where in the buffer content
+ * the "virtual zero area" starts and ends.
+ *
+ * ***: unused bytes
+ * xxx: bytes "added" at the front of the zero area
+ * ...: bytes "added" at the back of the zero area
+ * 000: virtual zero bytes
+ *
+ * Real byte buffer: |********xxxxxxxxxxxx.........*****|
+ * |--------^ m_start
+ * |-------------------^ m_zeroAreaStart
+ * |-----------------------------^ m_end - (m_zeroAreaEnd - m_zeroAreaStart)
+ * virtual byte buffer: |xxxxxxxxxxxx0000000000000.........|
+ * |--------^ m_start
+ * |--------------------^ m_zeroAreaStart
+ * |---------------------------------^ m_zeroAreaEnd
+ * |------------------------------------------^ m_end
+ *
+ * A simple state invariant is that m_start <= m_zeroStart <= m_zeroEnd <= m_end
*/
class Buffer {
public:
@@ -44,23 +98,23 @@
*/
class Iterator {
public:
- inline Iterator ();
+ Iterator ();
/**
* go forward by one byte
*/
- inline void Next (void);
+ void Next (void);
/**
* go backward by one byte
*/
- inline void Prev (void);
+ void Prev (void);
/**
* \param delta number of bytes to go forward
*/
- inline void Next (uint32_t delta);
+ void Next (uint32_t delta);
/**
* \param delta number of bytes to go backward
*/
- inline void Prev (uint32_t delta);
+ void Prev (uint32_t delta);
/**
* \param o the second iterator
* \return number of bytes included between the two iterators
@@ -69,18 +123,18 @@
* to the same underlying buffer. Debug builds ensure
* this with an assert.
*/
- inline uint32_t GetDistanceFrom (Iterator const &o) const;
+ uint32_t GetDistanceFrom (Iterator const &o) const;
/**
* \return true if this iterator points to the end of the byte array.
* false otherwise.
*/
- inline bool IsEnd (void) const;
+ bool IsEnd (void) const;
/**
* \return true if this iterator points to the start of the byte array.
* false otherwise.
*/
- inline bool IsStart (void) const;
+ bool IsStart (void) const;
/**
* \param data data to write in buffer
@@ -88,7 +142,7 @@
* Write the data in buffer and avance the iterator position
* by one byte.
*/
- inline void WriteU8 (uint8_t data);
+ BUFFER_INLINE void WriteU8 (uint8_t data);
/**
* \param data data to write in buffer
* \param len number of times data must be written in buffer
@@ -96,7 +150,7 @@
* Write the data in buffer len times and avance the iterator position
* by len byte.
*/
- inline void WriteU8 (uint8_t data, uint32_t len);
+ BUFFER_INLINE void WriteU8 (uint8_t data, uint32_t len);
/**
* \param data data to write in buffer
*
@@ -106,7 +160,7 @@
* return exactly what we wrote with writeU16 if the program
* is run on the same machine.
*/
- inline void WriteU16 (uint16_t data);
+ void WriteU16 (uint16_t data);
/**
* \param data data to write in buffer
*
@@ -116,7 +170,7 @@
* return exactly what we wrote with writeU32 if the program
* is run on the same machine.
*/
- inline void WriteU32 (uint32_t data);
+ void WriteU32 (uint32_t data);
/**
* \param data data to write in buffer
*
@@ -126,7 +180,7 @@
* return exactly what we wrote with writeU64 if the program
* is run on the same machine.
*/
- inline void WriteU64 (uint64_t data);
+ void WriteU64 (uint64_t data);
/**
* \param data data to write in buffer
*
@@ -134,7 +188,7 @@
* by two bytes. The data is written in network order and the
* input data is expected to be in host order.
*/
- inline void WriteHtonU16 (uint16_t data);
+ void WriteHtonU16 (uint16_t data);
/**
* \param data data to write in buffer
*
@@ -142,7 +196,7 @@
* by four bytes. The data is written in network order and the
* input data is expected to be in host order.
*/
- inline void WriteHtonU32 (uint32_t data);
+ void WriteHtonU32 (uint32_t data);
/**
* \param data data to write in buffer
*
@@ -150,7 +204,7 @@
* by eight bytes. The data is written in network order and the
* input data is expected to be in host order.
*/
- inline void WriteHtonU64 (uint64_t data);
+ void WriteHtonU64 (uint64_t data);
/**
* \param buffer a byte buffer to copy in the internal buffer.
* \param size number of bytes to copy.
@@ -158,7 +212,7 @@
* Write the data in buffer and avance the iterator position
* by size bytes.
*/
- inline void Write (uint8_t const*buffer, uint32_t size);
+ void Write (uint8_t const*buffer, uint32_t size);
/**
* \param start the start of the data to copy
* \param end the end of the data to copy
@@ -170,7 +224,7 @@
* we do to avoid overlapping copies. This is enforced
* in debug builds by asserts.
*/
- inline void Write (Iterator start, Iterator end);
+ void Write (Iterator start, Iterator end);
/**
* \return the byte read in the buffer.
@@ -178,7 +232,7 @@
* Read data and advance the Iterator by the number of bytes
* read.
*/
- inline uint8_t ReadU8 (void);
+ BUFFER_INLINE uint8_t ReadU8 (void);
/**
* \return the two bytes read in the buffer.
*
@@ -186,7 +240,7 @@
* read.
* The data is read in the format written by writeU16.
*/
- inline uint16_t ReadU16 (void);
+ uint16_t ReadU16 (void);
/**
* \return the four bytes read in the buffer.
*
@@ -194,7 +248,7 @@
* read.
* The data is read in the format written by writeU32.
*/
- inline uint32_t ReadU32 (void);
+ uint32_t ReadU32 (void);
/**
* \return the eight bytes read in the buffer.
*
@@ -202,7 +256,7 @@
* read.
* The data is read in the format written by writeU64.
*/
- inline uint64_t ReadU64 (void);
+ uint64_t ReadU64 (void);
/**
* \return the two bytes read in the buffer.
*
@@ -210,7 +264,7 @@
* read.
* The data is read in network format and return in host format.
*/
- inline uint16_t ReadNtohU16 (void);
+ uint16_t ReadNtohU16 (void);
/**
* \return the four bytes read in the buffer.
*
@@ -218,7 +272,7 @@
* read.
* The data is read in network format and return in host format.
*/
- inline uint32_t ReadNtohU32 (void);
+ uint32_t ReadNtohU32 (void);
/**
* \return the eight bytes read in the buffer.
*
@@ -226,7 +280,7 @@
* read.
* The data is read in network format and return in host format.
*/
- inline uint64_t ReadNtohU64 (void);
+ uint64_t ReadNtohU64 (void);
/**
* \param buffer buffer to copy data into
* \param size number of bytes to copy
@@ -235,22 +289,45 @@
* input buffer and avance the Iterator by the number of
* bytes read.
*/
- inline void Read (uint8_t *buffer, uint16_t size);
+ void Read (uint8_t *buffer, uint32_t size);
private:
friend class Buffer;
- inline Iterator (Buffer const*buffer, uint32_t m_current);
- inline uint32_t GetIndex (uint32_t n);
+ Iterator (Buffer const*buffer);
+ Iterator (Buffer const*buffer, bool);
+ void Construct (const Buffer *buffer);
+ bool CheckNoZero (uint32_t start, uint32_t end) const;
+ bool Check (uint32_t i) const;
+
+ /* offset in virtual bytes from the start of the data buffer to the
+ * start of the "virtual zero area".
+ */
uint32_t m_zeroStart;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * end of the "virtual zero area".
+ */
uint32_t m_zeroEnd;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * start of the data which can be read by this iterator
+ */
+ uint32_t m_dataStart;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * end of the data which can be read by this iterator
+ */
uint32_t m_dataEnd;
+ /* offset in virtual bytes from the start of the data buffer to the
+ * current position represented by this iterator.
+ */
uint32_t m_current;
+ /* a pointer to the underlying byte buffer. All offsets are relative
+ * to this pointer.
+ */
uint8_t *m_data;
};
/**
* \return the number of bytes stored in this buffer.
*/
- inline uint32_t GetSize (void) const;
+ uint32_t GetSize (void) const;
/**
* \return a pointer to the start of the internal
@@ -313,409 +390,135 @@
* \return an Iterator which points to the
* start of this Buffer.
*/
- inline Buffer::Iterator Begin (void) const;
+ Buffer::Iterator Begin (void) const;
/**
* \return an Iterator which points to the
* end of this Buffer.
*/
- inline Buffer::Iterator End (void) const;
+ Buffer::Iterator End (void) const;
Buffer CreateFullCopy (void) const;
- inline Buffer (Buffer const &o);
- inline Buffer &operator = (Buffer const &o);
- inline Buffer ();
- inline Buffer (uint32_t dataSize);
- inline ~Buffer ();
+ Buffer (Buffer const &o);
+ Buffer &operator = (Buffer const &o);
+ Buffer ();
+ Buffer (uint32_t dataSize);
+ ~Buffer ();
private:
- struct BufferData {
- uint32_t m_count;
- uint32_t m_size;
- uint32_t m_initialStart;
- uint32_t m_dirtyStart;
- uint32_t m_dirtySize;
- uint8_t m_data[1];
- };
- class BufferDataList : public std::vector<struct Buffer::BufferData*>
- {
- public:
- ~BufferDataList ();
- };
+
+ void TransformIntoRealBuffer (void) const;
+ bool CheckInternalState (void) const;
+ void Initialize (uint32_t zeroSize);
+ uint32_t GetInternalSize (void) const;
+ uint32_t GetInternalEnd (void) const;
+ static void Recycle (struct BufferData *data);
+ static struct BufferData *Create (uint32_t size);
- 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);
- static void Deallocate (struct Buffer::BufferData *data);
-
- static BufferDataList m_freeList;
- static uint32_t m_maxTotalAddStart;
- static uint32_t m_maxTotalAddEnd;
-
+ /* This structure is described in the buffer.cc file.
+ */
struct BufferData *m_data;
- uint32_t m_zeroAreaSize;
+#ifdef BUFFER_HEURISTICS
+ /* keep track of the maximum value of m_zeroAreaStart across
+ * the lifetime of a Buffer instance. This variable is used
+ * purely as a source of information for the heuristics which
+ * decide on the position of the zero area in new buffers.
+ * It is read from the Buffer destructor to update the global
+ * heuristic data and these global heuristic data are used from
+ * the Buffer constructor to choose an initial value for
+ * m_zeroAreaStart.
+ * It is possible to disable all these heuristics by undefining the
+ * BUFFER_HEURISTICS macro at the top of buffer.h
+ */
+ uint32_t m_maxZeroAreaStart;
+#endif /* BUFFER_HEURISTICS */
+ /* offset to the start of the virtual zero area from the start
+ * of m_data->m_data
+ */
+ uint32_t m_zeroAreaStart;
+ /* offset to the end of the virtual zero area from the start
+ * of m_data->m_data
+ */
+ uint32_t m_zeroAreaEnd;
+ /* offset to the start of the data referenced by this Buffer
+ * instance from the start of m_data->m_data
+ */
uint32_t m_start;
- uint32_t m_size;
+ /* offset to the end of the data referenced by this Buffer
+ * instance from the start of m_data->m_data
+ */
+ uint32_t m_end;
};
-}; // namespace ns3
-
+} // namespace ns3
-/**************************************************
- Start of implementation of methods which
- need to be inline for performance reasons.
- *************************************************/
+#ifdef BUFFER_USE_INLINE
#include "ns3/assert.h"
namespace ns3 {
-Buffer::Buffer ()
- : m_data (Buffer::Create ()),
- m_zeroAreaSize (0),
- m_start (m_maxTotalAddStart),
- m_size (0)
-{
- if (m_start > m_data->m_size)
- {
- m_start = 0;
- }
- NS_ASSERT (m_start <= m_data->m_size);
-}
-
-Buffer::Buffer (uint32_t dataSize)
- : m_data (Buffer::Create ()),
- m_zeroAreaSize (dataSize),
- m_start (m_maxTotalAddStart),
- m_size (0)
-{
- if (m_start > m_data->m_size)
- {
- m_start = 0;
- }
- NS_ASSERT (m_start <= m_data->m_size);
-}
-
-
-Buffer::Buffer (Buffer const&o)
- : m_data (o.m_data),
- m_zeroAreaSize (o.m_zeroAreaSize),
- m_start (o.m_start),
- m_size (o.m_size)
-{
- m_data->m_count++;
- NS_ASSERT (m_start <= m_data->m_size);
-}
-
-Buffer &
-Buffer::operator = (Buffer const&o)
-{
- if (m_data != o.m_data)
- {
- // not assignment to self.
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- Recycle (m_data);
- }
- m_data = o.m_data;
- m_data->m_count++;
- }
- m_zeroAreaSize = o.m_zeroAreaSize;
- m_start = o.m_start;
- m_size = o.m_size;
- NS_ASSERT (m_start <= m_data->m_size);
- return *this;
-}
-
-Buffer::~Buffer ()
-{
- m_data->m_count--;
- if (m_data->m_count == 0)
- {
- Recycle (m_data);
- }
-}
-
-
-uint8_t *
-Buffer::GetStart (void) const
+void
+Buffer::Iterator::WriteU8 (uint8_t data)
{
- return m_data->m_data + m_start;
-}
-
-uint32_t
-Buffer::GetSize (void) const
-{
- return m_size + m_zeroAreaSize;
-}
-
-Buffer::Iterator
-Buffer::Begin (void) const
-{
- return Buffer::Iterator (this, 0);
-}
-Buffer::Iterator
-Buffer::End (void) const
-{
- return Buffer::Iterator (this, GetSize ());
-}
-
+ NS_ASSERT (Check (m_current));
-Buffer::Iterator::Iterator ()
- : m_zeroStart (0),
- m_zeroEnd (0),
- m_dataEnd (0),
- m_current (0),
- m_data (0)
-{}
-Buffer::Iterator::Iterator (Buffer const*buffer, uint32_t current)
- : m_zeroStart (buffer->m_data->m_initialStart-buffer->m_start),
- m_zeroEnd (m_zeroStart+buffer->m_zeroAreaSize),
- m_dataEnd (buffer->GetSize ()),
- m_current (current),
- m_data (buffer->m_data->m_data+buffer->m_start)
-{}
-
-void
-Buffer::Iterator::Next (void)
-{
- NS_ASSERT (m_current + 1 <= m_dataEnd);
- m_current++;
-}
-void
-Buffer::Iterator::Prev (void)
-{
- NS_ASSERT (m_current >= 1);
- m_current--;
-}
-void
-Buffer::Iterator::Next (uint32_t delta)
-{
- NS_ASSERT (m_current + delta <= m_dataEnd);
- m_current += delta;
-}
-void
-Buffer::Iterator::Prev (uint32_t delta)
-{
- NS_ASSERT (m_current >= delta);
- m_current -= delta;
-}
-uint32_t
-Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
-{
- NS_ASSERT (m_data == o.m_data);
- int32_t start = m_current;
- int32_t end = o.m_current;
- int32_t diff = end - start;
- if (diff < 0)
+ if (m_current < m_zeroStart)
{
- return -diff;
+ m_data[m_current] = data;
+ m_current++;
}
else
{
- return diff;
+ m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
+ m_current++;
}
}
-bool
-Buffer::Iterator::IsEnd (void) const
-{
- return m_current == m_dataEnd;
-}
-bool
-Buffer::Iterator::IsStart (void) const
-{
- return m_current == 0;
-}
-
-uint32_t
-Buffer::Iterator::GetIndex (uint32_t n)
-{
- NS_ASSERT (
- (m_current + n <= m_dataEnd) &&
- ((m_current + n <= m_zeroStart) ||
- (m_current >= m_zeroEnd) ||
- m_zeroStart == m_zeroEnd)
- );
- uint32_t index;
- if (m_current < m_zeroStart)
- {
- index = m_current;
- }
- else
- {
- index = m_current - (m_zeroEnd-m_zeroStart);
- }
- return index;
-}
-
-
-void
-Buffer::Iterator::Write (Iterator start, Iterator end)
-{
- NS_ASSERT (start.m_data == end.m_data);
- NS_ASSERT (start.m_current <= end.m_current);
- NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
- NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
- NS_ASSERT (m_data != start.m_data);
- uint32_t size = end.m_current - start.m_current;
- uint8_t *src = start.m_data + start.GetIndex (size);
- uint8_t *dest = m_data + GetIndex (size);
- memcpy (dest, src, size);
- m_current += size;
-}
-
void
Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
{
- uint8_t *current = m_data + GetIndex (len);
- memset (current, data, len);
- m_current += len;
-}
-void
-Buffer::Iterator::WriteU8 (uint8_t data)
-{
- m_data[GetIndex (1)] = data;
- m_current++;
-}
-void
-Buffer::Iterator::WriteU16 (uint16_t data)
-{
- uint16_t *buffer = (uint16_t *)(m_data + GetIndex (2));
- *buffer = data;
- m_current += 2;
-}
-void
-Buffer::Iterator::WriteU32 (uint32_t data)
-{
- uint32_t *buffer = (uint32_t *)(m_data + GetIndex (4));
- *buffer = data;
- m_current += 4;
-}
-void
-Buffer::Iterator::WriteU64 (uint64_t data)
-{
- uint64_t *buffer = (uint64_t *)(m_data + GetIndex (8));
- *buffer = data;
- m_current += 8;
-}
-void
-Buffer::Iterator::WriteHtonU16 (uint16_t data)
-{
- uint8_t *current = m_data + GetIndex (2);
- *(current+0) = (data >> 8) & 0xff;
- *(current+1) = (data >> 0) & 0xff;
- m_current += 2;
-}
-void
-Buffer::Iterator::WriteHtonU32 (uint32_t data)
-{
- uint8_t *current = m_data + GetIndex (4);
- *(current+0) = (data >> 24) & 0xff;
- *(current+1) = (data >> 16) & 0xff;
- *(current+2) = (data >> 8) & 0xff;
- *(current+3) = (data >> 0) & 0xff;
- m_current += 4;
-}
-void
-Buffer::Iterator::WriteHtonU64 (uint64_t data)
-{
- uint8_t *current = m_data + GetIndex (8);
- *(current+0) = (data >> 56) & 0xff;
- *(current+1) = (data >> 48) & 0xff;
- *(current+2) = (data >> 40) & 0xff;
- *(current+3) = (data >> 32) & 0xff;
- *(current+4) = (data >> 24) & 0xff;
- *(current+5) = (data >> 16) & 0xff;
- *(current+6) = (data >> 8) & 0xff;
- *(current+7) = (data >> 0) & 0xff;
- m_current += 8;
-}
-void
-Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
-{
- uint8_t *current = m_data + GetIndex (size);
- memcpy (current, buffer, size);
- m_current += size;
+ NS_ASSERT (CheckNoZero (m_current, m_current + len));
+ if (m_current <= m_zeroStart)
+ {
+ memset (&(m_data[m_current]), data, len);
+ m_current += len;
+ }
+ else
+ {
+ uint8_t *buffer = &m_data[m_current - (m_zeroEnd-m_zeroStart)];
+ memset (buffer, data, len);
+ m_current += len;
+ }
}
uint8_t
Buffer::Iterator::ReadU8 (void)
{
- uint8_t data = m_data[GetIndex(1)];
- m_current++;
- return data;
-}
-uint16_t
-Buffer::Iterator::ReadU16 (void)
-{
- uint16_t *buffer = reinterpret_cast<uint16_t *>(m_data + GetIndex (2));
- m_current += 2;
- return *buffer;
-}
-uint32_t
-Buffer::Iterator::ReadU32 (void)
-{
- uint32_t *buffer = reinterpret_cast<uint32_t *>(m_data + GetIndex (4));
- m_current += 4;
- return *buffer;
-}
-uint64_t
-Buffer::Iterator::ReadU64 (void)
-{
- uint64_t *buffer = reinterpret_cast<uint64_t *>(m_data + GetIndex (8));
- m_current += 8;
- return *buffer;
-}
-uint16_t
-Buffer::Iterator::ReadNtohU16 (void)
-{
- uint8_t *current = m_data + GetIndex (2);
- uint16_t retval = 0;
- retval |= static_cast<uint16_t> (current[0]) << 8;
- retval |= static_cast<uint16_t> (current[1]) << 0;
- m_current += 2;
- return retval;
-}
-uint32_t
-Buffer::Iterator::ReadNtohU32 (void)
-{
- uint8_t *current = m_data + GetIndex (4);
- uint32_t retval = 0;
- retval |= static_cast<uint32_t> (current[0]) << 24;
- retval |= static_cast<uint32_t> (current[1]) << 16;
- retval |= static_cast<uint32_t> (current[2]) << 8;
- retval |= static_cast<uint32_t> (current[3]) << 0;
- m_current += 4;
- return retval;
-}
-uint64_t
-Buffer::Iterator::ReadNtohU64 (void)
-{
- uint8_t *current = m_data + GetIndex (8);
- uint64_t retval = 0;
- retval |= static_cast<uint64_t> (current[0]) << 56;
- retval |= static_cast<uint64_t> (current[1]) << 48;
- retval |= static_cast<uint64_t> (current[2]) << 40;
- retval |= static_cast<uint64_t> (current[3]) << 32;
- retval |= static_cast<uint64_t> (current[4]) << 24;
- retval |= static_cast<uint64_t> (current[5]) << 16;
- retval |= static_cast<uint64_t> (current[6]) << 8;
- retval |= static_cast<uint64_t> (current[7]) << 0;
- m_current += 8;
- return retval;
-}
-void
-Buffer::Iterator::Read (uint8_t *buffer, uint16_t size)
-{
- uint8_t *current = m_data + GetIndex (size);
- memcpy (buffer, current, size);
- m_current += size;
+ NS_ASSERT (m_current >= m_dataStart &&
+ m_current <= m_dataEnd);
+
+ if (m_current < m_zeroStart)
+ {
+ uint8_t data = m_data[m_current];
+ m_current++;
+ return data;
+ }
+ else if (m_current < m_zeroEnd)
+ {
+ m_current++;
+ return 0;
+ }
+ else
+ {
+ uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
+ m_current++;
+ return data;
+ }
}
-}; // namespace ns3
+} // namespace ns3
+
+#endif /* BUFFER_USE_INLINE */
#endif /* BUFFER_H */
--- a/src/common/packet-metadata-test.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/packet-metadata-test.cc Wed Sep 12 18:06:09 2007 +0100
@@ -673,6 +673,13 @@
p = DoAddHeader (p);
CHECK_HISTORY (p, 2, 10, 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);
+
return ok;
}
--- a/src/common/packet.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/common/packet.cc Wed Sep 12 18:06:09 2007 +0100
@@ -249,7 +249,7 @@
packet.GetSize ());
if (msg != "hello world")
{
- Failure () << "expected size 'hello world', got " << msg << std::endl;
+ Failure () << "expected 'hello world', got '" << msg << "'" << std::endl;
ok = false;
}
--- a/src/devices/csma/csma-channel.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-channel.cc Wed Sep 12 18:06:09 2007 +0100
@@ -250,7 +250,7 @@
}
NS_DEBUG ("CsmaChannel::TransmitEnd (): Schedule event in " <<
- m_delay.GetSeconds () << "sec");
+ m_delay.GetSeconds () << " sec");
Simulator::Schedule (m_delay,
&CsmaChannel::PropagationCompleteEvent,
--- a/src/devices/csma/csma-ipv4-topology.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-ipv4-topology.cc Wed Sep 12 18:06:09 2007 +0100
@@ -35,82 +35,79 @@
namespace ns3 {
uint32_t
-CsmaIpv4Topology::AddIpv4CsmaNode(Ptr<Node> n1,
- Ptr<CsmaChannel> ch,
- Eui48Address addr)
+CsmaIpv4Topology::AddIpv4CsmaNetDevice(
+ Ptr<Node> node,
+ Ptr<CsmaChannel> channel,
+ Eui48Address addr)
{
Ptr<Queue> q = Queue::CreateDefault ();
// assume full-duplex
- Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
- ns3::CsmaNetDevice::IP_ARP,
- true, true);
- nd0->AddQueue(q);
- nd0->Attach (ch);
- return nd0->GetIfIndex ();
+ Ptr<CsmaNetDevice> nd = Create<CsmaNetDevice> (node, addr,
+ ns3::CsmaNetDevice::IP_ARP, true, true);
+
+ nd->AddQueue(q);
+ nd->Attach (channel);
+ return nd->GetIfIndex ();
}
void
CsmaIpv4Topology::AddIpv4LlcCsmaNode(Ptr<Node> n1,
- Ptr<CsmaChannel> ch,
- Eui48Address addr)
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr)
{
Ptr<Queue> q = Queue::CreateDefault ();
Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
- ns3::CsmaNetDevice::LLC,
- true, false);
+ ns3::CsmaNetDevice::LLC,
+ true, false);
nd0->AddQueue(q);
nd0->Attach (ch);
Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
- ns3::CsmaNetDevice::LLC,
- false, true);
+ ns3::CsmaNetDevice::LLC,
+ false, true);
nd1->AddQueue(q);
nd1->Attach (ch);
}
void
CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr<Node> n1,
- Ptr<CsmaChannel> ch,
- Eui48Address addr)
+ Ptr<CsmaChannel> ch,
+ Eui48Address addr)
{
Ptr<Queue> q = Queue::CreateDefault ();
Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
- ns3::CsmaNetDevice::RAW,
- true, false);
+ ns3::CsmaNetDevice::RAW,
+ true, false);
nd0->AddQueue(q);
nd0->Attach (ch);
Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
- ns3::CsmaNetDevice::RAW,
- false, true);
+ ns3::CsmaNetDevice::RAW,
+ false, true);
nd1->AddQueue(q);
nd1->Attach (ch);
}
-void
-CsmaIpv4Topology::AddIpv4Address(Ptr<Node> n1,
- int ndNum,
- const Ipv4Address& addr1,
- const Ipv4Mask& netmask1)
+uint32_t
+CsmaIpv4Topology::AddIpv4Address(
+ Ptr<Node> node,
+ uint32_t netDeviceNumber,
+ const Ipv4Address address,
+ const Ipv4Mask mask)
{
+ Ptr<NetDevice> nd = node->GetDevice(netDeviceNumber);
- // Duplex link is assumed to be subnetted as a /30
- // May run this unnumbered in the future?
- Ipv4Mask netmask(netmask1);
-
- Ptr<NetDevice> nd1 = n1->GetDevice(ndNum);
+ Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+ uint32_t ifIndex = ipv4->AddInterface (nd);
- Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
- uint32_t index1 = ip1->AddInterface (nd1);
-
- ip1->SetAddress (index1, addr1);
- ip1->SetNetworkMask (index1, netmask);
- ip1->SetUp (index1);
-
+ ipv4->SetAddress (ifIndex, address);
+ ipv4->SetNetworkMask (ifIndex, mask);
+ ipv4->SetUp (ifIndex);
+ return ifIndex;
}
void
@@ -133,7 +130,7 @@
found = true;
}
}
- NS_ASSERT(found);
+ NS_ASSERT (found);
uint32_t index2 = 0;
found = false;
@@ -145,7 +142,7 @@
found = true;
}
}
- NS_ASSERT(found);
+ NS_ASSERT (found);
ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2);
--- a/src/devices/csma/csma-ipv4-topology.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-ipv4-topology.h Wed Sep 12 18:06:09 2007 +0100
@@ -61,9 +61,9 @@
*
* \return ifIndex of the device
*/
- static uint32_t AddIpv4CsmaNode( Ptr<Node> n1,
- Ptr<CsmaChannel> ch,
- Eui48Address addr);
+ static uint32_t AddIpv4CsmaNetDevice(Ptr<Node> node,
+ Ptr<CsmaChannel> channel,
+ Eui48Address addr);
/**
* \param n1 Node to be attached to the Csma channel
@@ -94,18 +94,23 @@
/**
- * \param n1 Node
- * \param ndNum NetDevice number with which to associate address
- * \param addr1 Ipv4 Address for ndNum of n1
- * \param netmask1 network mask for ndNum of node n1
+ * \brief Create an Ipv4 interface for a net device and assign an
+ * Ipv4Address to that interface.
+ *
+ * \param node The node to which to add the new address and corresponding
+ * interface.
+ * \param netDeviceNumber The NetDevice index number with which to associate
+ * the address.
+ * \param address The Ipv4 Address for the interface.
+ * \param network The network mask for the interface
*
* Add an Ipv4Address to the Ipv4 interface associated with the
- * ndNum CsmaIpv4NetDevices on the provided
- * CsmaIpv4Channel
+ * ndNum CsmaIpv4NetDevices on the provided CsmaIpv4Channel
*/
- static void AddIpv4Address(Ptr<Node> n1, int ndNum,
- const Ipv4Address& addr1,
- const Ipv4Mask& netmask1);
+ static uint32_t AddIpv4Address(Ptr<Node> node,
+ uint32_t netDeviceNumber,
+ const Ipv4Address address,
+ const Ipv4Mask mask);
/**
* \param nd1 Node
--- a/src/devices/csma/csma-net-device.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-net-device.cc Wed Sep 12 18:06:09 2007 +0100
@@ -19,8 +19,6 @@
* Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
*/
-#include <iostream>
-#include <cassert>
#include "ns3/debug.h"
#include "ns3/queue.h"
#include "ns3/simulator.h"
@@ -70,7 +68,6 @@
return m_type;
}
-
CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
: NetDevice (node, Eui48Address::Allocate ()),
m_bps (DataRate (0xffffffff))
@@ -81,7 +78,7 @@
}
CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr,
- CsmaEncapsulationMode encapMode)
+ CsmaEncapsulationMode encapMode)
: NetDevice(node, addr),
m_bps (DataRate (0xffffffff))
{
@@ -92,8 +89,8 @@
}
CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr,
- CsmaEncapsulationMode encapMode,
- bool sendEnable, bool receiveEnable)
+ CsmaEncapsulationMode encapMode,
+ bool sendEnable, bool receiveEnable)
: NetDevice(node, addr),
m_bps (DataRate (0xffffffff))
{
@@ -142,7 +139,7 @@
m_queue = 0;
EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
- EnableMulticast();
+ EnableMulticast (Eui48Address ("01:00:5e:00:00:00"));
SetSendEnable (sendEnable);
SetReceiveEnable (receiveEnable);
@@ -513,10 +510,11 @@
EthernetHeader header (false);
EthernetTrailer trailer;
Eui48Address broadcast;
+ Eui48Address multicast;
Eui48Address destination;
Packet p = packet;
- NS_DEBUG ("CsmaNetDevice::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())
@@ -535,12 +533,34 @@
trailer.CheckFcs(p);
p.RemoveHeader(header);
+ NS_DEBUG ("CsmaNetDevice::Receive (): Pkt destination is " <<
+ header.GetDestination ());
+//
+// An IP host group address is mapped to an Ethernet multicast address
+// by placing the low-order 23-bits of the IP address into the low-order
+// 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
+//
+// We are going to receive all packets destined to any multicast address,
+// which means clearing the low-order 23 bits the header destination
+//
+ Eui48Address mcDest;
+ uint8_t mcBuf[6];
+
+ header.GetDestination ().CopyTo (mcBuf);
+ mcBuf[3] &= 0x80;
+ mcBuf[4] = 0;
+ mcBuf[5] = 0;
+ mcDest.CopyFrom (mcBuf);
+
+ multicast = Eui48Address::ConvertFrom (GetMulticast ());
broadcast = Eui48Address::ConvertFrom (GetBroadcast ());
destination = Eui48Address::ConvertFrom (GetAddress ());
- if ((header.GetDestination() != broadcast) &&
- (header.GetDestination() != destination))
+
+ if ((header.GetDestination () != broadcast) &&
+ (mcDest != multicast) &&
+ (header.GetDestination () != destination))
{
- // not for us.
+ NS_DEBUG ("CsmaNetDevice::Receive (): Dropping pkt ");
m_dropTrace (p);
return;
}
@@ -572,6 +592,61 @@
return;
}
+Address
+CsmaNetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+ NS_DEBUG ("CsmaNetDevice::MakeMulticastAddress (" << multicastGroup <<
+ ")");
+//
+// First, get the generic multicast address.
+//
+ Address hardwareDestination = GetMulticast ();
+
+ NS_DEBUG ("CsmaNetDevice::MakeMulticastAddress (): "
+ "Device multicast address: " << hardwareDestination);
+//
+// It's our address, and we know we're playing with an EUI-48 address here
+// primarily since we know that by construction, but also since the parameter
+// is an Ipv4Address.
+//
+ Eui48Address etherAddr = Eui48Address::ConvertFrom (hardwareDestination);
+//
+// We now have the multicast address in an abstract 48-bit container. We
+// need to pull it out so we can play with it. When we're done, we have the
+// high order bits in etherBuffer[0], etc.
+//
+ uint8_t etherBuffer[6];
+ etherAddr.CopyTo (etherBuffer);
+//
+// Now we need to pull the raw bits out of the Ipv4 destination address.
+//
+ uint8_t ipBuffer[4];
+ multicastGroup.Serialize (ipBuffer);
+//
+// RFC 1112 says that an Ipv4 host group address is mapped to an EUI-48
+// multicast address by placing the low-order 23-bits of the IP address into
+// the low-order 23 bits of the Ethernet multicast address
+// 01-00-5E-00-00-00 (hex).
+//
+ etherBuffer[3] |= ipBuffer[1] & 0x7f;
+ etherBuffer[4] = ipBuffer[2];
+ etherBuffer[5] = ipBuffer[3];
+//
+// Now, etherBuffer has the desired ethernet multicast address. We have to
+// suck these bits back into the Eui48Address,
+//
+ etherAddr.CopyFrom (etherBuffer);
+//
+// Implicit conversion (operator Address ()) is defined for Eui48Address, so
+// use it by just returning the EUI-48 address which is automagically converted
+// to an Address.
+//
+ NS_DEBUG ("CsmaNetDevice::MakeMulticastAddress (): "
+ "multicast address is " << etherAddr);
+
+ return etherAddr;
+}
+
Ptr<Queue>
CsmaNetDevice::GetQueue(void) const
{
--- a/src/devices/csma/csma-net-device.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/csma/csma-net-device.h Wed Sep 12 18:06:09 2007 +0100
@@ -205,6 +205,37 @@
*/
void Receive (const Packet& p);
+ /**
+ * @brief Make and return a MAC multicast address using the provided
+ * multicast group
+ *
+ * RFC 1112 says that an Ipv4 host group address is mapped to an Ethernet
+ * multicast address by placing the low-order 23-bits of the IP address into
+ * the low-order 23 bits of the Ethernet multicast address
+ * 01-00-5E-00-00-00 (hex).
+ *
+ * This method performs the multicast address creation function appropriate
+ * to an EUI-48-based CSMA device. This MAC address is encapsulated in an
+ * abstract Address to avoid dependencies on the exact address format.
+ *
+ * A default imlementation of MakeMulticastAddress is provided, but this
+ * method simply NS_ASSERTS. In the case of net devices that do not support
+ * multicast, clients are expected to test NetDevice::IsMulticast and avoid
+ * attempting to map multicast packets. Subclasses of NetDevice that do
+ * support multicasting are expected to override this method and provide an
+ * implementation appropriate to the particular device.
+ *
+ * @param multicastGroup The IP address for the multicast group destination
+ * of the packet.
+ * @return The MAC multicast Address used to send packets to the provided
+ * multicast group.
+ *
+ * @see Ipv4Address
+ * @see Eui48Address
+ * @see Address
+ */
+ Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
bool IsSendEnabled (void);
bool IsReceiveEnabled (void);
--- a/src/devices/point-to-point/point-to-point-net-device.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc Wed Sep 12 18:06:09 2007 +0100
@@ -20,8 +20,6 @@
* Revised: George Riley <riley@ece.gatech.edu>
*/
-#include <iostream>
-#include <cassert>
#include "ns3/debug.h"
#include "ns3/queue.h"
#include "ns3/simulator.h"
@@ -73,11 +71,14 @@
{
NS_DEBUG ("PointToPointNetDevice::PointToPointNetDevice (" << node << ")");
- // BUGBUG FIXME
- //
- // You _must_ support broadcast to get any sort of packet from the ARP layer.
+// BUGBUG FIXME
+//
+// You _must_ support broadcast to get any sort of packet from the ARP layer.
EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
- EnableMulticast();
+//
+// We want to allow multicast packets to flow across this link
+//
+ EnableMulticast (Eui48Address ("01:00:5e:00:00:00"));
EnablePointToPoint();
}
@@ -218,6 +219,8 @@
m_bps = m_channel->GetDataRate ();
// GFR Comment. Below is definitely wrong. Interframe gap
// is unrelated to channel delay.
+ // -- unlesss you want to introduce a default gap which is there to avoid
+ // parts of multiple packets flowing on the "wire" at the same time.
//m_tInterframeGap = m_channel->GetDelay ();
/*
--- a/src/internet-node/arp-ipv4-interface.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.cc Wed Sep 12 18:06:09 2007 +0100
@@ -31,18 +31,26 @@
#include "ipv4-l3-protocol.h"
#include "arp-l3-protocol.h"
+NS_DEBUG_COMPONENT_DEFINE ("ArpIpv4Interface");
+
namespace ns3 {
ArpIpv4Interface::ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device)
: Ipv4Interface (device),
m_node (node)
-{}
+{
+ NS_DEBUG ("ArpIpv4Interface::ArpIpv4Interface ()");
+}
+
ArpIpv4Interface::~ArpIpv4Interface ()
-{}
+{
+ NS_DEBUG ("ArpIpv4Interface::~ArpIpv4Interface ()");
+}
Ptr<TraceResolver>
ArpIpv4Interface::GetTraceResolver (void) const
{
+ NS_DEBUG ("ArpIpv4Interface::DoCreateTraceResolver ()");
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
if (GetDevice () != 0)
{
@@ -55,32 +63,52 @@
void
ArpIpv4Interface::SendTo (Packet p, Ipv4Address dest)
{
+ NS_DEBUG ("ArpIpv4Interface::SendTo (" << &p << ", " << dest << ")");
+
NS_ASSERT (GetDevice () != 0);
if (GetDevice ()->NeedsArp ())
{
- Ptr<ArpL3Protocol> arp = m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
+ NS_DEBUG ("ArpIpv4Interface::SendTo (): Needs ARP");
+ Ptr<ArpL3Protocol> arp =
+ m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
Address hardwareDestination;
bool found;
if (dest.IsBroadcast () ||
dest.IsSubnetDirectedBroadcast (GetNetworkMask ()) )
{
+ NS_DEBUG ("ArpIpv4Interface::SendTo (): IsBroadcast");
hardwareDestination = GetDevice ()->GetBroadcast ();
found = true;
}
+ else if (dest.IsMulticast ())
+ {
+ NS_DEBUG ("ArpIpv4Interface::SendTo (): IsMulticast");
+ NS_ASSERT_MSG(GetDevice ()->IsMulticast (),
+ "ArpIpv4Interface::SendTo (): Sending multicast packet over "
+ "non-multicast device");
+
+ hardwareDestination = GetDevice ()->MakeMulticastAddress(dest);
+ found = true;
+ }
else
{
+ NS_DEBUG ("ArpIpv4Interface::SendTo (): ARP Lookup");
found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
}
if (found)
{
- GetDevice ()->Send (p, hardwareDestination, Ipv4L3Protocol::PROT_NUMBER);
+ NS_DEBUG ("ArpIpv4Interface::SendTo (): Address Resolved. Send.");
+ GetDevice ()->Send (p, hardwareDestination,
+ Ipv4L3Protocol::PROT_NUMBER);
}
}
else
{
- GetDevice ()->Send (p, GetDevice ()->GetBroadcast (), Ipv4L3Protocol::PROT_NUMBER);
+ NS_DEBUG ("ArpIpv4Interface::SendTo (): Doesn't need ARP");
+ GetDevice ()->Send (p, GetDevice ()->GetBroadcast (),
+ Ipv4L3Protocol::PROT_NUMBER);
}
}
--- a/src/internet-node/arp-ipv4-interface.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.h Wed Sep 12 18:06:09 2007 +0100
@@ -24,6 +24,7 @@
#include "ipv4-interface.h"
#include "ns3/ptr.h"
+#include "ns3/eui48-address.h"
namespace ns3 {
--- a/src/internet-node/ipv4-impl.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-impl.cc Wed Sep 12 18:06:09 2007 +0100
@@ -95,16 +95,72 @@
{
return m_ipv4->RemoveRoute (i);
}
+
+void
+Ipv4Impl::AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ m_ipv4->AddMulticastRoute (origin, group, inputInterface, outputInterfaces);
+}
+
+void
+Ipv4Impl::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+ m_ipv4->SetDefaultMulticastRoute (outputInterface);
+}
+
+uint32_t
+Ipv4Impl::GetNMulticastRoutes (void) const
+{
+ return m_ipv4->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute
+Ipv4Impl::GetMulticastRoute (uint32_t i) const
+{
+ return *m_ipv4->GetMulticastRoute (i);
+}
+
+void
+Ipv4Impl::RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+{
+ m_ipv4->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void
+Ipv4Impl::RemoveMulticastRoute (uint32_t i)
+{
+ return m_ipv4->RemoveMulticastRoute (i);
+}
+
uint32_t
Ipv4Impl::AddInterface (Ptr<NetDevice> device)
{
return m_ipv4->AddInterface (device);
}
+
uint32_t
Ipv4Impl::GetNInterfaces (void)
{
return m_ipv4->GetNInterfaces ();
}
+
+uint32_t
+Ipv4Impl::FindInterfaceForAddr (Ipv4Address addr) const
+{
+ return m_ipv4->FindInterfaceForAddr (addr);
+}
+
+uint32_t
+Ipv4Impl::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+{
+ return m_ipv4->FindInterfaceForAddr (addr, mask);
+}
+
Ptr<NetDevice>
Ipv4Impl::GetNetDevice (uint32_t i)
{
@@ -112,6 +168,18 @@
}
void
+Ipv4Impl::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ m_ipv4->JoinMulticastGroup(origin, group);
+}
+
+void
+Ipv4Impl::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ m_ipv4->LeaveMulticastGroup(origin, group);
+}
+
+void
Ipv4Impl::SetAddress (uint32_t i, Ipv4Address address)
{
m_ipv4->SetAddress (i, address);
@@ -126,11 +194,39 @@
{
return m_ipv4->GetNetworkMask (i);
}
+
Ipv4Address
Ipv4Impl::GetAddress (uint32_t i) const
{
return m_ipv4->GetAddress (i);
}
+
+bool
+Ipv4Impl::GetIfIndexForDestination (Ipv4Address dest, uint32_t &ifIndex) const
+{
+ return m_ipv4->GetIfIndexForDestination (dest, ifIndex);
+}
+
+Ipv4Address
+Ipv4Impl::GetSourceAddress (Ipv4Address destination) const
+{
+ uint32_t ifIndex = 0xffffffff;
+
+ bool result = m_ipv4->GetIfIndexForDestination (destination, ifIndex);
+
+ if (result)
+ {
+ return m_ipv4->GetAddress (ifIndex);
+ }
+ else
+ {
+//
+// If we can't find any address, just leave it 0.0.0.0
+//
+ return Ipv4Address::GetAny ();
+ }
+}
+
uint16_t
Ipv4Impl::GetMtu (uint32_t i) const
{
--- a/src/internet-node/ipv4-impl.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-impl.h Wed Sep 12 18:06:09 2007 +0100
@@ -55,14 +55,43 @@
virtual uint32_t GetNRoutes (void);
virtual Ipv4Route GetRoute (uint32_t i);
virtual void RemoveRoute (uint32_t i);
+
+
+ virtual void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+ virtual void SetDefaultMulticastRoute (uint32_t outputInterface);
+
+ virtual uint32_t GetNMulticastRoutes (void) const;
+ virtual Ipv4MulticastRoute GetMulticastRoute (uint32_t i) const;
+
+ virtual void RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface);
+ virtual void RemoveMulticastRoute (uint32_t i);
+
virtual uint32_t AddInterface (Ptr<NetDevice> device);
virtual uint32_t GetNInterfaces (void);
+
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr) const;
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr,
+ Ipv4Mask mask) const;
+
virtual Ptr<NetDevice> GetNetDevice(uint32_t i);
+ virtual void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+ virtual void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
virtual void SetAddress (uint32_t i, Ipv4Address address);
virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask);
virtual Ipv4Mask GetNetworkMask (uint32_t t) const;
virtual Ipv4Address GetAddress (uint32_t i) const;
+ virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const;
+ virtual bool GetIfIndexForDestination (Ipv4Address dest,
+ uint32_t &ifIndex) const;
+
virtual uint16_t GetMtu (uint32_t i) const;
virtual bool IsUp (uint32_t i) const;
virtual void SetUp (uint32_t i);
--- a/src/internet-node/ipv4-interface.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-interface.cc Wed Sep 12 18:06:09 2007 +0100
@@ -23,6 +23,9 @@
#include "ns3/ipv4-address.h"
#include "ns3/net-device.h"
#include "ns3/trace-resolver.h"
+#include "ns3/debug.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("Ipv4Interface");
namespace ns3 {
@@ -35,10 +38,14 @@
Ipv4Interface::Ipv4Interface (Ptr<NetDevice> nd)
: m_netdevice (nd),
m_ifup(false)
-{}
+{
+ NS_DEBUG ("Ipv4Interface::Ipv4Interface (" << &nd << ")");
+}
Ipv4Interface::~Ipv4Interface ()
-{}
+{
+ NS_DEBUG ("Ipv4Interface::~Ipv4Interface ()");
+}
void
Ipv4Interface::DoDispose (void)
@@ -50,42 +57,53 @@
Ptr<NetDevice>
Ipv4Interface::GetDevice (void) const
{
+ NS_DEBUG ("Ipv4Interface::GetDevice ()");
return m_netdevice;
}
void
Ipv4Interface::SetAddress (Ipv4Address a)
{
+ NS_DEBUG ("Ipv4Interface::SetAddress (" << a << ")");
m_address = a;
}
+
void
Ipv4Interface::SetNetworkMask (Ipv4Mask mask)
{
+ NS_DEBUG ("Ipv4Interface::SetMask (" << mask << ")");
m_netmask = mask;
}
Ipv4Address
Ipv4Interface::GetBroadcast (void) const
{
+ NS_DEBUG ("Ipv4Interface::GetBroadcast ()");
+
uint32_t mask = m_netmask.GetHostOrder ();
uint32_t address = m_address.GetHostOrder ();
Ipv4Address broadcast = Ipv4Address (address | (~mask));
return broadcast;
}
+
Ipv4Mask
Ipv4Interface::GetNetworkMask (void) const
{
+ NS_DEBUG ("Ipv4Interface::GetNetworkMask ()");
return m_netmask;
}
+
Ipv4Address
Ipv4Interface::GetAddress (void) const
{
+ NS_DEBUG ("Ipv4Interface::Address ()");
return m_address;
}
uint16_t
Ipv4Interface::GetMtu (void) const
{
+ NS_DEBUG ("Ipv4Interface::GetMtu ()");
if (m_netdevice == 0)
{
uint32_t mtu = (1<<16) - 1;
@@ -94,32 +112,36 @@
return m_netdevice->GetMtu ();
}
- /**
- * These are IP interface states and may be distinct from
- * NetDevice states, such as found in real implementations
- * (where the device may be down but IP interface state is still up).
- */
+/**
+ * These are IP interface states and may be distinct from
+ * NetDevice states, such as found in real implementations
+ * (where the device may be down but IP interface state is still up).
+ */
bool
Ipv4Interface::IsUp (void) const
{
+ NS_DEBUG ("Ipv4Interface::IsUp ()");
return m_ifup;
}
bool
Ipv4Interface::IsDown (void) const
{
+ NS_DEBUG ("Ipv4Interface::IsDown ()");
return !m_ifup;
}
void
Ipv4Interface::SetUp (void)
{
+ NS_DEBUG ("Ipv4Interface::SetUp ()");
m_ifup = true;
}
void
Ipv4Interface::SetDown (void)
{
+ NS_DEBUG ("Ipv4Interface::SetDown ()");
m_ifup = false;
}
@@ -127,7 +149,10 @@
void
Ipv4Interface::Send(Packet p, Ipv4Address dest)
{
+ NS_DEBUG ("Ipv4Interface::Send ()");
+
if (IsUp()) {
+ NS_DEBUG ("Ipv4Interface::Send (): SendTo ()");
SendTo(p, dest);
}
}
--- a/src/internet-node/ipv4-l3-protocol.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.cc Wed Sep 12 18:06:09 2007 +0100
@@ -129,17 +129,24 @@
m_identification (0),
m_node (node)
{
+ NS_DEBUG("Ipv4L3Protocol::Ipv4L3Protocol ()");
+
SetInterfaceId (Ipv4L3Protocol::iid);
m_staticRouting = Create<Ipv4StaticRouting> ();
AddRoutingProtocol (m_staticRouting, 0);
SetupLoopback ();
}
+
Ipv4L3Protocol::~Ipv4L3Protocol ()
-{}
+{
+ NS_DEBUG("Ipv4L3Protocol::~Ipv4L3Protocol ()");
+}
void
Ipv4L3Protocol::DoDispose (void)
{
+ NS_DEBUG("Ipv4L3Protocol::DoDispose ()");
+
m_interfaces.clear ();
m_node = 0;
m_staticRouting->Dispose ();
@@ -150,6 +157,8 @@
void
Ipv4L3Protocol::SetupLoopback (void)
{
+ NS_DEBUG("Ipv4L3Protocol::SetupLoopback ()");
+
Ptr<Ipv4LoopbackInterface> interface = Create<Ipv4LoopbackInterface> (m_node);
interface->SetAddress (Ipv4Address::GetLoopback ());
interface->SetNetworkMask (Ipv4Mask::GetLoopback ());
@@ -161,6 +170,8 @@
Ptr<TraceResolver>
Ipv4L3Protocol::GetTraceResolver (void) const
{
+ NS_DEBUG("Ipv4L3Protocol::GetTraceResolver ()");
+
Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
resolver->AddSource ("tx",
TraceDoc ("send ipv4 packet to outgoing interface",
@@ -185,6 +196,7 @@
void
Ipv4L3Protocol::SetDefaultTtl (uint8_t ttl)
{
+ NS_DEBUG("Ipv4L3Protocol::SetDefaultTtl ()");
m_defaultTtl = ttl;
}
@@ -194,20 +206,28 @@
Ipv4Address nextHop,
uint32_t interface)
{
+ NS_DEBUG("Ipv4L3Protocol::AddHostRouteTo (" << dest << ", " << nextHop <<
+ ", " << interface << ")");
m_staticRouting->AddHostRouteTo (dest, nextHop, interface);
}
+
void
Ipv4L3Protocol::AddHostRouteTo (Ipv4Address dest,
uint32_t interface)
{
+ NS_DEBUG("Ipv4L3Protocol::AddHostRouteTo (" << dest << ", " <<
+ interface << ")");
m_staticRouting->AddHostRouteTo (dest, interface);
}
+
void
Ipv4L3Protocol::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
Ipv4Address nextHop,
uint32_t interface)
{
+ NS_DEBUG("Ipv4L3Protocol::AddNetworkRouteTo (" << network << ", " <<
+ networkMask << ", " << nextHop << ", " << interface << ")");
m_staticRouting->AddNetworkRouteTo (network, networkMask, nextHop, interface);
}
void
@@ -215,28 +235,81 @@
Ipv4Mask networkMask,
uint32_t interface)
{
+ NS_DEBUG("Ipv4L3Protocol::AddNetworkRouteTo (" << network << ", " <<
+ networkMask << ", " << interface << ")");
m_staticRouting->AddNetworkRouteTo (network, networkMask, interface);
}
void
Ipv4L3Protocol::SetDefaultRoute (Ipv4Address nextHop,
uint32_t interface)
{
+ NS_DEBUG("Ipv4L3Protocol::SetDefaultRoute (" << nextHop << ", " <<
+ interface << ")");
m_staticRouting->SetDefaultRoute (nextHop, interface);
}
+void
+Ipv4L3Protocol::Lookup (
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+{
+ NS_DEBUG("Ipv4L3Protocol::Lookup (" << &ipHeader <<
+ ", " << &packet << &routeReply << ")");
+
+ Lookup (Ipv4RoutingProtocol::IF_INDEX_ANY, ipHeader, packet, routeReply);
+}
void
-Ipv4L3Protocol::Lookup (Ipv4Header const &ipHeader,
- Packet packet,
- Ipv4RoutingProtocol::RouteReplyCallback routeReply)
+Ipv4L3Protocol::Lookup (
+ uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply)
{
- for (Ipv4RoutingProtocolList::const_iterator rprotoIter = m_routingProtocols.begin ();
- rprotoIter != m_routingProtocols.end (); rprotoIter++)
+ NS_DEBUG("Ipv4L3Protocol::Lookup (" << ifIndex << ", " << &ipHeader <<
+ ", " << &packet << &routeReply << ")");
+
+ for (Ipv4RoutingProtocolList::const_iterator rprotoIter =
+ m_routingProtocols.begin ();
+ rprotoIter != m_routingProtocols.end ();
+ rprotoIter++)
{
- if ((*rprotoIter).second->RequestRoute (ipHeader, packet, routeReply))
+ NS_DEBUG("Ipv4L3Protocol::Lookup (): Requesting route");
+ if ((*rprotoIter).second->RequestRoute (ifIndex, ipHeader, packet,
+ routeReply))
return;
}
- // No route found
+
+ if (ipHeader.GetDestination ().IsMulticast () &&
+ ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY)
+ {
+ NS_DEBUG ("Ipv4L3Protocol::Lookup (): "
+ "Multicast destination with local source");
+//
+// We have a multicast packet originating from the current node and were not
+// able to send it using the usual RequestRoute process. Since the usual
+// process includes trying to use a default multicast route, this means that
+// there was no specific route out of the node found, and there was no default
+// multicast route set.
+//
+// The fallback position is to look for a default unicast route and use that
+// to get the packet off the node if we have one.
+//
+ Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+ if (route)
+ {
+ NS_DEBUG ("Ipv4StaticRouting::Lookup (): "
+ "Local source. Using unicast default route for multicast packet");
+
+ routeReply (true, *route, packet, ipHeader);
+ return;
+ }
+ }
+//
+// No route found
+//
routeReply (false, Ipv4Route (), packet, ipHeader);
}
@@ -244,6 +317,8 @@
Ipv4L3Protocol::AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
int priority)
{
+ NS_DEBUG("Ipv4L3Protocol::AddRoutingProtocol (" << &routingProtocol <<
+ ", " << priority << ")");
m_routingProtocols.push_back
(std::pair<int, Ptr<Ipv4RoutingProtocol> > (-priority, routingProtocol));
m_routingProtocols.sort ();
@@ -252,39 +327,99 @@
uint32_t
Ipv4L3Protocol::GetNRoutes (void)
{
+ NS_DEBUG("Ipv4L3Protocol::GetNRoutes ()");
return m_staticRouting->GetNRoutes ();
}
Ipv4Route *
Ipv4L3Protocol::GetRoute (uint32_t index)
{
+ NS_DEBUG("Ipv4L3Protocol::GetRoute ()");
return m_staticRouting->GetRoute (index);
}
void
Ipv4L3Protocol::RemoveRoute (uint32_t index)
{
+ NS_DEBUG("Ipv4L3Protocol::RemoveRoute (" << index << ")");
m_staticRouting->RemoveRoute (index);
}
+void
+Ipv4L3Protocol::AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ NS_DEBUG("Ipv4L3Protocol::AddMulticastRoute (" << origin << ", " <<
+ group << ", " << inputInterface << ", " << &outputInterfaces << ")");
+
+ m_staticRouting->AddMulticastRoute (origin, group, inputInterface,
+ outputInterfaces);
+}
+
+void
+Ipv4L3Protocol::SetDefaultMulticastRoute (uint32_t outputInterface)
+{
+ NS_DEBUG("Ipv4L3Protocol::SetDefaultMulticastRoute (" << outputInterface <<
+ ")");
+
+ m_staticRouting->SetDefaultMulticastRoute (outputInterface);
+}
+
+uint32_t
+Ipv4L3Protocol::GetNMulticastRoutes (void) const
+{
+ NS_DEBUG("Ipv4L3Protocol::GetNMulticastRoutes ()");
+ return m_staticRouting->GetNMulticastRoutes ();
+}
+
+Ipv4MulticastRoute *
+Ipv4L3Protocol::GetMulticastRoute (uint32_t index) const
+{
+ NS_DEBUG("Ipv4L3Protocol::GetMulticastRoute (" << index << ")");
+ return m_staticRouting->GetMulticastRoute (index);
+}
+
+void
+Ipv4L3Protocol::RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+{
+ NS_DEBUG("Ipv4L3Protocol::RemoveMulticastRoute (" << origin << ", " <<
+ group << ", " << inputInterface << ")");
+ m_staticRouting->RemoveMulticastRoute (origin, group, inputInterface);
+}
+
+void
+Ipv4L3Protocol::RemoveMulticastRoute (uint32_t index)
+{
+ NS_DEBUG("Ipv4L3Protocol::RemoveMulticastRoute (" << index << ")");
+ m_staticRouting->RemoveMulticastRoute (index);
+}
uint32_t
Ipv4L3Protocol::AddInterface (Ptr<NetDevice> device)
{
+ NS_DEBUG("Ipv4L3Protocol::AddInterface (" << &device << ")");
Ptr<Ipv4Interface> interface = Create<ArpIpv4Interface> (m_node, device);
return AddIpv4Interface (interface);
}
+
uint32_t
Ipv4L3Protocol::AddIpv4Interface (Ptr<Ipv4Interface>interface)
{
+ NS_DEBUG("Ipv4L3Protocol::AddIpv4Interface (" << interface << ")");
uint32_t index = m_nInterfaces;
m_interfaces.push_back (interface);
m_nInterfaces++;
return index;
}
+
Ptr<Ipv4Interface>
Ipv4L3Protocol::GetInterface (uint32_t index) const
{
+ NS_DEBUG("Ipv4L3Protocol::GetInterface (" << index << ")");
uint32_t tmp = 0;
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
{
@@ -296,15 +431,61 @@
}
return 0;
}
+
uint32_t
Ipv4L3Protocol::GetNInterfaces (void) const
{
+ NS_DEBUG("Ipv4L3Protocol::GetNInterface ()");
return m_nInterfaces;
}
+uint32_t
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr) const
+{
+ NS_DEBUG("Ipv4L3Protocol::FindInterfaceForAddr (" << addr << ")");
+
+ uint32_t ifIndex = 0;
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+ i != m_interfaces.end ();
+ i++, ifIndex++)
+ {
+ if ((*i)->GetAddress () == addr)
+ {
+ return ifIndex;
+ }
+ }
+
+ NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+ "Interface not found for IP address");
+ return 0;
+}
+
+uint32_t
+Ipv4L3Protocol::FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const
+{
+ NS_DEBUG("Ipv4L3Protocol::FindInterfaceForAddr (" << addr << ", " <<
+ mask << ")");
+
+ uint32_t ifIndex = 0;
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+ i != m_interfaces.end ();
+ i++, ifIndex++)
+ {
+ if ((*i)->GetAddress ().CombineMask (mask) == addr.CombineMask (mask))
+ {
+ return ifIndex;
+ }
+ }
+
+ NS_ASSERT_MSG(false, "Ipv4L3Protocol::FindInterfaceForAddr (): "
+ "Interface not found for masked IP address");
+ return 0;
+}
+
Ptr<Ipv4Interface>
Ipv4L3Protocol::FindInterfaceForDevice (Ptr<const NetDevice> device)
{
+ NS_DEBUG("Ipv4L3Protocol::FindInterfaceForDevice (" << &device << ")");
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
{
if ((*i)->GetDevice () == device)
@@ -318,8 +499,15 @@
void
Ipv4L3Protocol::Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
{
+ NS_DEBUG("Ipv4L3Protocol::Receive (" << &device << ", " << &p << ", " <<
+ protocol << ", " << from << ")");
+
+ NS_DEBUG("Ipv4L3Protocol::Receive (): Packet from " << from);
+
uint32_t index = 0;
- for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
+ for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
+ i != m_interfaces.end ();
+ i++)
{
if ((*i)->GetDevice () == device)
{
@@ -337,7 +525,7 @@
return;
}
- if (Forwarding (packet, ipHeader, device))
+ if (Forwarding (index, packet, ipHeader, device))
{
return;
}
@@ -352,6 +540,9 @@
Ipv4Address destination,
uint8_t protocol)
{
+ NS_DEBUG("Ipv4L3Protocol::Send (" << &packet << ", " << source << ", " <<
+ ", " << destination << ", " << protocol << ")");
+
Ipv4Header ipHeader;
ipHeader.SetSource (source);
@@ -400,36 +591,54 @@
Packet packet,
Ipv4Header const &ipHeader)
{
+ NS_DEBUG("Ipv4L3Protocol::SendRealOut (" << found << ", " << &route <<
+ ", " << &packet << &ipHeader << ")");
+
if (!found)
{
- NS_DEBUG ("no route to host. drop.");
+ NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): No route to host. Drop.");
m_dropTrace (packet);
return;
}
+
+ NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): Send via interface " <<
+ route.GetInterface ());
+
packet.AddHeader (ipHeader);
Ptr<Ipv4Interface> outInterface = GetInterface (route.GetInterface ());
NS_ASSERT (packet.GetSize () <= outInterface->GetMtu ());
m_txTrace (packet, route.GetInterface ());
if (route.IsGateway ())
{
+ NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): Send to gateway " <<
+ route.GetGateway ());
outInterface->Send (packet, route.GetGateway ());
}
else
{
+ NS_DEBUG ("Ipv4L3Protocol::SendRealOut (): Send to destination " <<
+ ipHeader.GetDestination ());
outInterface->Send (packet, ipHeader.GetDestination ());
}
}
+bool
+Ipv4L3Protocol::Forwarding (
+ uint32_t ifIndex,
+ Packet const &packet,
+ Ipv4Header &ipHeader,
+ Ptr<NetDevice> device)
+{
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (" << ifIndex << ", " << &packet <<
+ ", " << &ipHeader << ", " << device << ")");
-bool
-Ipv4L3Protocol::Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device)
-{
for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin ();
i != m_interfaces.end (); i++)
{
if ((*i)->GetAddress ().IsEqual (ipHeader.GetDestination ()))
{
- NS_DEBUG ("for me 1");
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+ "For me (destination match)");
return false;
}
}
@@ -442,7 +651,8 @@
{
if (ipHeader.GetDestination ().IsEqual (interface->GetBroadcast ()))
{
- NS_DEBUG ("for me 2");
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+ "For me (interface broadcast address)");
return false;
}
break;
@@ -451,78 +661,213 @@
if (ipHeader.GetDestination ().IsBroadcast ())
{
- NS_DEBUG ("for me 3");
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+ "For me (Ipv4Addr broadcast address)");
return false;
}
+
if (ipHeader.GetDestination ().IsEqual (Ipv4Address::GetAny ()))
{
- NS_DEBUG ("for me 4");
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+ "For me (Ipv4Addr any address)");
return false;
}
+
if (ipHeader.GetTtl () == 1)
{
// Should send ttl expired here
// XXX
- NS_DEBUG ("not for me -- ttl expired. drop.");
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+ "Not for me (TTL expired). Drop");
m_dropTrace (packet);
return true;
}
ipHeader.SetTtl (ipHeader.GetTtl () - 1);
- NS_DEBUG ("not for me -- forwarding.");
- Lookup (ipHeader, packet,
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): Forwarding packet.");
+ Lookup (ifIndex, ipHeader, packet,
MakeCallback (&Ipv4L3Protocol::SendRealOut, this));
+//
+// If this is a to a multicast address and this node is a member of the
+// indicated group we need to return false so the multicast is forwarded up.
+// Note that we may have just forwarded this packet too.
+//
+ for (Ipv4MulticastGroupList::const_iterator i = m_multicastGroups.begin ();
+ i != m_multicastGroups.end (); i++)
+ {
+ if ((*i).first.IsEqual (ipHeader.GetSource ()) &&
+ (*i).second.IsEqual (ipHeader.GetDestination ()))
+ {
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): "
+ "For me (Joined multicast group)");
+ return false;
+ }
+ }
+
+ NS_DEBUG("Ipv4L3Protocol::Forwarding (): Not for me.");
return true;
}
-
void
Ipv4L3Protocol::ForwardUp (Packet p, Ipv4Header const&ip)
{
+ NS_DEBUG("Ipv4L3Protocol::ForwardUp (" << &p << ", " << &ip << ")");
Ptr<Ipv4L4Demux> demux = m_node->QueryInterface<Ipv4L4Demux> (Ipv4L4Demux::iid);
Ptr<Ipv4L4Protocol> protocol = demux->GetProtocol (ip.GetProtocol ());
protocol->Receive (p, ip.GetSource (), ip.GetDestination ());
}
void
+Ipv4L3Protocol::JoinMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ NS_DEBUG("Ipv4L3Protocol::JoinMulticastGroup (" << origin << ", " <<
+ group << ")");
+ m_multicastGroups.push_back(
+ std::pair<Ipv4Address, Ipv4Address> (origin, group));
+}
+
+void
+Ipv4L3Protocol::LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group)
+{
+ NS_DEBUG("Ipv4L3Protocol::LeaveMulticastGroup (" << origin << ", " <<
+ group << ")");
+
+ for (Ipv4MulticastGroupList::iterator i = m_multicastGroups.begin ();
+ i != m_multicastGroups.end ();
+ i++)
+ {
+ if ((*i).first.IsEqual(origin) && (*i).second.IsEqual(group))
+ {
+ m_multicastGroups.erase (i);
+ return;
+ }
+ }
+}
+
+void
Ipv4L3Protocol::SetAddress (uint32_t i, Ipv4Address address)
{
+ NS_DEBUG("Ipv4L3Protocol::SetAddress (" << i << ", " << address << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetAddress (address);
}
+
void
Ipv4L3Protocol::SetNetworkMask (uint32_t i, Ipv4Mask mask)
{
+ NS_DEBUG("Ipv4L3Protocol::SetNetworkMask (" << i << ", " << mask << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetNetworkMask (mask);
}
+
Ipv4Mask
Ipv4L3Protocol::GetNetworkMask (uint32_t i) const
{
+ NS_DEBUG("Ipv4L3Protocol::GetNetworkMask (" << i << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetNetworkMask ();
}
+
Ipv4Address
Ipv4L3Protocol::GetAddress (uint32_t i) const
{
+ NS_DEBUG("Ipv4L3Protocol::GetAddress (" << i << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetAddress ();
}
+
+bool
+Ipv4L3Protocol::GetIfIndexForDestination (
+ Ipv4Address destination, uint32_t& ifIndex) const
+{
+ NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (" << destination <<
+ ", " << &ifIndex << ")");
+//
+// The first thing we do in trying to determine a source address is to
+// consult the routing protocols. These will also check for a default route
+// if one has been set.
+//
+ for (Ipv4RoutingProtocolList::const_iterator i = m_routingProtocols.begin ();
+ i != m_routingProtocols.end ();
+ i++)
+ {
+ NS_DEBUG("Ipv4L3Protocol::Lookup (): Requesting Source Address");
+ uint32_t ifIndexTmp;
+
+ if ((*i).second->RequestIfIndex (destination, ifIndexTmp))
+ {
+ NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+ "Found ifIndex " << ifIndexTmp);
+ ifIndex = ifIndexTmp;
+ return true;
+ }
+ }
+//
+// If there's no routing table entry telling us what *single* interface will
+// be used to send a packet to this destination, we'll have to just pick one.
+// If there's only one interface on this node, a good answer isn't very hard
+// to come up with. Before jumping to any conclusions, remember that the
+// zeroth interface is the loopback interface, so what we actually want is
+// a situation where there are exactly two interfaces on the node, in which
+// case interface one is the "single" interface connected to the outside world.
+//
+ if (GetNInterfaces () == 2)
+ {
+ NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+ "One Interface. Using interface 1.");
+ ifIndex = 1;
+ return true;
+ }
+//
+// If we fall through to here, we have a node with multiple interfaces and
+// no routes to guide us in determining what interface to choose. Either
+// no default route was found (for unicast or multicast), or in the case of a
+// multicast, the default route contained multiple outbound interfaces.
+//
+// The fallback position is to just get the unicast default route and use
+// the outgoing interface specified there. We don't want to leave the source
+// address unset, so we just assert here.
+//
+// N.B. that in the case of a multicast with a route containing multiple
+// outgoing interfaces, the source address of packets from that node will be
+// set to the IP address of the interface set in the default unicast route.
+// Also, in the case of a broadcast, the same will be true.
+//
+ NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+ "Using default unicast route");
+ Ipv4Route *route = m_staticRouting->GetDefaultRoute ();
+
+ NS_ASSERT_MSG(route,
+ "Ipv4L3Protocol::GetIfIndexForDestination (): "
+ "Unable to determine outbound interface. No default route set");
+
+ ifIndex = route->GetInterface ();
+
+ NS_DEBUG("Ipv4L3Protocol::GetIfIndexForDestination (): "
+ "Default route specifies interface " << ifIndex);
+ return true;
+}
+
uint16_t
Ipv4L3Protocol::GetMtu (uint32_t i) const
{
+ NS_DEBUG("Ipv4L3Protocol::GetMtu (" << i << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->GetMtu ();
}
+
bool
Ipv4L3Protocol::IsUp (uint32_t i) const
{
+ NS_DEBUG("Ipv4L3Protocol::IsUp (" << i << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
return interface->IsUp ();
}
+
void
Ipv4L3Protocol::SetUp (uint32_t i)
{
+ NS_DEBUG("Ipv4L3Protocol::SetUp (" << i << ")");
Ptr<Ipv4Interface> interface = GetInterface (i);
interface->SetUp ();
@@ -536,9 +881,11 @@
interface->GetNetworkMask (), i);
}
}
+
void
Ipv4L3Protocol::SetDown (uint32_t ifaceIndex)
{
+ NS_DEBUG("Ipv4L3Protocol::SetDown (" << ifaceIndex << ")");
Ptr<Ipv4Interface> interface = GetInterface (ifaceIndex);
interface->SetDown ();
--- a/src/internet-node/ipv4-l3-protocol.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.h Wed Sep 12 18:06:09 2007 +0100
@@ -169,15 +169,37 @@
Ipv4Route *GetRoute (uint32_t i);
void RemoveRoute (uint32_t i);
+ void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+ void SetDefaultMulticastRoute (uint32_t onputInterface);
+
+ uint32_t GetNMulticastRoutes (void) const;
+ Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
+
+ void RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface);
+ void RemoveMulticastRoute (uint32_t i);
+
uint32_t AddInterface (Ptr<NetDevice> device);
Ptr<Ipv4Interface> GetInterface (uint32_t i) const;
uint32_t GetNInterfaces (void) const;
+ uint32_t FindInterfaceForAddr (Ipv4Address addr) const;
+ uint32_t FindInterfaceForAddr (Ipv4Address addr, Ipv4Mask mask) const;
+ void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group);
+ void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group);
+
void SetAddress (uint32_t i, Ipv4Address address);
void SetNetworkMask (uint32_t i, Ipv4Mask mask);
Ipv4Mask GetNetworkMask (uint32_t t) const;
Ipv4Address GetAddress (uint32_t i) const;
+ bool GetIfIndexForDestination (Ipv4Address destination,
+ uint32_t& ifIndex) const;
uint16_t GetMtu (uint32_t i) const;
bool IsUp (uint32_t i) const;
void SetUp (uint32_t i);
@@ -192,17 +214,26 @@
virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
+ void Lookup (uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ Ipv4RoutingProtocol::RouteReplyCallback routeReply);
void SendRealOut (bool found,
Ipv4Route const &route,
Packet packet,
Ipv4Header const &ipHeader);
- bool Forwarding (Packet const &packet, Ipv4Header &ipHeader, Ptr<NetDevice> device);
+ bool Forwarding (uint32_t ifIndex,
+ Packet const &packet,
+ Ipv4Header &ipHeader,
+ Ptr<NetDevice> device);
void ForwardUp (Packet p, Ipv4Header const&ip);
uint32_t AddIpv4Interface (Ptr<Ipv4Interface> interface);
void SetupLoopback (void);
typedef std::list<Ptr<Ipv4Interface> > Ipv4InterfaceList;
+ typedef std::list<std::pair<Ipv4Address, Ipv4Address> >
+ Ipv4MulticastGroupList;
typedef std::list< std::pair< int, Ptr<Ipv4RoutingProtocol> > > Ipv4RoutingProtocolList;
Ipv4InterfaceList m_interfaces;
@@ -217,6 +248,7 @@
Ipv4RoutingProtocolList m_routingProtocols;
Ptr<Ipv4StaticRouting> m_staticRouting;
+ Ipv4MulticastGroupList m_multicastGroups;
};
} // Namespace ns3
--- a/src/internet-node/ipv4-loopback-interface.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-loopback-interface.cc Wed Sep 12 18:06:09 2007 +0100
@@ -19,25 +19,41 @@
* Authors:
* Mathieu Lacage <mathieu.lacage@sophia.inria.fr>,
*/
+
+#include "ns3/debug.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"
+NS_DEBUG_COMPONENT_DEFINE ("Ipv4LoopbackInterface");
+
namespace ns3 {
Ipv4LoopbackInterface::Ipv4LoopbackInterface (Ptr<Node> node)
: Ipv4Interface (0),
m_node (node)
-{}
+{
+ NS_DEBUG("Ipv4LoopbackInterface::Ipv4LoopbackInterface ()");
+}
+
Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()
-{}
+{
+ NS_DEBUG("Ipv4LoopbackInterface::~Ipv4LoopbackInterface ()");
+}
+
void
Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
{
- Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
- ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff"));
+ NS_DEBUG("Ipv4LoopbackInterface::SendTo (" << &packet << ", " <<
+ dest << ")");
+
+ Ptr<Ipv4L3Protocol> ipv4 =
+ m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+
+ ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER,
+ Eui48Address ("ff:ff:ff:ff:ff:ff"));
}
}//namespace ns3
--- a/src/internet-node/ipv4-static-routing.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-static-routing.cc Wed Sep 12 18:06:09 2007 +0100
@@ -19,22 +19,30 @@
// Author: George F. Riley<riley@ece.gatech.edu>
// Gustavo Carneiro <gjc@inescporto.pt>
+#include "ns3/debug.h"
#include "ipv4-static-routing.h"
#include "ns3/packet.h"
+NS_DEBUG_COMPONENT_DEFINE ("Ipv4StaticRouting");
namespace ns3 {
+Ipv4StaticRouting::Ipv4StaticRouting ()
+: m_defaultRoute (0), m_defaultMulticastRoute (0)
+{
+}
void
Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
uint32_t interface)
{
+
Ipv4Route *route = new Ipv4Route ();
*route = Ipv4Route::CreateHostRouteTo (dest, nextHop, interface);
m_hostRoutes.push_back (route);
}
+
void
Ipv4StaticRouting::AddHostRouteTo (Ipv4Address dest,
uint32_t interface)
@@ -43,6 +51,7 @@
*route = Ipv4Route::CreateHostRouteTo (dest, interface);
m_hostRoutes.push_back (route);
}
+
void
Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
@@ -56,6 +65,7 @@
interface);
m_networkRoutes.push_back (route);
}
+
void
Ipv4StaticRouting::AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
@@ -67,6 +77,7 @@
interface);
m_networkRoutes.push_back (route);
}
+
void
Ipv4StaticRouting::SetDefaultRoute (Ipv4Address nextHop,
uint32_t interface)
@@ -77,6 +88,168 @@
m_defaultRoute = route;
}
+void
+Ipv4StaticRouting::AddMulticastRoute(Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+ *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group,
+ inputInterface, outputInterfaces);
+ m_multicastRoutes.push_back (route);
+}
+
+void
+Ipv4StaticRouting::SetDefaultMulticastRoute(uint32_t outputInterface)
+{
+ Ipv4Address origin = Ipv4Address::GetAny ();
+ Ipv4Address group = Ipv4Address::GetAny ();
+ uint32_t inputInterface = Ipv4RoutingProtocol::IF_INDEX_ANY;
+
+ std::vector<uint32_t> outputInterfaces (1);
+ outputInterfaces[0] = outputInterface;
+
+ Ipv4MulticastRoute *route = new Ipv4MulticastRoute ();
+ *route = Ipv4MulticastRoute::CreateMulticastRoute (origin, group,
+ inputInterface, outputInterfaces);
+
+ delete m_defaultMulticastRoute;
+ m_defaultMulticastRoute = route;
+}
+
+uint32_t
+Ipv4StaticRouting::GetNMulticastRoutes (void) const
+{
+ return m_multicastRoutes.size () + m_defaultMulticastRoute ? 1 : 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetMulticastRoute (uint32_t index) const
+{
+ NS_ASSERT_MSG(index < m_multicastRoutes.size (),
+ "Ipv4StaticRouting::GetMulticastRoute (): Index out of range");
+//
+// From an external point of view the default route appears to be in slot 0
+// of the routing table. The implementation, however, puts it in a separate
+// place. So, if a client asks for index 0 and we have a default multicast
+// route, we have to return it from that different place
+// (m_defaultMulticastRoute).
+//
+ if (index == 0 && m_defaultMulticastRoute != 0)
+ {
+ return m_defaultMulticastRoute;
+ }
+//
+// If there is a default multicast route present, a client will just assume
+// that it is in slot zero and there is one "extra" zeroth route in the table.
+// To return the correct indexed entry in our list, we have to decrement the
+// index to take into account the default route not being in the actual list.
+// Since we fell through to here, we've taken care of the case where the
+// index was zero.
+//
+ if (m_defaultMulticastRoute != 0)
+ {
+ NS_ASSERT(index > 0);
+ index--;
+ }
+
+ if (index < m_multicastRoutes.size ())
+ {
+ uint32_t tmp = 0;
+ for (MulticastRoutesCI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ if (tmp == index)
+ {
+ return *i;
+ }
+ tmp++;
+ }
+ }
+ return 0;
+}
+
+Ipv4MulticastRoute *
+Ipv4StaticRouting::GetDefaultMulticastRoute () const
+{
+ if (m_defaultMulticastRoute != 0)
+ {
+ return m_defaultMulticastRoute;
+ }
+ return 0;
+}
+
+bool
+Ipv4StaticRouting::RemoveMulticastRoute(Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface)
+{
+//
+// This method does not attempt to delete the multicast route.
+//
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+ if (origin == route->GetOrigin () &&
+ group == route->GetGroup () &&
+ inputInterface == route->GetInputInterface ())
+ {
+ delete *i;
+ m_multicastRoutes.erase (i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Ipv4StaticRouting::RemoveMulticastRoute(uint32_t index)
+{
+//
+// From an external point of view the default route appears to be in slot 0
+// of the routing table. The implementation, however, puts it in a separate
+// place. So, if a client asks to delete index 0 and we have a default
+// multicast route set, we have to delete it from that different place
+// (m_defaultMulticastRoute).
+//
+ if (index == 0 && m_defaultMulticastRoute != 0)
+ {
+ delete m_defaultMulticastRoute;
+ m_defaultMulticastRoute = 0;
+ }
+//
+// If there is a default multicast route present, a client will just assume
+// that it is in slot zero and there is one "extra" zeroth route in the table.
+// To return the correct indexed entry in our list, we have to decrement the
+// index to take into account the default route not being in the actual list.
+// Since we fell through to here, we've taken care of the case where the
+// index was zero.
+//
+ if (m_defaultMulticastRoute != 0)
+ {
+ NS_ASSERT(index > 0);
+ index--;
+ }
+
+ uint32_t tmp = 0;
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ if (tmp == index)
+ {
+ delete *i;
+ m_multicastRoutes.erase (i);
+ return;
+ }
+ tmp++;
+ }
+}
+
Ipv4Route *
Ipv4StaticRouting::LookupStatic (Ipv4Address dest)
{
@@ -110,6 +283,110 @@
return 0;
}
+Ipv4MulticastRoute *
+Ipv4StaticRouting::LookupStatic (
+ Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t ifIndex)
+{
+//
+// We treat the "any" address (typically 0.0.0.0) as a wildcard in our matching
+// scheme.
+//
+ Ipv4Address wildcard = Ipv4Address::GetAny ();
+
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+//
+// We've been passed an origin address, a multicast group address and an
+// interface index. We have to decide if the current route in the list is
+// a match.
+//
+// The first case is the restrictive case where the origin, group and index
+// matches. This picks up exact routes during forwarded and exact routes from
+// the local node (in which case the ifIndex is a wildcard).
+//
+ if (origin == route->GetOrigin () && group == route->GetGroup ())
+ {
+ if (ifIndex == Ipv4RoutingProtocol::IF_INDEX_ANY ||
+ ifIndex == route->GetInputInterface ())
+ {
+ return *i;
+ }
+ }
+ }
+//
+// If the input interface index is not a wildcard (that means that the packet
+// did not originally come from this node), we're done. We don't
+// just happily forward packets we don't really know what to do with.
+// Multicast storms are not generally considered a good thing.
+//
+ if (ifIndex != Ipv4RoutingProtocol::IF_INDEX_ANY)
+ {
+ return 0;
+ }
+//
+// Now, we're going to get a litle less restricive. This only applies in the
+// case where the packet in question is coming from the local node. In order
+// to avoid dependencies on the order in which routes were added, we will
+// actually walk the list two more times, the first time looking for routes
+// with a single wildcard, and the last time looking for the first route
+// with two wildcards.
+//
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+//
+// Here we will ignore the origin. We know that a single source address must
+// be picked for a packet, but we may want to send multicast packets out
+// multiple interfaces. To support this case, a user would need to add
+// a Multicast route with the route's origin set to wildcard. N.B As a
+// result, packets sourced from a node with multiple interface may have a
+// source IP address different from that of the interface actually used to
+// send the packet.
+//
+ if (route->GetOrigin () == wildcard && group == route->GetGroup ())
+ {
+ return *i;
+ }
+ }
+//
+// Finally we want to allow users to specify a default route that specifies
+// sending all multicast packets out multiple interfaces. The standard
+// default multicast route is patterned after other systems and limits the
+// number of outputs to one. If, however a client manually adds a multicast
+// route with the origin, the multicast group and the input interface index
+// all set to wildcard, she has created a default route with multiple output
+// interfaces.
+//
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i++)
+ {
+ Ipv4MulticastRoute *route = *i;
+
+ if (route->GetOrigin () == wildcard && route->GetGroup () == wildcard)
+ {
+ return *i;
+ }
+ }
+//
+// We also allow users to specify a typical default multicast route. This
+// default route is limited to specifying a single output interface.
+//
+ if (m_defaultMulticastRoute != 0)
+ {
+ return m_defaultMulticastRoute;
+ }
+
+ return 0;
+}
+
uint32_t
Ipv4StaticRouting::GetNRoutes (void)
{
@@ -122,6 +399,20 @@
n += m_networkRoutes.size ();
return n;
}
+
+Ipv4Route *
+Ipv4StaticRouting::GetDefaultRoute ()
+{
+ if (m_defaultRoute != 0)
+ {
+ return m_defaultRoute;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
Ipv4Route *
Ipv4StaticRouting::GetRoute (uint32_t index)
{
@@ -209,10 +500,52 @@
}
bool
-Ipv4StaticRouting::RequestRoute (Ipv4Header const &ipHeader,
- Packet packet,
- RouteReplyCallback routeReply)
+Ipv4StaticRouting::RequestRoute (
+ uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
+ Packet packet,
+ RouteReplyCallback routeReply)
{
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (" << &ipHeader << ", " <<
+ &packet << ", " << &routeReply << ")");
+
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): source = " <<
+ ipHeader.GetSource ());
+
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): destination = " <<
+ ipHeader.GetDestination ());
+
+ if (ipHeader.GetDestination ().IsMulticast ())
+ {
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): Multicast destination");
+
+ Ipv4MulticastRoute *mRoute = LookupStatic(ipHeader.GetSource (),
+ ipHeader.GetDestination (), ifIndex);
+
+ if (mRoute)
+ {
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): "
+ "Multicast route found");
+
+ for (uint32_t i = 0; i < mRoute->GetNOutputInterfaces (); ++i)
+ {
+ Packet p = packet;
+ Ipv4Header h = ipHeader;
+ Ipv4Route route =
+ Ipv4Route::CreateHostRouteTo(h.GetDestination (),
+ mRoute->GetOutputInterface(i));
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): "
+ "Send via interface " << mRoute->GetOutputInterface(i));
+ routeReply (true, route, p, h);
+ }
+ return true;
+ }
+ return false; // Let other routing protocols try to handle this
+ }
+//
+// This is a unicast packet. Check to see if we have a route for it.
+//
+ NS_DEBUG ("Ipv4StaticRouting::RequestRoute (): Unicast destination");
Ipv4Route *route = LookupStatic (ipHeader.GetDestination ());
if (route != 0)
{
@@ -226,6 +559,57 @@
}
}
+bool
+Ipv4StaticRouting::RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex)
+{
+ NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (" << destination << ", " <<
+ &ifIndex << ")");
+//
+// First, see if this is a multicast packet we have a route for. If we
+// have a route, then send the packet down each of the specified interfaces.
+//
+ if (destination.IsMulticast ())
+ {
+ NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): Multicast destination");
+
+ Ipv4MulticastRoute *mRoute = LookupStatic(Ipv4Address::GetAny (),
+ destination, Ipv4RoutingProtocol::IF_INDEX_ANY);
+
+ if (mRoute)
+ {
+ NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): "
+ "Multicast route found");
+
+ if (mRoute->GetNOutputInterfaces () != 1)
+ {
+ NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): "
+ "Route is to multiple interfaces. Ignoring.");
+ return false;
+ }
+
+ ifIndex = mRoute->GetOutputInterface(0);
+ NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): "
+ "Found ifIndex " << ifIndex);
+ return true;
+ }
+ return false; // Let other routing protocols try to handle this
+ }
+//
+// See if this is a unicast packet we have a route for.
+//
+ NS_DEBUG ("Ipv4StaticRouting::RequestIfIndex (): Unicast destination");
+ Ipv4Route *route = LookupStatic (destination);
+ if (route)
+ {
+ ifIndex = route->GetInterface ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
void
Ipv4StaticRouting::DoDispose (void)
{
@@ -246,8 +630,18 @@
delete m_defaultRoute;
m_defaultRoute = 0;
}
+ for (MulticastRoutesI i = m_multicastRoutes.begin ();
+ i != m_multicastRoutes.end ();
+ i = m_multicastRoutes.erase (i))
+ {
+ delete (*i);
+ }
+ if (m_defaultMulticastRoute != 0)
+ {
+ delete m_defaultMulticastRoute;
+ m_defaultMulticastRoute = 0;
+ }
Ipv4RoutingProtocol::DoDispose ();
}
-
}//namespace ns3
--- a/src/internet-node/ipv4-static-routing.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/ipv4-static-routing.h Wed Sep 12 18:06:09 2007 +0100
@@ -45,36 +45,441 @@
class TraceContext;
+/**
+ * @brief Static routing protocol for IP version 4 stacks.
+ *
+ * In ns-3 we have the concept of a pluggable routing protocol. Routing
+ * protocols are added to a list maintained by the Ipv4L3Protocol. Every
+ * stack gets one routing protocol for free -- the Ipv4StaticRouting routing
+ * protocol is added in the constructor of the Ipv4L3Protocol (this is the
+ * piece of code that implements the functionality of the IP layer).
+ *
+ * The Ipv4StaticRouting class inherits from the abstract base class
+ * Ipv4RoutingProtocol that defines the interface methods that a routing
+ * protocol must support.
+ *
+ * When a packet arrives in the Ipv4L3Protocol for transmission, it comes
+ * either from a local source via Ipv4L3Protocol::Send or from a remote
+ * source via Ipv4L3Protocol::Forwarding. In both cases, a function is called
+ * (Ipv4L3Protocol::Lookup) to look up the routing information for the packet.
+ *
+ * The lookup function iterates through the list of routing protocols asking
+ * each to see if it can find a route and send the packet. A callback is
+ * provided during each of these calls that should be considered a pre-
+ * packaged send call. This is done to allow asynchronous calls into
+ * routing subsystems in order to support on-demand routing, for example. The
+ * method for requesting this operation is Ipv4StaticRouting::RequestRoute for
+ * the static routing protocol.
+ *
+ * Each routing protocol is also free to implement its own methods for managing
+ * routes which you will find below. This class manages a set of "static" or
+ * manually configured routes for host, network and multicast routes.
+ *
+ * @see Ipv4RoutingProtocol
+ * @see Ipv4L3Protocol::AddRoutingProtocol
+ * @see Ipv4L3Protocol::Ipv4L3Protocol
+ */
class Ipv4StaticRouting : public Ipv4RoutingProtocol
{
+public:
+/**
+ * @brief Construct an empty Ipv4StaticRouting routing protocol,
+ * @internal
+ *
+ * The Ipv4StaticRouting class supports host, network and multicast routes.
+ * This method initializes the lists containing these routes to empty.
+ *
+ * @see Ipv4StaticRouting
+ */
+ Ipv4StaticRouting ();
-public:
- Ipv4StaticRouting () : m_defaultRoute (0) {}
-
- virtual bool RequestRoute (Ipv4Header const &ipHeader,
+/**
+ * @brief Request that a check for a route bw performed and if a route is found
+ * that the packet be sent on its way using the pre-packaged send callback.
+ *
+ * The source and destination IP addresses for the packet in question are found
+ * in the provided Ipv4Header. There are two major processing forks depending
+ * on the type of destination address.
+ *
+ * If the destination address is unicast then the routing table is consulted
+ * for a route to the destination and if it is found, the routeReply callback
+ * is executed to send the packet (with the found route).
+ *
+ * If the destination address is a multicast, then the exact processing steps
+ * depend on whether or not the packet has been sourced locally. This is
+ * determined by the parameter ifIndex. This is the interface index over which
+ * this packet was received. If the packet has not been received over a
+ * network interface, this index will be set to
+ * Ipv4RoutingProtocol::IF_INDEX_ANY (a very large number). In that case,
+ * we want to avoid the requirement that an explicit route out of each node
+ * must be set, so we don't do anything here.
+ *
+ * If the packet is a multicast destination and has been received over a
+ * network interface, a call to this method implies that the packet is being
+ * forwarded. In that case, there must be an explicit route out of the node.
+ * A multicast route references the source address, the destination address
+ * (the multicast group) and the input interface in order to find a route.
+ * We consult the multicast routing table and, if a route is found, send the
+ * packet out of as many interfaces as required using the provided callback
+ * (think of it as a pre-packaged send call).
+ *
+ * @param ifIndex The network interface index over which the packed was
+ * received. If the packet is from a local source, ifIndex will be set to
+ * Ipv4RoutingProtocol::IF_INDEX_ANY.
+ * @param ipHeader the Ipv4Header containing the source and destination IP
+ * addresses for the packet.
+ * @param packet The packet to be sent if a route is found.
+ * @param routeReply A callback that packaged up the call to actually send the
+ * packet.
+ * @return Returns true if a route is found and the packet has been sent,
+ * otherwise returns false indicating that the next routing protocol should
+ * be consulted. In practice, the static routing protocol is the last chance
+ * protocol.
+ *
+ * @see Ipv4StaticRouting
+ * @see Ipv4RoutingProtocol
+ */
+ virtual bool RequestRoute (uint32_t ifIndex,
+ Ipv4Header const &ipHeader,
Packet packet,
RouteReplyCallback routeReply);
+/**
+ * @brief Check to see if we can determine the interface index that will be
+ * used if a packet is sent to this destination.
+ *
+ * This method addresses a problem in the IP stack where a destination address
+ * must be present and checksummed into the IP header before the actual
+ * interface over which the packet is sent can be determined. The answer is
+ * to implement a known and intentional cross-layer violation. This is the
+ * endpoint of a call chain that started up quite high in the stack (sockets)
+ * and has found its way down to the Ipv4L3Protocol which is consulting the
+ * routing protocols for what they would do if presented with a packet of the
+ * given destination.
+ *
+ * Note that the a single interface index is returned. This means that if
+ * the destination address is a multicast, and an explicit route is present
+ * that includeds multiple output interfaces, that route cannot be used.
+ *
+ * If there are multiple paths out of the node, the resolution is performed
+ * by Ipv4L3Protocol::GetIfIndexforDestination which has access to more
+ * contextual information that is useful for making a determination.
+ *
+ * @param destination The Ipv4Address if the destination of a hypothetical
+ * packet. This may be a multicast group address.
+ * @param ifIndex A reference to the interface index over which a packet
+ * sent to this destination would be sent.
+ * @return Returns true if a route is found to the destination that involves
+ * a single output interface index, otherwise returns false indicating that
+ * the next routing protocol should be consulted. In practice, the static
+ * routing protocol is the last chance protocol.
+ *
+ * @see Ipv4StaticRouting
+ * @see Ipv4RoutingProtocol
+ * @see Ipv4L3Protocol
+ */
+ virtual bool RequestIfIndex (Ipv4Address destination, uint32_t& ifIndex);
+/**
+ * @brief Add a host route to the static routing table.
+ *
+ * @param dest The Ipv4Address destination for this route.
+ * @param nextHop The Ipv4Address of the next hop in the route.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
void AddHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
uint32_t interface);
+/**
+ * @brief Add a host route to the static routing table.
+ *
+ * @param dest The Ipv4Address destination for this route.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
void AddHostRouteTo (Ipv4Address dest,
uint32_t interface);
+/**
+ * @brief Add a network route to the static routing table.
+ *
+ * @param network The Ipv4Address network for this route.
+ * @param networkmask The Ipv4Mask to extract the network.
+ * @param nextHop The next hop in the route to the destination network.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
void AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
Ipv4Address nextHop,
uint32_t interface);
+
+/**
+ * @brief Add a network route to the static routing table.
+ *
+ * @param network The Ipv4Address network for this route.
+ * @param networkmask The Ipv4Mask to extract the network.
+ * @param interface The network interface index used to send packets to the
+ * destination.
+ *
+ * @see Ipv4Address
+ */
void AddNetworkRouteTo (Ipv4Address network,
Ipv4Mask networkMask,
uint32_t interface);
+
+/**
+ * @brief Add a default route to the static routing table.
+ *
+ * This method tells the routing system what to do in the case where a specific
+ * route to a destination is not found. The system forwards packets to the
+ * specified node in the hope that it knows better how to route the packet.
+ *
+ * If the default route is set, it is returned as the selected route from
+ * LookupStatic irrespective of destination address if no specific route is
+ * found.
+ *
+ * @param nextHop The Ipv4Address to send packets to in the hope that they
+ * will be forwarded correctly.
+ * @param interface The network interface index used to send packets.
+ *
+ * @see Ipv4Address
+ * @see Ipv4StaticRouting::Lookup
+ */
void SetDefaultRoute (Ipv4Address nextHop,
uint32_t interface);
+
+/**
+ * @brief Get the number of individual unicast routes that have been added
+ * to the routing table.
+ *
+ * @warning The default route counts as one of the routes.
+ */
uint32_t GetNRoutes (void);
+
+/**
+ * @brief Get the default route from the static routing table.
+ *
+ * @return If the default route is set, a pointer to that Ipv4Route is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ */
+ Ipv4Route *GetDefaultRoute (void);
+
+/**
+ * @brief Get a route from the static unicast routing table.
+ *
+ * Externally, the unicast static routing table appears simply as a table with
+ * n entries. The one sublety of note is that if a default route has been set
+ * it will appear as the zeroth entry in the table. This means that if you
+ * add only a default route, the table will have one entry that can be accessed
+ * either by explicity calling GetDefaultRoute () or by calling GetRoute (0).
+ *
+ * Similarly, if the default route has been set, calling RemoveRoute (0) will
+ * remove the default route.
+ *
+ * @param i The index (into the routing table) of the route to retrieve. If
+ * the default route has been set, it will occupy index zero.
+ * @return If route is set, a pointer to that Ipv4Route is returned, otherwise
+ * a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::RemoveRoute
+ */
Ipv4Route *GetRoute (uint32_t i);
+
+/**
+ * @brief Remove a route from the static unicast routing table.
+ *
+ * Externally, the unicast static routing table appears simply as a table with
+ * n entries. The one sublety of note is that if a default route has been set
+ * it will appear as the zeroth entry in the table. This means that if the
+ * default route has been set, calling RemoveRoute (0) will remove the
+ * default route.
+ *
+ * @param i The index (into the routing table) of the route to remove. If
+ * the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
void RemoveRoute (uint32_t i);
+/**
+ * @brief Add a multicast route to the static routing table.
+ *
+ * A multicast route must specify an origin IP address, a multicast group and
+ * an input network interface index as conditions and provide a vector of
+ * output network interface indices over which packets matching the conditions
+ * are sent.
+ *
+ * Typically there are two main types of multicast routes: routes of the
+ * first kind are used during forwarding. All of the conditions must be
+ * exlicitly provided. The second kind of routes are used to get packets off
+ * of a local node. The difference is in the input interface. Routes for
+ * forwarding will always have an explicit input interface specified. Routes
+ * off of a node will always set the input interface to a wildcard specified
+ * by the index Ipv4RoutingProtocol::IF_INDEX_ANY.
+ *
+ * For routes off of a local node wildcards may be used in the origin and
+ * multicast group addresses. The wildcard used for Ipv4Adresses is that
+ * address returned by Ipv4Address::GetAny () -- typically "0.0.0.0". Usage
+ * of a wildcard allows one to specify default behavior to varying degrees.
+ *
+ * For example, making the origin address a wildcard, but leaving the
+ * multicast group specific allows one (in the case of a node with multiple
+ * interfaces) to create different routes using different output interfaces
+ * for each multicast group.
+ *
+ * If the origin and multicast addresses are made wildcards, you have created
+ * essentially a default multicast address that can forward to multiple
+ * interfaces. Compare this to the actual default multicast address that is
+ * limited to specifying a single output interface for compatibility with
+ * existing functionality in other systems.
+ *
+ * @param origin The Ipv4Address of the origin of packets for this route. May
+ * be Ipv4Address:GetAny for open groups.
+ * @param group The Ipv4Address of the multicast group or this route.
+ * @param inputInterface The input network interface index over which to
+ * expect packets destined for this route. May be
+ * Ipv4RoutingProtocol::IF_INDEX_ANY for packets of local origin.
+ * @param outputInterface A vector of network interface indices used to specify
+ * how to send packets to the destination(s).
+ *
+ * @see Ipv4Address
+ */
+ void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+/**
+ * @brief Add a default multicast route to the static routing table.
+ *
+ * This is the multicast equivalent of the unicast version SetDefaultRoute.
+ * We tell the routing system what to do in the case where a specific route
+ * to a destination multicast group is not found. The system forwards
+ * packets out the specified interface in the hope that "something out there"
+ * knows better how to route the packet. This method is only used in
+ * initially sending packets off of a host. The default multicast route is
+ * not consulted during forwarding -- exact routes must be specified using
+ * AddMulticastRoute for that case.
+ *
+ * Since we're basically sending packets to some entity we think may know
+ * better what to do, we don't pay attention to "subtleties" like origin
+ * address, nor do we worry about forwarding out multiple interfaces. If the
+ * default multicast route is set, it is returned as the selected route from
+ * LookupStatic irrespective of origin or multicast group if another specific
+ * route is not found.
+ *
+ * @param outputInterface The network interface index used to specify where
+ * to send packets in the case of unknown routes.
+ *
+ * @see Ipv4Address
+ */
+ void SetDefaultMulticastRoute (uint32_t outputInterface);
+
+/**
+ * @brief Get the number of individual multicast routes that have been added
+ * to the routing table.
+ *
+ * @warning The default multicast route counts as one of the routes.
+ */
+ uint32_t GetNMulticastRoutes (void) const;
+
+/**
+ * @brief Get a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default route has
+ * been set it will appear as the zeroth entry in the table. This means that
+ * if you add only a default route, the table will have one entry that can be
+ * accessed either by explicity calling GetDefaultMulticastRoute () or by
+ * calling GetMulticastRoute (0).
+ *
+ * Similarly, if the default route has been set, calling
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param i The index (into the routing table) of the multicast route to
+ * retrieve. If the default route has been set, it will occupy index zero.
+ * @return If route <i> is set, a pointer to that Ipv4MulticastRoute is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::RemoveRoute
+ */
+ Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
+
+/**
+ * @brief Get the default multicast route from the static routing table.
+ *
+ * @return If the default route is set, a pointer to that Ipv4MulticastRoute is
+ * returned, otherwise a zero pointer is returned.
+ *
+ * @see Ipv4Route
+ */
+ Ipv4MulticastRoute *GetDefaultMulticastRoute (void) const;
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table. This
+ * means that the default route may be removed by calling this method with
+ * appropriate wildcard parameters.
+ *
+ * This method causes the multicast routing table to be searched for the first
+ * route that matches the parameters and removes it.
+ *
+ * Wildcards may be provided to this function, but the wildcards are used to
+ * exacly match wildcards in the routes (see AddMulticastRoute). That is,
+ * calling RemoveMulticastRoute with the origin set to "0.0.0.0" will not
+ * remove routes with any address in the origin, but will only remove routes
+ * with "0.0.0.0" set as the the origin.
+ *
+ * @param origin The IP address specified as the origin of packets for the
+ * route.
+ * @param origin The IP address specified as the multicast group addres of
+ * the route.
+ * @param inputInterfade The network interface index specified as the expected
+ * input interface for the route.
+ * @returns True if a route was found and removed, false otherwise.
+ *
+ * @see Ipv4MulticastRoute
+ * @see Ipv4StaticRouting::AddMulticastRoute
+ */
+ bool RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface);
+
+/**
+ * @brief Remove a route from the static multicast routing table.
+ *
+ * Externally, the multicast static routing table appears simply as a table
+ * with n entries. The one sublety of note is that if a default multicast
+ * route has been set it will appear as the zeroth entry in the table. This
+ * means that if the default route has been set, calling
+ * RemoveMulticastRoute (0) will remove the default route.
+ *
+ * @param index The index (into the multicast routing table) of the route to
+ * remove. If the default route has been set, it will occupy index zero.
+ *
+ * @see Ipv4Route
+ * @see Ipv4StaticRouting::GetRoute
+ * @see Ipv4StaticRouting::AddRoute
+ */
+ void RemoveMulticastRoute (uint32_t index);
+
protected:
void DoDispose (void);
@@ -86,15 +491,21 @@
typedef std::list<Ipv4Route *>::const_iterator NetworkRoutesCI;
typedef std::list<Ipv4Route *>::iterator NetworkRoutesI;
+ typedef std::list<Ipv4MulticastRoute *> MulticastRoutes;
+ typedef std::list<Ipv4MulticastRoute *>::const_iterator MulticastRoutesCI;
+ typedef std::list<Ipv4MulticastRoute *>::iterator MulticastRoutesI;
+
Ipv4Route *LookupStatic (Ipv4Address dest);
+ Ipv4MulticastRoute *LookupStatic (Ipv4Address origin, Ipv4Address group,
+ uint32_t ifIndex);
HostRoutes m_hostRoutes;
NetworkRoutes m_networkRoutes;
Ipv4Route *m_defaultRoute;
+ Ipv4MulticastRoute *m_defaultMulticastRoute;
+ MulticastRoutes m_multicastRoutes;
};
-
-
} // Namespace ns3
#endif /* IPV4_STATIC_ROUTING_H */
--- a/src/internet-node/udp-l4-protocol.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/udp-l4-protocol.cc Wed Sep 12 18:06:09 2007 +0100
@@ -19,6 +19,7 @@
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+#include "ns3/debug.h"
#include "ns3/assert.h"
#include "ns3/packet.h"
#include "ns3/node.h"
@@ -30,6 +31,8 @@
#include "ipv4-l3-protocol.h"
#include "udp-socket.h"
+NS_DEBUG_COMPONENT_DEFINE ("UdpL4Protocol");
+
namespace ns3 {
/* see http://www.iana.org/assignments/protocol-numbers */
@@ -39,14 +42,19 @@
: Ipv4L4Protocol (PROT_NUMBER, 2),
m_node (node),
m_endPoints (new Ipv4EndPointDemux ())
-{}
+{
+ NS_DEBUG("UdpL4Protocol::UdpL4Protocol ()");
+}
UdpL4Protocol::~UdpL4Protocol ()
-{}
+{
+ NS_DEBUG("UdpL4Protocol::~UdpL4Protocol ()");
+}
void
UdpL4Protocol::DoDispose (void)
{
+ NS_DEBUG("UdpL4Protocol::DoDispose ()");
if (m_endPoints != 0)
{
delete m_endPoints;
@@ -59,6 +67,7 @@
Ptr<Socket>
UdpL4Protocol::CreateSocket (void)
{
+ NS_DEBUG("UdpL4Protocol::CreateSocket ()");
Ptr<Socket> socket = Create<UdpSocket> (m_node, this);
return socket;
}
@@ -66,27 +75,36 @@
Ipv4EndPoint *
UdpL4Protocol::Allocate (void)
{
+ NS_DEBUG("UdpL4Protocol::Allocate ()");
return m_endPoints->Allocate ();
}
+
Ipv4EndPoint *
UdpL4Protocol::Allocate (Ipv4Address address)
{
+ NS_DEBUG("UdpL4Protocol::Allocate (" << address << ")");
return m_endPoints->Allocate (address);
}
+
Ipv4EndPoint *
UdpL4Protocol::Allocate (uint16_t port)
{
+ NS_DEBUG("UdpL4Protocol::Allocate (" << port << ")");
return m_endPoints->Allocate (port);
}
+
Ipv4EndPoint *
UdpL4Protocol::Allocate (Ipv4Address address, uint16_t port)
{
+ NS_DEBUG("UdpL4Protocol::Allocate (" << address << ", " << port << ")");
return m_endPoints->Allocate (address, port);
}
Ipv4EndPoint *
UdpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
Ipv4Address peerAddress, uint16_t peerPort)
{
+ NS_DEBUG("UdpL4Protocol::Allocate (" << localAddress << ", " << localPort <<
+ ", " << peerAddress << ", " << peerPort << ")");
return m_endPoints->Allocate (localAddress, localPort,
peerAddress, peerPort);
}
@@ -94,6 +112,7 @@
void
UdpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
{
+ NS_DEBUG("UdpL4Protocol::Deallocate (" << endPoint << ")");
m_endPoints->DeAllocate (endPoint);
}
@@ -102,6 +121,9 @@
Ipv4Address const &source,
Ipv4Address const &destination)
{
+ NS_DEBUG("UdpL4Protocol::Receive (" << &packet << ", " << source <<
+ ", " << destination << ")");
+
UdpHeader udpHeader;
packet.RemoveHeader (udpHeader);
Ipv4EndPointDemux::EndPoints endPoints =
@@ -119,6 +141,9 @@
Ipv4Address saddr, Ipv4Address daddr,
uint16_t sport, uint16_t dport)
{
+ NS_DEBUG("UdpL4Protocol::Send (" << &packet << ", " << saddr <<
+ ", " << daddr << ", " << sport << ", " << dport << ")");
+
UdpHeader udpHeader;
udpHeader.SetDestination (dport);
udpHeader.SetSource (sport);
@@ -132,6 +157,7 @@
Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
if (ipv4 != 0)
{
+ NS_DEBUG("UdpL4Protocol::Send (): Sending to IP");
ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
}
}
--- a/src/internet-node/udp-socket.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/internet-node/udp-socket.cc Wed Sep 12 18:06:09 2007 +0100
@@ -18,6 +18,8 @@
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
+
+#include "ns3/debug.h"
#include "ns3/node.h"
#include "ns3/inet-socket-address.h"
#include "ns3/ipv4-route.h"
@@ -26,6 +28,9 @@
#include "udp-l4-protocol.h"
#include "ipv4-end-point.h"
#include "ipv4-l4-demux.h"
+#include "ns3/ipv4.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("UdpSocket");
namespace ns3 {
@@ -37,9 +42,14 @@
m_shutdownSend (false),
m_shutdownRecv (false),
m_connected (false)
-{}
+{
+ NS_DEBUG("UdpSocket::UdpSocket ()");
+}
+
UdpSocket::~UdpSocket ()
{
+ NS_DEBUG("UdpSocket::~UdpSocket ()");
+
m_node = 0;
if (m_endPoint != 0)
{
@@ -62,25 +72,32 @@
enum Socket::SocketErrno
UdpSocket::GetErrno (void) const
{
+ NS_DEBUG("UdpSocket::GetErrno ()");
+
return m_errno;
}
Ptr<Node>
UdpSocket::GetNode (void) const
{
+ NS_DEBUG("UdpSocket::GetNode ()");
return m_node;
}
void
UdpSocket::Destroy (void)
{
+ NS_DEBUG("UdpSocket::Destroy ()");
m_node = 0;
m_endPoint = 0;
m_udp = 0;
}
+
int
UdpSocket::FinishBind (void)
{
+ NS_DEBUG("UdpSocket::FinishBind ()");
+
if (m_endPoint == 0)
{
return -1;
@@ -93,14 +110,20 @@
int
UdpSocket::Bind (void)
{
+ NS_DEBUG("UdpSocket::Bind ()");
+
m_endPoint = m_udp->Allocate ();
return FinishBind ();
}
+
int
UdpSocket::Bind (const Address &address)
{
+ NS_DEBUG("UdpSocket::Bind (" << address << ")");
+
if (!InetSocketAddress::IsMatchingType (address))
{
+ NS_DEBUG("UdpSocket::Bind (): Not IsMatchingType");
return ERROR_INVAL;
}
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
@@ -129,12 +152,15 @@
int
UdpSocket::ShutdownSend (void)
{
+ NS_DEBUG("UdpSocket::ShutDownSend ()");
m_shutdownSend = true;
return 0;
}
+
int
UdpSocket::ShutdownRecv (void)
{
+ NS_DEBUG("UdpSocket::ShutDownRecv ()");
m_shutdownRecv = false;
return 0;
}
@@ -142,6 +168,7 @@
int
UdpSocket::Close(void)
{
+ NS_DEBUG("UdpSocket::Close ()");
NotifyCloseCompleted ();
return 0;
}
@@ -149,24 +176,36 @@
int
UdpSocket::Connect(const Address & address)
{
+ NS_DEBUG ("UdpSocket::Connect (" << address << ")");
Ipv4Route routeToDest;
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
m_defaultAddress = transport.GetIpv4 ();
m_defaultPort = transport.GetPort ();
NotifyConnectionSucceeded ();
m_connected = true;
- if (GetIpv4RouteToDestination (m_node, routeToDest, m_defaultAddress) )
+
+ NS_DEBUG ("UdpSocket::Connect (): Updating local address");
+
+ uint32_t localIfIndex;
+
+ Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+
+ if (ipv4->GetIfIndexForDestination (m_defaultAddress, localIfIndex))
{
- uint32_t localIfIndex = routeToDest.GetInterface ();
- Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
- m_endPoint->SetLocalAddress (ipv4->GetAddress(localIfIndex) );
+ m_endPoint->SetLocalAddress (ipv4->GetAddress(localIfIndex));
}
+
+ NS_DEBUG ("UdpSocket::Connect (): Local address is " <<
+ m_endPoint->GetLocalAddress());
+
return 0;
}
int
UdpSocket::Send (const Packet &p)
{
+ NS_DEBUG("UdpSocket::Send (" << &p << ")");
+
if (!m_connected)
{
m_errno = ERROR_NOTCONN;
@@ -196,12 +235,14 @@
return DoSendTo (p, m_defaultAddress, m_defaultPort);
}
-
int
UdpSocket::DoSendTo (const Packet &p, const Address &address)
{
+ NS_DEBUG("UdpSocket::DoSendTo (" << &p << ", " << address << ")");
+
if (!m_connected)
{
+ NS_DEBUG("UdpSocket::DoSendTo (): Not connected");
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
Ipv4Address ipv4 = transport.GetIpv4 ();
uint16_t port = transport.GetPort ();
@@ -210,13 +251,19 @@
else
{
// connected UDP socket must use default addresses
+ NS_DEBUG("UdpSocket::DoSendTo (): Connected");
return DoSendTo (p, m_defaultAddress, m_defaultPort);
}
}
+
int
UdpSocket::DoSendTo (const Packet &p, Ipv4Address dest, uint16_t port)
{
+ NS_DEBUG("UdpSocket::DoSendTo (" << &p << ", " << dest << ", " <<
+ port << ")");
+
Ipv4Route routeToDest;
+
if (m_endPoint == 0)
{
if (Bind () == -1)
@@ -231,13 +278,17 @@
m_errno = ERROR_SHUTDOWN;
return -1;
}
+
+ uint32_t localIfIndex;
+ Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+
//
// If dest is sent to the limited broadcast address (all ones),
// convert it to send a copy of the packet out of every interface
//
if (dest.IsBroadcast ())
{
- Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_DEBUG("UdpSocket::DoSendTo (): Limited broadcast");
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++ )
{
Ipv4Address addri = ipv4->GetAddress (i);
@@ -247,10 +298,9 @@
NotifyDataSent (p.GetSize ());
}
}
- else if (GetIpv4RouteToDestination (m_node, routeToDest, dest) )
+ else if (ipv4->GetIfIndexForDestination(dest, localIfIndex))
{
- uint32_t localIfIndex = routeToDest.GetInterface ();
- Ptr<Ipv4> ipv4 = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+ NS_DEBUG("UdpSocket::DoSendTo (): Route exists");
m_udp->Send (p, ipv4->GetAddress (localIfIndex), dest,
m_endPoint->GetLocalPort (), port);
NotifyDataSent (p.GetSize ());
@@ -258,15 +308,18 @@
}
else
{
+ NS_DEBUG("UdpSocket::DoSendTo (): ERROR_NOROUTETOHOST");
m_errno = ERROR_NOROUTETOHOST;
return -1;
}
+
return 0;
}
int
UdpSocket::SendTo(const Address &address, const Packet &p)
{
+ NS_DEBUG("UdpSocket::SendTo (" << address << ", " << &p << ")");
InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
Ipv4Address ipv4 = transport.GetIpv4 ();
uint16_t port = transport.GetPort ();
@@ -276,6 +329,9 @@
void
UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port)
{
+ NS_DEBUG("UdpSocket::ForwardUp (" << &packet << ", " << ipv4 << ", " <<
+ port << ")");
+
if (m_shutdownRecv)
{
return;
@@ -286,4 +342,4 @@
NotifyDataReceived (p, address);
}
-}//namespace ns3
+} //namespace ns3
--- a/src/mobility/grid-topology.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/grid-topology.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/grid-topology.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/grid-topology.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/hierarchical-mobility-model.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/hierarchical-mobility-model.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/hierarchical-mobility-model.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/hierarchical-mobility-model.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/mobility-model-notifier.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model-notifier.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/mobility-model-notifier.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model-notifier.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/mobility-model.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model.cc Wed Sep 12 18:06:09 2007 +0100
@@ -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
--- a/src/mobility/mobility-model.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/mobility-model.h Wed Sep 12 18:06:09 2007 +0100
@@ -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
--- a/src/mobility/position.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/position.cc Wed Sep 12 18:06:09 2007 +0100
@@ -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 <mathieu.lacage@sophia.inria.fr>
+ */
#include "position.h"
#include <cmath>
--- a/src/mobility/position.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/position.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +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 <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef POSITION_H
#define POSITION_H
--- a/src/mobility/random-position.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/random-position.cc Wed Sep 12 18:06:09 2007 +0100
@@ -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 <mathieu.lacage@sophia.inria.fr>
+ */
#include "random-position.h"
#include "ns3/random-variable.h"
#include "ns3/default-value.h"
--- a/src/mobility/random-position.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/random-position.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +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 <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef RANDOM_POSITION_H
#define RANDOM_POSITION_H
--- a/src/mobility/rectangle-default-value.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle-default-value.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/rectangle-default-value.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle-default-value.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/rectangle.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/rectangle.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/rectangle.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- 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
--- a/src/mobility/speed.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/speed.cc Wed Sep 12 18:06:09 2007 +0100
@@ -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 <mathieu.lacage@sophia.inria.fr>
+ */
#include "speed.h"
namespace ns3 {
--- a/src/mobility/speed.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/speed.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +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 <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef SPEED_H
#define SPEED_H
--- a/src/mobility/static-mobility-model.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-mobility-model.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,7 +1,6 @@
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2006 INRIA
- * All rights reserved.
+ * 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
--- a/src/mobility/static-mobility-model.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-mobility-model.h Wed Sep 12 18:06:09 2007 +0100
@@ -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
--- a/src/mobility/static-speed-helper.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-helper.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,3 +1,22 @@
+/* -*- 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 <mathieu.lacage@sophia.inria.fr>
+ */
#include "ns3/simulator.h"
#include "ns3/rectangle.h"
#include "static-speed-helper.h"
--- a/src/mobility/static-speed-helper.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-helper.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,4 +1,22 @@
/* -*- 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 <mathieu.lacage@sophia.inria.fr>
+ */
#ifndef STATIC_SPEED_HELPER_H
#define STATIC_SPEED_HELPER_H
--- a/src/mobility/static-speed-mobility-model.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-mobility-model.cc Wed Sep 12 18:06:09 2007 +0100
@@ -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
--- a/src/mobility/static-speed-mobility-model.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/mobility/static-speed-mobility-model.h Wed Sep 12 18:06:09 2007 +0100
@@ -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
--- a/src/node/ipv4-route.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4-route.cc Wed Sep 12 18:06:09 2007 +0100
@@ -30,6 +30,7 @@
Ipv4Route::Ipv4Route ()
{}
+
Ipv4Route::Ipv4Route (Ipv4Route const &route)
: m_dest (route.m_dest),
m_destNetworkMask (route.m_destNetworkMask),
@@ -37,6 +38,13 @@
m_interface (route.m_interface)
{}
+Ipv4Route::Ipv4Route (Ipv4Route const *route)
+ : m_dest (route->m_dest),
+ m_destNetworkMask (route->m_destNetworkMask),
+ m_gateway (route->m_gateway),
+ m_interface (route->m_interface)
+{}
+
Ipv4Route::Ipv4Route (Ipv4Address dest,
Ipv4Address gateway,
uint32_t interface)
@@ -137,7 +145,6 @@
return m_interface;
}
-
Ipv4Route
Ipv4Route::CreateHostRouteTo (Ipv4Address dest,
Ipv4Address nextHop,
@@ -220,4 +227,108 @@
return os;
}
+/*****************************************************
+ * Ipv4MulticastRoute
+ *****************************************************/
+
+Ipv4MulticastRoute::Ipv4MulticastRoute ()
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (Ipv4MulticastRoute const &route)
+:
+ m_origin (route.m_origin),
+ m_group (route.m_group),
+ m_inputInterface (route.m_inputInterface),
+ m_outputInterfaces (route.m_outputInterfaces)
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (Ipv4MulticastRoute const *route)
+:
+ m_origin (route->m_origin),
+ m_group (route->m_group),
+ m_inputInterface (route->m_inputInterface),
+ m_outputInterfaces (route->m_outputInterfaces)
+{
+}
+
+Ipv4MulticastRoute::Ipv4MulticastRoute (
+ Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ m_origin = origin;
+ m_group = group;
+ m_inputInterface = inputInterface;
+ m_outputInterfaces = outputInterfaces;
+}
+
+Ipv4Address
+Ipv4MulticastRoute::GetOrigin (void) const
+{
+ return m_origin;
+}
+
+Ipv4Address
+Ipv4MulticastRoute::GetGroup (void) const
+{
+ return m_group;
+}
+
+uint32_t
+Ipv4MulticastRoute::GetInputInterface (void) const
+{
+ return m_inputInterface;
+}
+
+uint32_t
+Ipv4MulticastRoute::GetNOutputInterfaces (void) const
+{
+ return m_outputInterfaces.size ();
+}
+
+uint32_t
+Ipv4MulticastRoute::GetOutputInterface (uint32_t n) const
+{
+ NS_ASSERT_MSG(n < m_outputInterfaces.size (),
+ "Ipv4MulticastRoute::GetOutputInterface (): index out of bounds");
+
+ return m_outputInterfaces[n];
+}
+
+std::vector<uint32_t>
+Ipv4MulticastRoute::GetOutputInterfaces (void) const
+{
+ return m_outputInterfaces;
+}
+
+Ipv4MulticastRoute
+Ipv4MulticastRoute::CreateMulticastRoute (
+ Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces)
+{
+ return Ipv4MulticastRoute (origin, group, inputInterface, outputInterfaces);
+}
+
+std::ostream&
+operator<< (std::ostream& os, Ipv4MulticastRoute const& route)
+{
+ os << "origin=" << route.GetOrigin () <<
+ ", group=" << route.GetGroup () <<
+ ", input interface=" << route.GetInputInterface () <<
+ ", output interfaces=";
+
+ for (uint32_t i = 0; i < route.GetNOutputInterfaces (); ++i)
+ {
+ os << route.GetOutputInterface (i) << " ";
+
+ }
+
+ return os;
+}
+
}//namespace ns3
--- a/src/node/ipv4-route.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4-route.h Wed Sep 12 18:06:09 2007 +0100
@@ -22,6 +22,7 @@
#define IPV4_ROUTE_H
#include <list>
+#include <vector>
#include <ostream>
#include "ipv4-address.h"
@@ -36,12 +37,19 @@
* \brief This constructor does nothing
*/
Ipv4Route ();
+
/**
* \brief Copy Constructor
* \param route The route to copy
*/
Ipv4Route (Ipv4Route const &route);
+ /**
+ * \brief Copy Constructor
+ * \param route The route to copy
+ */
+ Ipv4Route (Ipv4Route const *route);
+
bool IsHost (void) const;
/**
* \return The IPv4 address of the destination of this route
@@ -98,6 +106,74 @@
std::ostream& operator<< (std::ostream& os, Ipv4Route const& route);
+/**
+ * \brief A record of an IPv4 multicast route
+ */
+class Ipv4MulticastRoute {
+public:
+ /**
+ * \brief This constructor does nothing
+ */
+ Ipv4MulticastRoute ();
+
+ /**
+ * \brief Copy Constructor
+ * \param route The route to copy
+ */
+ Ipv4MulticastRoute (Ipv4MulticastRoute const &route);
+
+ /**
+ * \brief Copy Constructor
+ * \param route The route to copy
+ */
+ Ipv4MulticastRoute (Ipv4MulticastRoute const *route);
+
+ /**
+ * \return The IPv4 address of the source of this route
+ */
+ Ipv4Address GetOrigin (void) const;
+
+ /**
+ * \return The IPv4 address of the multicast group of this route
+ */
+ Ipv4Address GetGroup (void) const;
+
+ /**
+ * \return The IPv4 address of the input interface of this route
+ */
+ uint32_t GetInputInterface (void) const;
+
+ /**
+ * \return The number of output interfaces of this route
+ */
+ uint32_t GetNOutputInterfaces (void) const;
+
+ /**
+ * \return A specified output interface.
+ */
+ uint32_t GetOutputInterface (uint32_t n) const;
+
+ /**
+ * \return A vector of all of the output interfaces of this route.
+ */
+ std::vector<uint32_t> GetOutputInterfaces (void) const;
+
+ static Ipv4MulticastRoute CreateMulticastRoute (Ipv4Address origin,
+ Ipv4Address group, uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces);
+
+private:
+ Ipv4MulticastRoute (Ipv4Address origin, Ipv4Address group,
+ uint32_t inputInterface, std::vector<uint32_t> outputInterfaces);
+
+ Ipv4Address m_origin;
+ Ipv4Address m_group;
+ uint32_t m_inputInterface;
+ std::vector<uint32_t> m_outputInterfaces;
+};
+
+std::ostream& operator<< (std::ostream& os, Ipv4MulticastRoute const& route);
+
}//namespace ns3
#endif /* IPV4_ROUTE_H */
--- a/src/node/ipv4.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4.cc Wed Sep 12 18:06:09 2007 +0100
@@ -36,10 +36,10 @@
{}
uint32_t
-GetIfIndexByIpv4Address (Ptr<Node> node, Ipv4Address a, Ipv4Mask amask)
+Ipv4::GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a, Ipv4Mask amask)
{
Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
- NS_ASSERT_MSG (ipv4, "GetIfIndexByIpv4Address: No Ipv4 interface");
+ NS_ASSERT_MSG (ipv4, "Ipv4::GetIfIndexByAddress: No Ipv4 interface");
for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
{
if (ipv4->GetAddress (i).CombineMask(amask) == a.CombineMask(amask) )
@@ -48,17 +48,26 @@
}
}
// Mapping not found
- NS_ASSERT_MSG (false, "GetIfIndexByIpv4Address failed");
+ NS_ASSERT_MSG (false, "Ipv4::GetIfIndexByAddress failed");
return 0;
}
+//
+// XXX BUGBUG I don't think this is really the right approach here. The call
+// to GetRoute () filters down into Ipv4L3Protocol where it translates into
+// a call into the Ipv4 static routing package. This bypasses any other
+// routing packages. At a minimum, the name is misleading.
+//
bool
-GetIpv4RouteToDestination (Ptr<Node> node, Ipv4Route& route,
- Ipv4Address a, Ipv4Mask amask)
+Ipv4::GetRouteToDestination (
+ Ptr<Node> node,
+ Ipv4Route& route,
+ Ipv4Address a,
+ Ipv4Mask amask)
{
Ipv4Route tempRoute;
Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
- NS_ASSERT_MSG (ipv4, "GetIpv4RouteToDestination: No Ipv4 interface");
+ NS_ASSERT_MSG (ipv4, "Ipv4::GetRouteToDestination: No Ipv4 interface");
for (uint32_t i = 0; i < ipv4->GetNRoutes (); i++)
{
tempRoute = ipv4->GetRoute (i);
@@ -83,5 +92,4 @@
return false;
}
-
} // namespace ns3
--- a/src/node/ipv4.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/ipv4.h Wed Sep 12 18:06:09 2007 +0100
@@ -71,6 +71,7 @@
/**
* \brief Asynchronously requests a route for a given packet and IP header
*
+ * \param ifIndex The interface index on which the packet was received.
* \param ipHeader IP header of the packet
* \param packet packet that is being sent or forwarded
* \param routeReply callback that will receive the route reply
@@ -100,9 +101,47 @@
* immediately after the IP header, although most routing do not
* insert any extra header.
*/
- virtual bool RequestRoute (const Ipv4Header &ipHeader,
+ virtual bool RequestRoute (uint32_t ifIndex,
+ const Ipv4Header &ipHeader,
Packet packet,
RouteReplyCallback routeReply) = 0;
+
+/**
+ * \brief Synchronously check to see if we can determine the interface index
+ * that will be used if a packet is sent to this destination.
+ *
+ * This method addresses a problem in the IP stack where a destination address
+ * must be present and checksummed into the IP header before the actual
+ * interface over which the packet is sent can be determined. The answer is
+ * to implement a known and intentional cross-layer violation. This is the
+ * endpoint of a call chain that started up quite high in the stack (sockets)
+ * and has found its way down to the Ipv4L3Protocol which is consulting the
+ * routing protocols for what they would do if presented with a packet of the
+ * given destination.
+ *
+ * Note that the a single interface index is returned. This means that if
+ * the destination address is a multicast, and an explicit route is present
+ * that includeds multiple output interfaces, that route cannot be used.
+ *
+ * If there are multiple paths out of the node, the resolution is performed
+ * by Ipv4L3Protocol::GetIfIndexforDestination which has access to more
+ * contextual information that is useful for making a determination.
+ *
+ * \param destination The Ipv4Address if the destination of a hypothetical
+ * packet. This may be a multicast group address.
+ * \param ifIndex A reference to the interface index over which a packet
+ * sent to this destination would be sent.
+ * \return Returns true if a route is found to the destination that involves
+ * a single output interface index, otherwise false.
+ *
+ * \see Ipv4StaticRouting
+ * \see Ipv4RoutingProtocol
+ * \see Ipv4L3Protocol
+ */
+ virtual bool RequestIfIndex (Ipv4Address destination,
+ uint32_t& ifIndex) = 0;
+
+ static const uint32_t IF_INDEX_ANY = 0xffffffff;
};
/**
@@ -194,17 +233,69 @@
* \returns the number of entries in the routing table.
*/
virtual uint32_t GetNRoutes (void) = 0;
+
/**
* \param i index of route to return
* \returns the route whose index is i
*/
virtual Ipv4Route GetRoute (uint32_t i) = 0;
+
/**
* \param i index of route to remove from routing table.
*/
virtual void RemoveRoute (uint32_t i) = 0;
+
+ /**
+ * \brief Add a static multicast route for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ * \param inputInterface The interface index over which the packet arrived.
+ * \param outputInterfaces The list of output interface indices over which
+ * the packet should be sent (excluding the inputInterface).
+ */
+ virtual void AddMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface,
+ std::vector<uint32_t> outputInterfaces) = 0;
+ /**
+ * \brief Remove a static multicast route for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ * \param inputInterface The interface index over which the packet arrived.
+ */
+ virtual void RemoveMulticastRoute (Ipv4Address origin,
+ Ipv4Address group,
+ uint32_t inputInterface) = 0;
/**
+ * \brief Set the default static multicast route.
+ *
+ * \param outputInterface The network output interface index over which
+ * packets without specific routes should be sent.
+ */
+ virtual void SetDefaultMulticastRoute (uint32_t outputInterface) = 0;
+
+ /**
+ * \returns the number of entries in the multicast routing table.
+ */
+ virtual uint32_t GetNMulticastRoutes (void) const = 0;
+
+ /**
+ * \param i index of route to return
+ * \returns the route whose index is i
+ */
+ virtual Ipv4MulticastRoute GetMulticastRoute (uint32_t i) const = 0;
+
+ /**
+ * \param i index of route to remove from routing table.
+ */
+ virtual void RemoveMulticastRoute (uint32_t i) = 0;
+
+ /**
* \param device device to add to the list of ipv4 interfaces
* which can be used as output interfaces during packet forwarding.
* \returns the index of the ipv4 interface added.
@@ -214,49 +305,120 @@
* make sure that it is never used during packet forwarding.
*/
virtual uint32_t AddInterface (Ptr<NetDevice> device) = 0;
+
/**
* \returns the number of interfaces added by the user.
*/
virtual uint32_t GetNInterfaces (void) = 0;
/**
+ * \brief Find and return the interface ID of the interface that has been
+ * assigned the specified IP address.
+ * \param addr The IP address assigned to the interface of interest.
+ * \returns The index of the ipv4 interface with the given address.
+ *
+ * Each IP interface has an IP address associated with it. It is often
+ * useful to search the list of interfaces for one that corresponds to
+ * a known IP Address. This call takes an IP address as a parameter and
+ * returns the interface index of the first interface that has been assigned
+ * that address. If the address is not found, this function asserts.
+ */
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr) const = 0;
+
+ /**
+ * \brief Find and return the interface ID of the interface that has been
+ * assigned the specified (masked) IP address.
+ * \param addr The IP address assigned to the interface of interest.
+ * \param mask The address mask to be used in address matching.
+ * \returns The index of the ipv4 interface with the given address.
+ *
+ * Each IP interface has an IP address associated with it. It is often
+ * useful to search the list of interfaces for one that corresponds to
+ * a known IP Address. This call takes an IP address and an IP address
+ * mask as parameters and returns the interface index of the first interface
+ * that matches the masked IP address.
+ */
+ virtual uint32_t FindInterfaceForAddr (Ipv4Address addr,
+ Ipv4Mask mask) const = 0;
+
+ /**
* \param i index of ipv4 interface
* \returns the NetDevice associated with the ipv4 interface index
*/
virtual Ptr<NetDevice> GetNetDevice (uint32_t i) = 0;
/**
+ * \brief Join a multicast group for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ */
+ virtual void JoinMulticastGroup (Ipv4Address origin, Ipv4Address group) = 0;
+
+ /**
+ * \brief Leave a multicast group for a given multicast source and
+ * group.
+ *
+ * \param origin The Ipv4 address of the multicast source.
+ * \param group The multicast group address.
+ */
+ virtual void LeaveMulticastGroup (Ipv4Address origin, Ipv4Address group) = 0;
+
+ /**
* \param i index of ipv4 interface
* \param address address to associate to the underlying ipv4 interface
*/
virtual void SetAddress (uint32_t i, Ipv4Address address) = 0;
+
/**
* \param i index of ipv4 interface
* \param mask mask to associate to the underlying ipv4 interface
*/
virtual void SetNetworkMask (uint32_t i, Ipv4Mask mask) = 0;
+
/**
* \param i index of ipv4 interface
* \returns the mask associated to the underlying ipv4 interface
*/
virtual Ipv4Mask GetNetworkMask (uint32_t i) const = 0;
+
/**
* \param i index of ipv4 interface
* \returns the address associated to the underlying ipv4 interface
*/
virtual Ipv4Address GetAddress (uint32_t i) const = 0;
+
+ /**
+ * \param destination The IP address of a hypothetical destination.
+ * \returns The IP address assigned to the interface that will be used
+ * if we were to send a packet to destination.
+ */
+ virtual Ipv4Address GetSourceAddress (Ipv4Address destination) const = 0;
+
+ /**
+ * \param destination The IP address of a hypothetical destination.
+ * \param ifIndex filled in with the interface index that will be used to
+ * send a packet to the hypothetical destination.
+ * \returns True if a single interface can be identified, false otherwise.
+ */
+ virtual bool GetIfIndexForDestination (Ipv4Address dest,
+ uint32_t &ifIndex) const = 0;
+
/**
* \param i index of ipv4 interface
* \returns the Maximum Transmission Unit (in bytes) associated
* to the underlying ipv4 interface
*/
virtual uint16_t GetMtu (uint32_t i) const = 0;
+
/**
* \param i index of ipv4 interface
* \returns true if the underlying interface is in the "up" state,
* false otherwise.
*/
virtual bool IsUp (uint32_t i) const = 0;
+
/**
* \param i index of ipv4 interface
*
@@ -264,6 +426,7 @@
* considered valid during ipv4 forwarding.
*/
virtual void SetUp (uint32_t i) = 0;
+
/**
* \param i index of ipv4 interface
*
@@ -271,21 +434,18 @@
* ignored during ipv4 forwarding.
*/
virtual void SetDown (uint32_t i) = 0;
-
-};
/**
* Convenience functions (Doxygen still needed)
*
* Return the ifIndex corresponding to the Ipv4Address provided.
*/
-uint32_t GetIfIndexByIpv4Address (Ptr<Node> node,
- Ipv4Address a,
- Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+ static uint32_t GetIfIndexByAddress (Ptr<Node> node, Ipv4Address a,
+ Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
-bool GetIpv4RouteToDestination (Ptr<Node> node, Ipv4Route& route,
- Ipv4Address a,
- Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+ static bool GetRouteToDestination (Ptr<Node> node, Ipv4Route& route,
+ Ipv4Address a, Ipv4Mask amask = Ipv4Mask("255.255.255.255"));
+};
} // namespace ns3
--- a/src/node/net-device.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/net-device.cc Wed Sep 12 18:06:09 2007 +0100
@@ -114,6 +114,7 @@
{
return m_isBroadcast;
}
+
Address const &
NetDevice::GetBroadcast (void) const
{
@@ -140,10 +141,27 @@
return m_isMulticast;
}
+Address
+NetDevice::GetMulticast (void) const
+{
+ NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+ "Invalid operation when not IsMulticast ()");
+ return m_multicast;
+}
+
+Address
+NetDevice::MakeMulticastAddress(Ipv4Address multicastGroup) const
+{
+ NS_ASSERT_MSG (m_isMulticast, "NetDevice::GetMulticast (): "
+ "Invalid operation when not IsMulticast ()");
+ return m_multicast;
+}
+
void
-NetDevice::EnableMulticast (void)
+NetDevice::EnableMulticast (Address multicast)
{
m_isMulticast = true;
+ m_multicast = multicast;
}
void
--- a/src/node/net-device.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/node/net-device.h Wed Sep 12 18:06:09 2007 +0100
@@ -29,6 +29,7 @@
#include "ns3/object.h"
#include "ns3/ptr.h"
#include "address.h"
+#include "ipv4-address.h"
namespace ns3 {
@@ -130,10 +131,69 @@
* not true.
*/
Address const &GetBroadcast (void) const;
+
/**
* \return value of m_isMulticast flag
*/
bool IsMulticast (void) const;
+
+ /**
+ * \brief Return the MAC multicast base address used when mapping multicast
+ * groups to MAC multicast addresses.
+ *
+ * Typically when one constructs a multicast MAC addresses, some bits from
+ * the IP multicast group are copied into a corresponding MAC multicast
+ * group. In EUI-48, for example, the low order 23 bits of the multicast
+ * group are copied to the MAC multicast group base address.
+ *
+ * This method allows access to the underlying MAC multicast group base
+ * address. It is expected that in most cases, a net device client will
+ * allow the net device to perform the actual construction of the multicast
+ * address. Use of this method is discouraged unless you have a good reason
+ * to perform a custom mapping. You should prefer
+ * NetDevice::MakeMulticastAddress which will do the RFC-specified mapping
+ * for the net device in question.
+ *
+ * \return The multicast address supported by this net device.
+ *
+ * \warning Calling this method is invalid if IsMulticast returns not true.
+ * The method NS_ASSERTs if the device is not a multicast device.
+ * \see NetDevice::MakeMulticastAddress
+ */
+ Address GetMulticast (void) const;
+
+ /**
+ * \brief Make and return a MAC multicast address using the provided
+ * multicast group
+ *
+ * RFC 1112 says that an Ipv4 host group address is mapped to an Ethernet
+ * multicast address by placing the low-order 23-bits of the IP address into
+ * the low-order 23 bits of the Ethernet multicast address
+ * 01-00-5E-00-00-00 (hex). Similar RFCs exist for Ipv6 and Eui64 mappings.
+ * This method performs the multicast address creation function appropriate
+ * to the underlying MAC address of the device. This MAC address is
+ * encapsulated in an abstract Address to avoid dependencies on the exact
+ * MAC address format.
+ *
+ * A default imlementation of MakeMulticastAddress is provided, but this
+ * method simply NS_ASSERTS. In the case of net devices that do not support
+ * multicast, clients are expected to test NetDevice::IsMulticast and avoid
+ * attempting to map multicast packets. Subclasses of NetDevice that do
+ * support multicasting are expected to override this method and provide an
+ * implementation appropriate to the particular device.
+ *
+ * \param multicastGroup The IP address for the multicast group destination
+ * of the packet.
+ * \return The MAC multicast Address used to send packets to the provided
+ * multicast group.
+ *
+ * \warning Calling this method is invalid if IsMulticast returns not true.
+ * \see Ipv4Address
+ * \see Address
+ * \see NetDevice::IsMulticast
+ */
+ virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
/**
* \return value of m_isPointToPoint flag
*/
@@ -204,9 +264,10 @@
*/
void DisableBroadcast (void);
/**
- * Set m_isMulticast flag to true
+ * Enable multicast support. This method should be
+ * called by subclasses from their constructor
*/
- void EnableMulticast (void);
+ void EnableMulticast (Address multicast);
/**
* Set m_isMulticast flag to false
*/
@@ -286,6 +347,7 @@
uint16_t m_ifIndex;
Address m_address;
Address m_broadcast;
+ Address m_multicast;
uint16_t m_mtu;
bool m_isUp;
bool m_isBroadcast;
--- a/src/routing/global-routing/candidate-queue.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/candidate-queue.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,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 (craigdo@ee.washington.edu)
*/
#include "ns3/debug.h"
--- a/src/routing/global-routing/candidate-queue.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/candidate-queue.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,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 (craigdo@ee.washington.edu)
*/
#ifndef CANDIDATE_QUEUE_H
--- a/src/routing/global-routing/global-route-manager-impl.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager-impl.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,8 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 2007 University of Washington
+ * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
+ *
* 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;
@@ -12,6 +15,12 @@
* 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: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
+ *
+ * Kunihiro Ishigura, Toshiaki Takada (GNU Zebra) are attributed authors
+ * of the quagga 0.99.7/src/ospfd/ospf_spf.c code which was ported here
*/
#include <utility>
@@ -1143,7 +1152,7 @@
// we're looking for. If we find one, return the corresponding interface
// index.
//
- return (GetIfIndexByIpv4Address (node, a, amask) );
+ return (Ipv4::GetIfIndexByAddress (node, a, amask) );
}
}
//
--- a/src/routing/global-routing/global-route-manager-impl.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager-impl.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,9 @@
* 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: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
*/
#ifndef GLOBAL_ROUTE_MANAGER_IMPL_H
--- a/src/routing/global-routing/global-route-manager.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,9 @@
* 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: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
*/
#include "ns3/assert.h"
--- a/src/routing/global-routing/global-route-manager.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-route-manager.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,9 @@
* 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: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
*/
#ifndef GLOBAL_ROUTE_MANAGER_H
--- a/src/routing/global-routing/global-router-interface.cc Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-router-interface.cc Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,9 @@
* 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: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
*/
#include "ns3/debug.h"
--- a/src/routing/global-routing/global-router-interface.h Tue Sep 11 15:09:55 2007 +0100
+++ b/src/routing/global-routing/global-router-interface.h Wed Sep 12 18:06:09 2007 +0100
@@ -1,5 +1,7 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
+ * Copyright 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;
@@ -12,6 +14,9 @@
* 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: Craig Dowell (craigdo@ee.washington.edu)
+ * Tom Henderson (tomhend@u.washington.edu)
*/
#ifndef GLOBAL_ROUTER_INTERFACE_H