blob: cf5759f8fb7fb8de769b7ba5bd7a66c5e9dc0f26 [file] [log] [blame]
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Alexander Afanasyev45b92d42011-08-14 23:11:38 -07002/*
3 * Copyright (c) 2011 UCLA
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -070018 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
Ilya Moiseenkofbd0a8b2011-10-28 13:07:16 -070019 * Ilya Moiseenko <iliamo@cs.ucla.edu>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070020 */
21
22/**
23 * \ingroup ccnx
24 * \defgroup CcnxStackModel Ccnx Stack Model
25 *
26 * \section CcnxStackTracingModel Tracing in the Ccnx Stack
27 *
28 * The ccnx stack provides a number of trace sources in its various
29 * protocol implementations. These trace sources can be hooked using your own
30 * custom trace code, or you can use our helper functions in some cases to
31 * arrange for tracing to be enabled.
32 *
33 * \subsection CcnxStackCcnxTracingModel Tracing in Ccnx
34 *
35 * The Ccnx layer three protocol provides three trace hooks. These are the
36 * "Tx" (ns3::CcnxL3Protocol::m_txTrace), "Rx" (ns3::CcnxL3Protocol::m_rxTrace)
37 * and "Drop" (ns3::CcnxL3Protocol::m_dropTrace) trace sources.
38 *
39 * The "Tx" trace is fired in a number of situations, all of which indicate that
40 * a given packet is about to be sent down to a given ns3::CcnxFace.
41 *
42 * - \todo list Tx trace events
43 *
44 * The "Rx" trace is fired when a packet is passed from the device up to the
45 * ns3::CcnxL3Protocol::Receive function.
46 *
47 * - In the receive function, the CcnxFaceList is iterated, and if the
48 * CcnxFace corresponding to the receiving device is found to be in the
49 * UP state, the trace is fired.
50 *
51 * The "Drop" trace is fired in any case where the packet is dropped (in both
52 * the transmit and receive paths).
53 *
54 * - \todo list Drop trace events
55 */
56
57#include "ns3/assert.h"
58#include "ns3/log.h"
59#include "ns3/object.h"
60#include "ns3/names.h"
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070061#include "ns3/packet-socket-factory.h"
62#include "ns3/config.h"
63#include "ns3/simulator.h"
64#include "ns3/string.h"
65#include "ns3/net-device.h"
66#include "ns3/callback.h"
67#include "ns3/node.h"
68#include "ns3/core-config.h"
Alexander Afanasyevc74a6022011-08-15 20:01:35 -070069#include "ns3/ccnx-forwarding-strategy.h"
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -070070#include "ns3/ccnx-net-device-face.h"
71#include "ns3/ccnx-l3-protocol.h"
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -070072#include "ns3/ccnx-fib.h"
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070073
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -070074#include "ccnx-face-container.h"
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070075#include "ccnx-stack-helper.h"
76#include "ccnx-forwarding-helper.h"
77
78#include <limits>
79#include <map>
80
81NS_LOG_COMPONENT_DEFINE ("CcnxStackHelper");
82
83namespace ns3 {
84
85// Things are going to work differently here with respect to trace
86// file handling than in most places because the Tx and Rx trace
87// sources we are interested in are going to multiplex receive and
88// transmit callbacks for all Ccnx and face pairs through one
89// callback. We want packets to or from each distinct pair to go to
90// an individual file, so we have got to demultiplex the Ccnx and face
91// pair into a corresponding Ptr<PcapFileWrapper> at the callback.
92//
93// A complication in this situation is that the trace sources are
94// hooked on a protocol basis. There is no trace source hooked by an
95// Ccnx and face pair. This means that if we naively proceed to hook,
96// say, a drop trace for a given Ccnx with face 0, and then hook for
97// Ccnx with face 1 we will hook the drop trace twice and get two
98// callbacks per event. What we need to do is to hook the event once,
99// and that will result in a single callback per drop event, and the
100// trace source will provide the face which we filter on in the trace
101// sink.
102//
103// This has got to continue to work properly after the helper has been
104// destroyed; but must be cleaned up at the end of time to avoid
105// leaks. Global maps of protocol/face pairs to file objects seems to
106// fit the bill.
107//
108typedef std::pair<Ptr<Ccnx>, uint32_t> FacePairCcnx;
109typedef std::map<FacePairCcnx, Ptr<PcapFileWrapper> > FaceFileMapCcnx;
110typedef std::map<FacePairCcnx, Ptr<OutputStreamWrapper> > FaceStreamMapCcnx;
111
112static FaceFileMapCcnx g_faceFileMapCcnx; /**< A mapping of Ccnx/face pairs to pcap files */
113static FaceStreamMapCcnx g_faceStreamMapCcnx; /**< A mapping of Ccnx/face pairs to ascii streams */
114
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700115
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700116CcnxStackHelper::CcnxStackHelper ()
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700117 : m_forwardingHelper (Ccnx::NDN_FLOODING)
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700118{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700119}
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700120
121CcnxStackHelper::CcnxStackHelper (Ccnx::ForwardingStrategy strategy)
122 : m_forwardingHelper (strategy)
123{
124}
125
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700126CcnxStackHelper::~CcnxStackHelper ()
127{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700128}
129
130CcnxStackHelper::CcnxStackHelper (const CcnxStackHelper &o)
131{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700132}
133
134CcnxStackHelper &
135CcnxStackHelper::operator = (const CcnxStackHelper &o)
136{
137 if (this == &o)
138 {
139 return *this;
140 }
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700141 return *this;
142}
143
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700144void
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700145CcnxStackHelper::SetForwardingStrategy (Ccnx::ForwardingStrategy strategy)
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700146{
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700147 CcnxForwardingHelper newForwardingHelper (strategy);
148 m_forwardingHelper = newForwardingHelper;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700149}
150
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700151Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700152CcnxStackHelper::Install (NodeContainer c) const
153{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700154 Ptr<CcnxFaceContainer> faces = Create<CcnxFaceContainer> ();
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700155 for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
156 {
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700157 faces->AddAll (Install (*i));
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700158 }
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700159 return faces;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700160}
161
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700162Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700163CcnxStackHelper::InstallAll (void) const
164{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700165 return Install (NodeContainer::GetGlobal ());
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700166}
167
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700168// void
169// CcnxStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId)
170// {
171// ObjectFactory factory;
172// factory.SetTypeId (typeId);
173// Ptr<Object> protocol = factory.Create <Object> ();
174// node->AggregateObject (protocol);
175// }
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700176
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700177Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700178CcnxStackHelper::Install (Ptr<Node> node) const
179{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700180 // NS_ASSERT_MSG (m_forwarding, "SetForwardingHelper() should be set prior calling Install() method");
181 Ptr<CcnxFaceContainer> faces = Create<CcnxFaceContainer> ();
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700182
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700183 if (node->GetObject<Ccnx> () != 0)
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700184 {
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700185 NS_FATAL_ERROR ("CcnxStackHelper::Install (): Installing "
186 "a CcnxStack to a node with an existing Ccnx object");
187 return 0;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700188 }
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700189
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700190 Ptr<CcnxFib> fib = CreateObject<CcnxFib> ();
191 node->AggregateObject (fib);
192
Ilya Moiseenkofbd0a8b2011-10-28 13:07:16 -0700193 Ptr<CcnxL3Protocol> ccnx = CreateObject<CcnxL3Protocol> ();
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700194 node->AggregateObject (ccnx);
195
Ilya Moiseenkofbd0a8b2011-10-28 13:07:16 -0700196 Ptr<CcnxPit> pit = ccnx->GetPit();
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800197 NS_LOG_INFO("NODE->GetNDevices()="<<node->GetNDevices());
198
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700199 for (uint32_t index=0; index < node->GetNDevices (); index++)
200 {
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800201 Ptr<PointToPointNetDevice> device = DynamicCast<PointToPointNetDevice>(node->GetDevice(index));
202 if(device == 0)
203 continue;
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700204
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700205 Ptr<CcnxNetDeviceFace> face = Create<CcnxNetDeviceFace> (node->GetDevice (index));
206 face->SetNode (node);
207 uint32_t __attribute__ ((unused)) face_id = ccnx->AddFace (face);
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700208 NS_LOG_LOGIC ("Node " << node->GetId () << ": added CcnxNetDeviceFace as face #" << face_id);
Ilya Moiseenkofbd0a8b2011-10-28 13:07:16 -0700209 // Setup bucket filtering
210 // Assume that we know average data packet size, and this size is equal default size
211 // Set maximum buckets (averaging over 1 second)
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700212
Ilya Moiseenkofbd0a8b2011-10-28 13:07:16 -0700213 DataRateValue dataRate;
214 device->GetAttribute ("DataRate", dataRate);
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700215 NS_LOG_INFO("DataRate for this link is " << dataRate.Get());
216 pit->maxBucketsPerFace[face->GetId()] = 0.1 * dataRate.Get().GetBitRate () / 8 /(NDN_DEFAULT_DATA_SIZE + sizeof(CcnxInterestHeader));
217 NS_LOG_INFO("maxBucketsPerFace["<<face->GetId()<<"] = " << pit->maxBucketsPerFace[face->GetId()]);
Ilya Moiseenkofbd0a8b2011-10-28 13:07:16 -0700218 pit->leakSize[face->GetId()] = 0.97 * NDN_INTEREST_RESET_PERIOD / SECOND * dataRate.Get().GetBitRate () / 8 / (NDN_DEFAULT_DATA_SIZE + sizeof(CcnxInterestHeader));
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700219 NS_LOG_INFO("pit->leakSize["<<face->GetId()<<"] = " << pit->leakSize[face->GetId()]);
220
221
222 if(face->IsLocal()==true)
223 NS_LOG_INFO("Face #" << face_id << " is turned on");
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700224 face->SetUp ();
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700225 faces->Add (face);
226 }
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700227
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700228 m_forwardingHelper.SetForwarding (ccnx, pit);
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700229
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700230 return faces;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700231}
232
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700233Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700234CcnxStackHelper::Install (std::string nodeName) const
235{
236 Ptr<Node> node = Names::Find<Node> (nodeName);
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700237 return Install (node);
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700238}
239
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700240
241void
242CcnxStackHelper::AddRoute (std::string nodeName, std::string prefix, uint32_t faceId, int32_t metric)
243{
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800244 NS_LOG_FUNCTION(this << nodeName << prefix << faceId << metric);
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700245 NS_LOG_LOGIC ("[" << nodeName << "]$ route add " << prefix << " via " << faceId << " metric " << metric);
246
247 Ptr<Node> node = Names::Find<Node> (nodeName);
248 NS_ASSERT_MSG (node != 0, "Node [" << nodeName << "] does not exist");
249
250 Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
251 Ptr<CcnxFib> fib = node->GetObject<CcnxFib> ();
252 Ptr<CcnxFace> face = ccnx->GetFace (faceId);
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800253 NS_ASSERT_MSG (face != 0, "Face with ID [" << faceId << "] does not exist on node [" << nodeName << "]");
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700254
255 CcnxNameComponentsValue prefixValue;
256 prefixValue.DeserializeFromString (prefix, MakeCcnxNameComponentsChecker ());
257 fib->Add (prefixValue.Get (), face, metric);
258}
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800259
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700260void
261CcnxStackHelper::AddRoute (Ptr<Node> node, std::string prefix, uint32_t faceId, int32_t metric)
262{
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800263 NS_LOG_FUNCTION(this << node << prefix << faceId << metric);
264 NS_LOG_LOGIC ("[" << node->GetId () << "]$ route add " << prefix << " via " << faceId << " metric " << metric);
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700265
266 NS_ASSERT_MSG (node != 0, "Node does not exist");
267
268 Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
269 Ptr<CcnxFib> fib = node->GetObject<CcnxFib> ();
270 Ptr<CcnxFace> face = ccnx->GetFace (faceId);
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800271 NS_ASSERT_MSG (face != NULL, "Face with ID [" << faceId << "] does not exist on node [" << node->GetId () << "]");
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700272
273 CcnxNameComponentsValue prefixValue;
274 prefixValue.DeserializeFromString (prefix, MakeCcnxNameComponentsChecker ());
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800275 NS_ASSERT_MSG (face != NULL, "Face with ID [" << faceId << "] does not exist on node [" << node->GetId () << "]");
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700276 fib->Add (prefixValue.Get (), face, metric);
277}
Ilya Moiseenkoae394872011-11-15 17:56:36 -0800278
Ilya Moiseenkoc9266042011-11-02 17:49:21 -0700279
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700280static void
281CcnxL3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ccnx> ccnx, uint32_t face)
282{
283 NS_LOG_FUNCTION (p << ccnx << face);
284
285 //
286 // Since trace sources are independent of face, if we hook a source
287 // on a particular protocol we will get traces for all of its faces.
288 // We need to filter this to only report faces for which the user
289 // has expressed interest.
290 //
291 FacePairCcnx pair = std::make_pair (ccnx, face);
292 if (g_faceFileMapCcnx.find (pair) == g_faceFileMapCcnx.end ())
293 {
294 NS_LOG_INFO ("Ignoring packet to/from face " << face);
295 return;
296 }
297
298 Ptr<PcapFileWrapper> file = g_faceFileMapCcnx[pair];
299 file->Write (Simulator::Now (), p);
300}
301
302bool
303CcnxStackHelper::PcapHooked (Ptr<Ccnx> ccnx)
304{
305 for (FaceFileMapCcnx::const_iterator i = g_faceFileMapCcnx.begin ();
306 i != g_faceFileMapCcnx.end ();
307 ++i)
308 {
309 if ((*i).first.first == ccnx)
310 {
311 return true;
312 }
313 }
314 return false;
315}
316
317void
318CcnxStackHelper::EnablePcapCcnxInternal (std::string prefix, Ptr<Ccnx> ccnx, uint32_t face, bool explicitFilename)
319{
320 NS_LOG_FUNCTION (prefix << ccnx << face);
321
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700322 //
323 // We have to create a file and a mapping from protocol/face to file
324 // irrespective of how many times we want to trace a particular protocol.
325 //
326 PcapHelper pcapHelper;
327
328 std::string filename;
329 if (explicitFilename)
330 {
331 filename = prefix;
332 }
333 else
334 {
335 filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
336 }
337
338 Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
339
340 //
341 // However, we only hook the trace source once to avoid multiple trace sink
342 // calls per event (connect is independent of face).
343 //
344 if (!PcapHooked (ccnx))
345 {
346 //
347 // Ptr<Ccnx> is aggregated to node and CcnxL3Protocol is aggregated to
348 // node so we can get to CcnxL3Protocol through Ccnx.
349 //
350 Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
351 NS_ASSERT_MSG (ccnxL3Protocol, "CcnxStackHelper::EnablePcapCcnxInternal(): "
352 "m_ccnxEnabled and ccnxL3Protocol inconsistent");
353
354 bool result = ccnxL3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&CcnxL3ProtocolRxTxSink));
355 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal(): "
356 "Unable to connect ccnxL3Protocol \"Tx\"");
357
358 result = ccnxL3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&CcnxL3ProtocolRxTxSink));
359 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal(): "
360 "Unable to connect ccnxL3Protocol \"Rx\"");
361 // cast result to void, to suppress ‘result’ set but not used compiler-warning
362 // for optimized builds
363 (void) result;
364 }
365
366 g_faceFileMapCcnx[std::make_pair (ccnx, face)] = file;
367}
368
369static void
370CcnxL3ProtocolDropSinkWithoutContext (
371 Ptr<OutputStreamWrapper> stream,
372 Ptr<const Packet> packet,
373 CcnxL3Protocol::DropReason reason,
374 Ptr<Ccnx> ccnx,
375 uint32_t face)
376{
377 //
378 // Since trace sources are independent of face, if we hook a source
379 // on a particular protocol we will get traces for all of its faces.
380 // We need to filter this to only report faces for which the user
381 // has expressed interest.
382 //
383 FacePairCcnx pair = std::make_pair (ccnx, face);
384 if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
385 {
386 NS_LOG_INFO ("Ignoring packet to/from face " << face);
387 return;
388 }
389
390 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
391}
392
393static void
394CcnxL3ProtocolDropSinkWithContext (
395 Ptr<OutputStreamWrapper> stream,
396 std::string context,
397 Ptr<const Packet> packet,
398 CcnxL3Protocol::DropReason reason,
399 Ptr<Ccnx> ccnx,
400 uint32_t face)
401{
402 //
403 // Since trace sources are independent of face, if we hook a source
404 // on a particular protocol we will get traces for all of its faces.
405 // We need to filter this to only report faces for which the user
406 // has expressed interest.
407 //
408 FacePairCcnx pair = std::make_pair (ccnx, face);
409 if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
410 {
411 NS_LOG_INFO ("Ignoring packet to/from face " << face);
412 return;
413 }
414
415 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << face << ") "
416 << *packet << std::endl;
417}
418
419bool
420CcnxStackHelper::AsciiHooked (Ptr<Ccnx> ccnx)
421{
422 for ( FaceStreamMapCcnx::const_iterator i = g_faceStreamMapCcnx.begin ();
423 i != g_faceStreamMapCcnx.end ();
424 ++i)
425 {
426 if ((*i).first.first == ccnx)
427 {
428 return true;
429 }
430 }
431 return false;
432}
433
434void
435CcnxStackHelper::EnableAsciiCcnxInternal (
436 Ptr<OutputStreamWrapper> stream,
437 std::string prefix,
438 Ptr<Ccnx> ccnx,
439 uint32_t face,
440 bool explicitFilename)
441{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700442 //
443 // Our trace sinks are going to use packet printing, so we have to
444 // make sure that is turned on.
445 //
446 Packet::EnablePrinting ();
447
448 //
449 // If we are not provided an OutputStreamWrapper, we are expected to create
450 // one using the usual trace filename conventions and hook WithoutContext
451 // since there will be one file per context and therefore the context would
452 // be redundant.
453 //
454 if (stream == 0)
455 {
456 //
457 // Set up an output stream object to deal with private ofstream copy
458 // constructor and lifetime issues. Let the helper decide the actual
459 // name of the file given the prefix.
460 //
461 // We have to create a stream and a mapping from protocol/face to
462 // stream irrespective of how many times we want to trace a particular
463 // protocol.
464 //
465 AsciiTraceHelper asciiTraceHelper;
466
467 std::string filename;
468 if (explicitFilename)
469 {
470 filename = prefix;
471 }
472 else
473 {
474 filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
475 }
476
477 Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
478
479 //
480 // However, we only hook the trace sources once to avoid multiple trace sink
481 // calls per event (connect is independent of face).
482 //
483 if (!AsciiHooked (ccnx))
484 {
485 //
486 // The drop sink for the CcnxL3Protocol uses a different signature than
487 // the default sink, so we have to cook one up for ourselves. We can get
488 // to the Ptr<CcnxL3Protocol> through our Ptr<Ccnx> since they must both
489 // be aggregated to the same node.
490 //
491 Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
492 bool __attribute__ ((unused)) result = ccnxL3Protocol->TraceConnectWithoutContext ("Drop",
493 MakeBoundCallback (&CcnxL3ProtocolDropSinkWithoutContext, theStream));
494 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EanableAsciiCcnxInternal(): "
495 "Unable to connect ccnxL3Protocol \"Drop\"");
496 }
497
498 g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = theStream;
499 return;
500 }
501
502 //
503 // If we are provided an OutputStreamWrapper, we are expected to use it, and
504 // to provide a context. We are free to come up with our own context if we
505 // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
506 // compatibility and simplicity, we just use Config::Connect and let it deal
507 // with the context.
508 //
509 // We need to associate the ccnx/face with a stream to express interest
510 // in tracing events on that pair, however, we only hook the trace sources
511 // once to avoid multiple trace sink calls per event (connect is independent
512 // of face).
513 //
514 if (!AsciiHooked (ccnx))
515 {
516 Ptr<Node> node = ccnx->GetObject<Node> ();
517 std::ostringstream oss;
518
519 //
520 // This has all kinds of parameters coming with, so we have to cook up our
521 // own sink.
522 //
523 oss.str ("");
524 oss << "/NodeList/" << node->GetId () << "/$ns3::CcnxL3Protocol/Drop";
525 Config::Connect (oss.str (), MakeBoundCallback (&CcnxL3ProtocolDropSinkWithContext, stream));
526 }
527
528 g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = stream;
529}
530
531} // namespace ns3