Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
8c759dff599e22578d422b4ad68dfb375f96e07d
[simgrid.git] / src / surf / ns3 / my-point-to-point-helper.cc
1 /* Copyright (c) 2011, 2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 /*
8  * Copyright (c) 2008 INRIA
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation;
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
24  */
25
26 #include "ns3/abort.h"
27 #include "ns3/log.h"
28 #include "ns3/simulator.h"
29 #include "ns3/point-to-point-net-device.h"
30 #include "ns3/point-to-point-channel.h"
31 #include "ns3/point-to-point-remote-channel.h"
32 #include "ns3/queue.h"
33 #include "ns3/config.h"
34 #include "ns3/packet.h"
35 #include "ns3/names.h"
36 #include "ns3/string.h"
37 #include "ns3/mpi-interface.h"
38 #include "ns3/mpi-receiver.h"
39
40 #include "ns3/trace-helper.h"
41 #include "my-point-to-point-helper.h"
42
43 NS_LOG_COMPONENT_DEFINE ("MyPointToPointHelper");
44
45 ///> RED Parameters  see src/node/red-queue.* for details
46 //.AddAttribute ("Mode",
47 //                "Whether to use Bytes (see MaxBytes) or Packets (see MaxPackets) as the maximum queue size metric.",
48 //                EnumValue (BYTES), ///> currently supports BYTES only
49 //                MakeEnumAccessor (&RedQueue::SetMode),
50 //                MakeEnumChecker (BYTES, "Bytes",
51 //                                 PACKETS, "Packets"))
52 // .AddAttribute ("MaxPackets",
53 //                "The maximum number of packets accepted by this RedQueue.",
54 //                UintegerValue (100),
55 //                MakeUintegerAccessor (&RedQueue::m_maxPackets),
56 //                MakeUintegerChecker<uint32_t> ())
57 // .AddAttribute ("MaxBytes",
58 //                "The maximum number of bytes accepted by this RedQueue.",
59 //                UintegerValue (100000),
60 //                MakeUintegerAccessor (&RedQueue::m_maxBytes),
61 //                MakeUintegerChecker<uint32_t> ())
62 // .AddAttribute ("m_burst",
63 //                "maximum number of m_burst packets accepted by this queue",
64 //                UintegerValue (6), ///> bursts must be > minTh/avpkt
65 //                MakeUintegerAccessor (&RedQueue::m_burst),
66 //                MakeUintegerChecker<uint32_t> ())
67 // .AddAttribute ("m_avPkt",
68 //                "In bytes, use with m_burst to determine the time constant for average queue size calculations",
69 //                UintegerValue (1024), ///> average packet size
70 //                MakeUintegerAccessor (&RedQueue::m_avPkt),
71 //                MakeUintegerChecker<uint32_t> ())
72 // .AddAttribute ("m_minTh",
73 //                "Average queue size at which marking becomes a m_prob",
74 //                UintegerValue (5120), ///> in bytes  1024x5
75 //                MakeUintegerAccessor (&RedQueue::m_minTh),
76 //                MakeUintegerChecker<uint32_t> ())
77 // .AddAttribute ("m_maxTh",
78 //                "Maximal marking m_prob, should be at least twice min to prevent synchronous retransmits",
79 //                UintegerValue (15360), ///> in bytes 1024x15
80 //                MakeUintegerAccessor (&RedQueue::m_maxTh),
81 //                MakeUintegerChecker<uint32_t> ())
82 // .AddAttribute ("m_rate",
83 //                "this m_rate is used for calculating the average queue size after some idle time.",
84 //                UintegerValue (1500000), ///> in bps, should be set to bandwidth of interface
85 //                MakeUintegerAccessor (&RedQueue::m_rate),
86 //                MakeUintegerChecker<uint64_t> ())
87 // .AddAttribute ("m_prob",
88 //                "Probability for marking, suggested values are 0.01 and 0.02",
89 //                DoubleValue (0.02),
90 //                MakeDoubleAccessor (&RedQueue::m_prob),
91 //                MakeDoubleChecker <double> ())
92 std::string qMode = "Bytes";
93 std::string qBurst = "6";
94 std::string qAvPkt = "1024";
95 std::string qLimit = "25600"; //"100000";
96 std::string qthMin = "5120";  // 1024 x 5 bytes
97 std::string qthMax = "15360"; // 1024 x 15 bytes
98 std::string qIdleRate = "1500000";  //1.5 Mbps
99 std::string qProb = "0.02";
100
101 namespace ns3 {
102
103 MyPointToPointHelper::MyPointToPointHelper ()
104 {
105   m_queueFactory.SetTypeId ("ns3::DropTailQueue");
106   m_queueFactory_red.SetTypeId ("ns3::RedQueue");
107 //  m_queueFactory_red.Set ("Mode",    StringValue (qMode));
108 //  m_queueFactory_red.Set ("MaxBytes",StringValue (qLimit));
109 //  m_queueFactory_red.Set ("m_burst", StringValue (qBurst));
110 //  m_queueFactory_red.Set ("m_avPkt", StringValue (qAvPkt));
111 //  m_queueFactory_red.Set ("m_minTh", StringValue (qthMin));
112 //  m_queueFactory_red.Set ("m_maxTh", StringValue (qthMax));
113 //  m_queueFactory_red.Set ("m_rate",  StringValue (qIdleRate));
114 //  m_queueFactory_red.Set ("m_prob",  StringValue (qProb));
115   m_deviceFactory.SetTypeId ("ns3::PointToPointNetDevice");
116   m_channelFactory.SetTypeId ("ns3::PointToPointChannel");
117   m_remoteChannelFactory.SetTypeId ("ns3::PointToPointRemoteChannel");
118 }
119
120 void 
121 MyPointToPointHelper::SetQueue (std::string type,
122                               std::string n1, const AttributeValue &v1,
123                               std::string n2, const AttributeValue &v2,
124                               std::string n3, const AttributeValue &v3,
125                               std::string n4, const AttributeValue &v4,
126                               std::string n5, const AttributeValue &v5,
127                               std::string n6, const AttributeValue &v6,
128                               std::string n7, const AttributeValue &v7,
129                               std::string n8, const AttributeValue &v8)
130 {
131   m_queueFactory.SetTypeId (type);
132   m_queueFactory.Set (n1, v1);
133   m_queueFactory.Set (n2, v2);
134   m_queueFactory.Set (n3, v3);
135   m_queueFactory.Set (n4, v4);
136   m_queueFactory.Set (n5, v5);
137   m_queueFactory.Set (n6, v6);
138   m_queueFactory.Set (n7, v7);
139   m_queueFactory.Set (n8, v8);
140 }
141
142 void 
143 MyPointToPointHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1)
144 {
145   m_deviceFactory.Set (n1, v1);
146 }
147
148 void 
149 MyPointToPointHelper::SetChannelAttribute (std::string n1, const AttributeValue &v1)
150 {
151   m_channelFactory.Set (n1, v1);
152   m_remoteChannelFactory.Set (n1, v1);
153 }
154
155 void 
156 MyPointToPointHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)
157 {
158   //
159   // All of the Pcap enable functions vector through here including the ones
160   // that are wandering through all of devices on perhaps all of the nodes in
161   // the system.  We can only deal with devices of type PointToPointNetDevice.
162   //
163   Ptr<PointToPointNetDevice> device = nd->GetObject<PointToPointNetDevice> ();
164   if (device == 0)
165     {
166       NS_LOG_INFO ("MyPointToPointHelper::EnablePcapInternal(): Device " << device << " not of type ns3::PointToPointNetDevice");
167       return;
168     }
169
170   PcapHelper pcapHelper;
171
172   std::string filename;
173   if (explicitFilename)
174     {
175       filename = prefix;
176     }
177   else
178     {
179       filename = pcapHelper.GetFilenameFromDevice (prefix, device);
180     }
181
182   Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, 
183                                                      PcapHelper::DLT_PPP);
184   pcapHelper.HookDefaultSink<PointToPointNetDevice> (device, "PromiscSniffer", file);
185 }
186
187 void 
188 MyPointToPointHelper::EnableAsciiInternal (
189   Ptr<OutputStreamWrapper> stream, 
190   std::string prefix, 
191   Ptr<NetDevice> nd,
192   bool explicitFilename)
193 {
194   //
195   // All of the ascii enable functions vector through here including the ones
196   // that are wandering through all of devices on perhaps all of the nodes in
197   // the system.  We can only deal with devices of type PointToPointNetDevice.
198   //
199   Ptr<PointToPointNetDevice> device = nd->GetObject<PointToPointNetDevice> ();
200   if (device == 0)
201     {
202       NS_LOG_INFO ("MyPointToPointHelper::EnableAsciiInternal(): Device " << device <<
203                    " not of type ns3::PointToPointNetDevice");
204       return;
205     }
206
207   //
208   // Our default trace sinks are going to use packet printing, so we have to 
209   // make sure that is turned on.
210   //
211   Packet::EnablePrinting ();
212
213   //
214   // If we are not provided an OutputStreamWrapper, we are expected to create 
215   // one using the usual trace filename conventions and do a Hook*WithoutContext
216   // since there will be one file per context and therefore the context would
217   // be redundant.
218   //
219   if (stream == 0)
220     {
221       //
222       // Set up an output stream object to deal with private ofstream copy 
223       // constructor and lifetime issues.  Let the helper decide the actual
224       // name of the file given the prefix.
225       //
226       AsciiTraceHelper asciiTraceHelper;
227
228       std::string filename;
229       if (explicitFilename)
230         {
231           filename = prefix;
232         }
233       else
234         {
235           filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
236         }
237
238       Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
239
240       //
241       // The MacRx trace source provides our "r" event.
242       //
243       asciiTraceHelper.HookDefaultReceiveSinkWithoutContext<PointToPointNetDevice> (device, "MacRx", theStream);
244
245       //
246       // The "+", '-', and 'd' events are driven by trace sources actually in the
247       // transmit queue.
248       //
249       Ptr<Queue> queue = device->GetQueue ();
250       asciiTraceHelper.HookDefaultEnqueueSinkWithoutContext<Queue> (queue, "Enqueue", theStream);
251       asciiTraceHelper.HookDefaultDropSinkWithoutContext<Queue> (queue, "Drop", theStream);
252       asciiTraceHelper.HookDefaultDequeueSinkWithoutContext<Queue> (queue, "Dequeue", theStream);
253
254       // PhyRxDrop trace source for "d" event
255       asciiTraceHelper.HookDefaultDropSinkWithoutContext<PointToPointNetDevice> (device, "PhyRxDrop", theStream);
256
257       return;
258     }
259
260   //
261   // If we are provided an OutputStreamWrapper, we are expected to use it, and
262   // to providd a context.  We are free to come up with our own context if we
263   // want, and use the AsciiTraceHelper Hook*WithContext functions, but for 
264   // compatibility and simplicity, we just use Config::Connect and let it deal
265   // with the context.
266   //
267   // Note that we are going to use the default trace sinks provided by the 
268   // ascii trace helper.  There is actually no AsciiTraceHelper in sight here,
269   // but the default trace sinks are actually publicly available static 
270   // functions that are always there waiting for just such a case.
271   //
272   uint32_t nodeid = nd->GetNode ()->GetId ();
273   uint32_t deviceid = nd->GetIfIndex ();
274   std::ostringstream oss;
275
276   oss << "/NodeList/" << nd->GetNode ()->GetId () << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/MacRx";
277   Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultReceiveSinkWithContext, stream));
278
279   oss.str ("");
280   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Enqueue";
281   Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultEnqueueSinkWithContext, stream));
282
283   oss.str ("");
284   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Dequeue";
285   Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDequeueSinkWithContext, stream));
286
287   oss.str ("");
288   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Drop";
289   Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
290
291   oss.str ("");
292   oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/PhyRxDrop";
293   Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
294 }
295
296 NetDeviceContainer 
297 MyPointToPointHelper::Install (NodeContainer c)
298 {
299   NS_ASSERT (c.GetN () == 2);
300   return Install (c.Get (0), c.Get (1));
301 }
302
303 NetDeviceContainer 
304 MyPointToPointHelper::Install (Ptr<Node> a, e_ns3_network_element_type_t type_a, Ptr<Node> b, e_ns3_network_element_type_t type_b)
305 {
306   NetDeviceContainer container;
307   Ptr<Queue> queueA;
308   Ptr<Queue> queueB;
309
310   Ptr<PointToPointNetDevice> devA = m_deviceFactory.Create<PointToPointNetDevice> ();
311   devA->SetAddress (Mac48Address::Allocate ());
312   a->AddDevice (devA);
313
314   if(type_a == NS3_NETWORK_ELEMENT_ROUTER){
315         queueA = m_queueFactory_red.Create<Queue> ();
316   }
317   else
318           queueA = m_queueFactory.Create<Queue> ();
319   devA->SetQueue (queueA);
320
321   Ptr<PointToPointNetDevice> devB = m_deviceFactory.Create<PointToPointNetDevice> ();
322   devB->SetAddress (Mac48Address::Allocate ());
323   b->AddDevice (devB);
324
325   if(type_b == NS3_NETWORK_ELEMENT_ROUTER){
326         queueB = m_queueFactory_red.Create<Queue> ();
327   }
328   else
329           queueB = m_queueFactory.Create<Queue> ();
330   devB->SetQueue (queueB);
331
332   // If MPI is enabled, we need to see if both nodes have the same system id 
333   // (rank), and the rank is the same as this instance.  If both are true, 
334   //use a normal p2p channel, otherwise use a remote channel
335   bool useNormalChannel = true;
336   Ptr<PointToPointChannel> channel = 0;
337   if (MpiInterface::IsEnabled ())
338     {
339       uint32_t n1SystemId = a->GetSystemId ();
340       uint32_t n2SystemId = b->GetSystemId ();
341       uint32_t currSystemId = MpiInterface::GetSystemId ();
342       if (n1SystemId != currSystemId || n2SystemId != currSystemId) 
343         {
344           useNormalChannel = false;
345         }
346     }
347   if (useNormalChannel)
348     {
349       channel = m_channelFactory.Create<PointToPointChannel> ();
350     }
351   else
352     {
353       channel = m_remoteChannelFactory.Create<PointToPointRemoteChannel> ();
354       Ptr<MpiReceiver> mpiRecA = CreateObject<MpiReceiver> ();
355       Ptr<MpiReceiver> mpiRecB = CreateObject<MpiReceiver> ();
356       mpiRecA->SetReceiveCallback (MakeCallback (&PointToPointNetDevice::Receive, devA));
357       mpiRecB->SetReceiveCallback (MakeCallback (&PointToPointNetDevice::Receive, devB));
358       devA->AggregateObject (mpiRecA);
359       devB->AggregateObject (mpiRecB);
360     }
361
362   devA->Attach (channel);
363   devB->Attach (channel);
364   container.Add (devA);
365   container.Add (devB);
366
367   return container;
368 }
369
370 NetDeviceContainer 
371 MyPointToPointHelper::Install (Ptr<Node> a, Ptr<Node> b)
372 {
373   NetDeviceContainer container;
374
375   Ptr<PointToPointNetDevice> devA = m_deviceFactory.Create<PointToPointNetDevice> ();
376   devA->SetAddress (Mac48Address::Allocate ());
377   a->AddDevice (devA);
378   Ptr<Queue> queueA = m_queueFactory.Create<Queue> ();
379   devA->SetQueue (queueA);
380   Ptr<PointToPointNetDevice> devB = m_deviceFactory.Create<PointToPointNetDevice> ();
381   devB->SetAddress (Mac48Address::Allocate ());
382   b->AddDevice (devB);
383   Ptr<Queue> queueB = m_queueFactory.Create<Queue> ();
384   devB->SetQueue (queueB);
385   // If MPI is enabled, we need to see if both nodes have the same system id
386   // (rank), and the rank is the same as this instance.  If both are true,
387   //use a normal p2p channel, otherwise use a remote channel
388   bool useNormalChannel = true;
389   Ptr<PointToPointChannel> channel = 0;
390   if (MpiInterface::IsEnabled ())
391     {
392       uint32_t n1SystemId = a->GetSystemId ();
393       uint32_t n2SystemId = b->GetSystemId ();
394       uint32_t currSystemId = MpiInterface::GetSystemId ();
395       if (n1SystemId != currSystemId || n2SystemId != currSystemId)
396         {
397           useNormalChannel = false;
398         }
399     }
400   if (useNormalChannel)
401     {
402       channel = m_channelFactory.Create<PointToPointChannel> ();
403     }
404   else
405     {
406       channel = m_remoteChannelFactory.Create<PointToPointRemoteChannel> ();
407       Ptr<MpiReceiver> mpiRecA = CreateObject<MpiReceiver> ();
408       Ptr<MpiReceiver> mpiRecB = CreateObject<MpiReceiver> ();
409       mpiRecA->SetReceiveCallback (MakeCallback (&PointToPointNetDevice::Receive, devA));
410       mpiRecB->SetReceiveCallback (MakeCallback (&PointToPointNetDevice::Receive, devB));
411       devA->AggregateObject (mpiRecA);
412       devB->AggregateObject (mpiRecB);
413     }
414
415   devA->Attach (channel);
416   devB->Attach (channel);
417   container.Add (devA);
418   container.Add (devB);
419
420   return container;
421 }
422
423 NetDeviceContainer
424 MyPointToPointHelper::Install (Ptr<Node> a, std::string bName)
425 {
426   Ptr<Node> b = Names::Find<Node> (bName);
427   return Install (a, b);
428 }
429
430 NetDeviceContainer 
431 MyPointToPointHelper::Install (std::string aName, Ptr<Node> b)
432 {
433   Ptr<Node> a = Names::Find<Node> (aName);
434   return Install (a, b);
435 }
436
437 NetDeviceContainer 
438 MyPointToPointHelper::Install (std::string aName, std::string bName)
439 {
440   Ptr<Node> a = Names::Find<Node> (aName);
441   Ptr<Node> b = Names::Find<Node> (bName);
442   return Install (a, b);
443 }
444
445 } // namespace ns3