blob: d59827e9a60b86d8140d50f1167f6dac567a661b [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 *
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -070018 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070019 */
20
21/**
22 * \ingroup ccnx
23 * \defgroup CcnxStackModel Ccnx Stack Model
24 *
25 * \section CcnxStackTracingModel Tracing in the Ccnx Stack
26 *
27 * The ccnx stack provides a number of trace sources in its various
28 * protocol implementations. These trace sources can be hooked using your own
29 * custom trace code, or you can use our helper functions in some cases to
30 * arrange for tracing to be enabled.
31 *
32 * \subsection CcnxStackCcnxTracingModel Tracing in Ccnx
33 *
34 * The Ccnx layer three protocol provides three trace hooks. These are the
35 * "Tx" (ns3::CcnxL3Protocol::m_txTrace), "Rx" (ns3::CcnxL3Protocol::m_rxTrace)
36 * and "Drop" (ns3::CcnxL3Protocol::m_dropTrace) trace sources.
37 *
38 * The "Tx" trace is fired in a number of situations, all of which indicate that
39 * a given packet is about to be sent down to a given ns3::CcnxFace.
40 *
41 * - \todo list Tx trace events
42 *
43 * The "Rx" trace is fired when a packet is passed from the device up to the
44 * ns3::CcnxL3Protocol::Receive function.
45 *
46 * - In the receive function, the CcnxFaceList is iterated, and if the
47 * CcnxFace corresponding to the receiving device is found to be in the
48 * UP state, the trace is fired.
49 *
50 * The "Drop" trace is fired in any case where the packet is dropped (in both
51 * the transmit and receive paths).
52 *
53 * - \todo list Drop trace events
54 */
55
56#include "ns3/assert.h"
57#include "ns3/log.h"
58#include "ns3/object.h"
59#include "ns3/names.h"
60#include "ns3/ccnx.h"
61#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 Afanasyev45b92d42011-08-14 23:11:38 -070072
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -070073#include "ccnx-face-container.h"
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070074#include "ccnx-stack-helper.h"
75#include "ccnx-forwarding-helper.h"
76
77#include <limits>
78#include <map>
79
80NS_LOG_COMPONENT_DEFINE ("CcnxStackHelper");
81
82namespace ns3 {
83
84// Things are going to work differently here with respect to trace
85// file handling than in most places because the Tx and Rx trace
86// sources we are interested in are going to multiplex receive and
87// transmit callbacks for all Ccnx and face pairs through one
88// callback. We want packets to or from each distinct pair to go to
89// an individual file, so we have got to demultiplex the Ccnx and face
90// pair into a corresponding Ptr<PcapFileWrapper> at the callback.
91//
92// A complication in this situation is that the trace sources are
93// hooked on a protocol basis. There is no trace source hooked by an
94// Ccnx and face pair. This means that if we naively proceed to hook,
95// say, a drop trace for a given Ccnx with face 0, and then hook for
96// Ccnx with face 1 we will hook the drop trace twice and get two
97// callbacks per event. What we need to do is to hook the event once,
98// and that will result in a single callback per drop event, and the
99// trace source will provide the face which we filter on in the trace
100// sink.
101//
102// This has got to continue to work properly after the helper has been
103// destroyed; but must be cleaned up at the end of time to avoid
104// leaks. Global maps of protocol/face pairs to file objects seems to
105// fit the bill.
106//
107typedef std::pair<Ptr<Ccnx>, uint32_t> FacePairCcnx;
108typedef std::map<FacePairCcnx, Ptr<PcapFileWrapper> > FaceFileMapCcnx;
109typedef std::map<FacePairCcnx, Ptr<OutputStreamWrapper> > FaceStreamMapCcnx;
110
111static FaceFileMapCcnx g_faceFileMapCcnx; /**< A mapping of Ccnx/face pairs to pcap files */
112static FaceStreamMapCcnx g_faceStreamMapCcnx; /**< A mapping of Ccnx/face pairs to ascii streams */
113
114CcnxStackHelper::CcnxStackHelper ()
115 : m_forwarding (0)
116 , m_ccnxEnabled (true)
117{
118 Initialize ();
119}
120
121// private method called by both constructor and Reset ()
122void
123CcnxStackHelper::Initialize ()
124{
125 // CcnxStaticForwardingHelper staticForwarding;
126 // CcnxGlobalForwardingHelper globalForwarding;
127 // CcnxListForwardingHelper listForwarding;
128 // listForwarding.Add (staticForwarding, 0);
129 // listForwarding.Add (globalForwarding, -10);
130 // SetForwardingHelper (listForwarding);
131}
132
133CcnxStackHelper::~CcnxStackHelper ()
134{
135 if (m_forwarding)
136 {
137 delete m_forwarding;
138 m_forwarding = 0;
139 }
140}
141
142CcnxStackHelper::CcnxStackHelper (const CcnxStackHelper &o)
143{
144 m_forwarding = o.m_forwarding->Copy ();
145 m_ccnxEnabled = o.m_ccnxEnabled;
146}
147
148CcnxStackHelper &
149CcnxStackHelper::operator = (const CcnxStackHelper &o)
150{
151 if (this == &o)
152 {
153 return *this;
154 }
155 m_forwarding = o.m_forwarding->Copy ();
156 return *this;
157}
158
159void
160CcnxStackHelper::Reset (void)
161{
162 delete m_forwarding;
163 m_forwarding = 0;
164 m_ccnxEnabled = true;
165 Initialize ();
166}
167
168void
169CcnxStackHelper::SetForwardingHelper (const CcnxForwardingHelper &forwarding)
170{
171 delete m_forwarding;
172 m_forwarding = forwarding.Copy ();
173}
174
175void
176CcnxStackHelper::SetCcnxStackInstall (bool enable)
177{
178 m_ccnxEnabled = enable;
179}
180
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700181Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700182CcnxStackHelper::Install (NodeContainer c) const
183{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700184 Ptr<CcnxFaceContainer> faces = Create<CcnxFaceContainer> ();
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700185 for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
186 {
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700187 faces->AddAll (Install (*i));
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700188 }
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700189 return faces;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700190}
191
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700192Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700193CcnxStackHelper::InstallAll (void) const
194{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700195 return Install (NodeContainer::GetGlobal ());
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700196}
197
198void
199CcnxStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId)
200{
201 ObjectFactory factory;
202 factory.SetTypeId (typeId);
203 Ptr<Object> protocol = factory.Create <Object> ();
204 node->AggregateObject (protocol);
205}
206
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700207Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700208CcnxStackHelper::Install (Ptr<Node> node) const
209{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700210 // NS_ASSERT_MSG (m_forwarding, "SetForwardingHelper() should be set prior calling Install() method");
211 Ptr<CcnxFaceContainer> faces = Create<CcnxFaceContainer> ();
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700212
213 if (m_ccnxEnabled)
214 {
215 if (node->GetObject<Ccnx> () != 0)
216 {
217 NS_FATAL_ERROR ("CcnxStackHelper::Install (): Installing "
218 "a CcnxStack to a node with an existing Ccnx object");
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700219 return 0;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700220 }
221
222 CreateAndAggregateObjectFromTypeId (node, "ns3::CcnxL3Protocol");
223 // Set forwarding
224 Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700225 for (uint32_t index=0; index < node->GetNDevices (); index++)
226 {
227 Ptr<CcnxNetDeviceFace> face = Create<CcnxNetDeviceFace> (node->GetDevice (index));
228 uint32_t __attribute__ ((unused)) face_id = ccnx->AddFace (face);
229 NS_LOG_LOGIC ("Node " << node->GetId () << ": added CcxnNetDeviceFace as face #" << face_id);
230
231 faces->Add (face);
232 }
233 // Ptr<CcnxForwardingStrategy> ccnxForwarding = m_forwarding->Create (node);
234 // ccnx->SetForwardingStrategy (ccnxForwarding);
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700235 }
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700236
237 return faces;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700238}
239
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700240Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700241CcnxStackHelper::Install (std::string nodeName) const
242{
243 Ptr<Node> node = Names::Find<Node> (nodeName);
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700244 return Install (node);
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700245}
246
247static void
248CcnxL3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ccnx> ccnx, uint32_t face)
249{
250 NS_LOG_FUNCTION (p << ccnx << face);
251
252 //
253 // Since trace sources are independent of face, if we hook a source
254 // on a particular protocol we will get traces for all of its faces.
255 // We need to filter this to only report faces for which the user
256 // has expressed interest.
257 //
258 FacePairCcnx pair = std::make_pair (ccnx, face);
259 if (g_faceFileMapCcnx.find (pair) == g_faceFileMapCcnx.end ())
260 {
261 NS_LOG_INFO ("Ignoring packet to/from face " << face);
262 return;
263 }
264
265 Ptr<PcapFileWrapper> file = g_faceFileMapCcnx[pair];
266 file->Write (Simulator::Now (), p);
267}
268
269bool
270CcnxStackHelper::PcapHooked (Ptr<Ccnx> ccnx)
271{
272 for (FaceFileMapCcnx::const_iterator i = g_faceFileMapCcnx.begin ();
273 i != g_faceFileMapCcnx.end ();
274 ++i)
275 {
276 if ((*i).first.first == ccnx)
277 {
278 return true;
279 }
280 }
281 return false;
282}
283
284void
285CcnxStackHelper::EnablePcapCcnxInternal (std::string prefix, Ptr<Ccnx> ccnx, uint32_t face, bool explicitFilename)
286{
287 NS_LOG_FUNCTION (prefix << ccnx << face);
288
289 if (!m_ccnxEnabled)
290 {
291 NS_LOG_INFO ("Call to enable Ccnx pcap tracing but Ccnx not enabled");
292 return;
293 }
294
295 //
296 // We have to create a file and a mapping from protocol/face to file
297 // irrespective of how many times we want to trace a particular protocol.
298 //
299 PcapHelper pcapHelper;
300
301 std::string filename;
302 if (explicitFilename)
303 {
304 filename = prefix;
305 }
306 else
307 {
308 filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
309 }
310
311 Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
312
313 //
314 // However, we only hook the trace source once to avoid multiple trace sink
315 // calls per event (connect is independent of face).
316 //
317 if (!PcapHooked (ccnx))
318 {
319 //
320 // Ptr<Ccnx> is aggregated to node and CcnxL3Protocol is aggregated to
321 // node so we can get to CcnxL3Protocol through Ccnx.
322 //
323 Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
324 NS_ASSERT_MSG (ccnxL3Protocol, "CcnxStackHelper::EnablePcapCcnxInternal(): "
325 "m_ccnxEnabled and ccnxL3Protocol inconsistent");
326
327 bool result = ccnxL3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&CcnxL3ProtocolRxTxSink));
328 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal(): "
329 "Unable to connect ccnxL3Protocol \"Tx\"");
330
331 result = ccnxL3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&CcnxL3ProtocolRxTxSink));
332 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal(): "
333 "Unable to connect ccnxL3Protocol \"Rx\"");
334 // cast result to void, to suppress ‘result’ set but not used compiler-warning
335 // for optimized builds
336 (void) result;
337 }
338
339 g_faceFileMapCcnx[std::make_pair (ccnx, face)] = file;
340}
341
342static void
343CcnxL3ProtocolDropSinkWithoutContext (
344 Ptr<OutputStreamWrapper> stream,
345 Ptr<const Packet> packet,
346 CcnxL3Protocol::DropReason reason,
347 Ptr<Ccnx> ccnx,
348 uint32_t face)
349{
350 //
351 // Since trace sources are independent of face, if we hook a source
352 // on a particular protocol we will get traces for all of its faces.
353 // We need to filter this to only report faces for which the user
354 // has expressed interest.
355 //
356 FacePairCcnx pair = std::make_pair (ccnx, face);
357 if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
358 {
359 NS_LOG_INFO ("Ignoring packet to/from face " << face);
360 return;
361 }
362
363 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
364}
365
366static void
367CcnxL3ProtocolDropSinkWithContext (
368 Ptr<OutputStreamWrapper> stream,
369 std::string context,
370 Ptr<const Packet> packet,
371 CcnxL3Protocol::DropReason reason,
372 Ptr<Ccnx> ccnx,
373 uint32_t face)
374{
375 //
376 // Since trace sources are independent of face, if we hook a source
377 // on a particular protocol we will get traces for all of its faces.
378 // We need to filter this to only report faces for which the user
379 // has expressed interest.
380 //
381 FacePairCcnx pair = std::make_pair (ccnx, face);
382 if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
383 {
384 NS_LOG_INFO ("Ignoring packet to/from face " << face);
385 return;
386 }
387
388 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << face << ") "
389 << *packet << std::endl;
390}
391
392bool
393CcnxStackHelper::AsciiHooked (Ptr<Ccnx> ccnx)
394{
395 for ( FaceStreamMapCcnx::const_iterator i = g_faceStreamMapCcnx.begin ();
396 i != g_faceStreamMapCcnx.end ();
397 ++i)
398 {
399 if ((*i).first.first == ccnx)
400 {
401 return true;
402 }
403 }
404 return false;
405}
406
407void
408CcnxStackHelper::EnableAsciiCcnxInternal (
409 Ptr<OutputStreamWrapper> stream,
410 std::string prefix,
411 Ptr<Ccnx> ccnx,
412 uint32_t face,
413 bool explicitFilename)
414{
415 if (!m_ccnxEnabled)
416 {
417 NS_LOG_INFO ("Call to enable Ccnx ascii tracing but Ccnx not enabled");
418 return;
419 }
420
421 //
422 // Our trace sinks are going to use packet printing, so we have to
423 // make sure that is turned on.
424 //
425 Packet::EnablePrinting ();
426
427 //
428 // If we are not provided an OutputStreamWrapper, we are expected to create
429 // one using the usual trace filename conventions and hook WithoutContext
430 // since there will be one file per context and therefore the context would
431 // be redundant.
432 //
433 if (stream == 0)
434 {
435 //
436 // Set up an output stream object to deal with private ofstream copy
437 // constructor and lifetime issues. Let the helper decide the actual
438 // name of the file given the prefix.
439 //
440 // We have to create a stream and a mapping from protocol/face to
441 // stream irrespective of how many times we want to trace a particular
442 // protocol.
443 //
444 AsciiTraceHelper asciiTraceHelper;
445
446 std::string filename;
447 if (explicitFilename)
448 {
449 filename = prefix;
450 }
451 else
452 {
453 filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
454 }
455
456 Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
457
458 //
459 // However, we only hook the trace sources once to avoid multiple trace sink
460 // calls per event (connect is independent of face).
461 //
462 if (!AsciiHooked (ccnx))
463 {
464 //
465 // The drop sink for the CcnxL3Protocol uses a different signature than
466 // the default sink, so we have to cook one up for ourselves. We can get
467 // to the Ptr<CcnxL3Protocol> through our Ptr<Ccnx> since they must both
468 // be aggregated to the same node.
469 //
470 Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
471 bool __attribute__ ((unused)) result = ccnxL3Protocol->TraceConnectWithoutContext ("Drop",
472 MakeBoundCallback (&CcnxL3ProtocolDropSinkWithoutContext, theStream));
473 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EanableAsciiCcnxInternal(): "
474 "Unable to connect ccnxL3Protocol \"Drop\"");
475 }
476
477 g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = theStream;
478 return;
479 }
480
481 //
482 // If we are provided an OutputStreamWrapper, we are expected to use it, and
483 // to provide a context. We are free to come up with our own context if we
484 // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
485 // compatibility and simplicity, we just use Config::Connect and let it deal
486 // with the context.
487 //
488 // We need to associate the ccnx/face with a stream to express interest
489 // in tracing events on that pair, however, we only hook the trace sources
490 // once to avoid multiple trace sink calls per event (connect is independent
491 // of face).
492 //
493 if (!AsciiHooked (ccnx))
494 {
495 Ptr<Node> node = ccnx->GetObject<Node> ();
496 std::ostringstream oss;
497
498 //
499 // This has all kinds of parameters coming with, so we have to cook up our
500 // own sink.
501 //
502 oss.str ("");
503 oss << "/NodeList/" << node->GetId () << "/$ns3::CcnxL3Protocol/Drop";
504 Config::Connect (oss.str (), MakeBoundCallback (&CcnxL3ProtocolDropSinkWithContext, stream));
505 }
506
507 g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = stream;
508}
509
510} // namespace ns3