blob: e1a554a31c748b381853a682c6e7951e217acd6a [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>
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"
Alexander Afanasyev45b92d42011-08-14 23:11:38 -070060#include "ns3/packet-socket-factory.h"
61#include "ns3/config.h"
62#include "ns3/simulator.h"
63#include "ns3/string.h"
64#include "ns3/net-device.h"
65#include "ns3/callback.h"
66#include "ns3/node.h"
67#include "ns3/core-config.h"
Alexander Afanasyevc74a6022011-08-15 20:01:35 -070068#include "ns3/ccnx-forwarding-strategy.h"
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -070069#include "ns3/ccnx-net-device-face.h"
70#include "ns3/ccnx-l3-protocol.h"
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -070071#include "ns3/ccnx-fib.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
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700114
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700115CcnxStackHelper::CcnxStackHelper ()
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700116 : m_forwardingHelper (Ccnx::NDN_FLOODING)
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700117{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700118}
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700119
120CcnxStackHelper::CcnxStackHelper (Ccnx::ForwardingStrategy strategy)
121 : m_forwardingHelper (strategy)
122{
123}
124
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700125CcnxStackHelper::~CcnxStackHelper ()
126{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700127}
128
129CcnxStackHelper::CcnxStackHelper (const CcnxStackHelper &o)
130{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700131}
132
133CcnxStackHelper &
134CcnxStackHelper::operator = (const CcnxStackHelper &o)
135{
136 if (this == &o)
137 {
138 return *this;
139 }
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700140 return *this;
141}
142
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700143void
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700144CcnxStackHelper::SetForwardingStrategy (Ccnx::ForwardingStrategy strategy)
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700145{
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700146 CcnxForwardingHelper newForwardingHelper (strategy);
147 m_forwardingHelper = newForwardingHelper;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700148}
149
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700150Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700151CcnxStackHelper::Install (NodeContainer c) const
152{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700153 Ptr<CcnxFaceContainer> faces = Create<CcnxFaceContainer> ();
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700154 for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
155 {
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700156 faces->AddAll (Install (*i));
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700157 }
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700158 return faces;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700159}
160
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700161Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700162CcnxStackHelper::InstallAll (void) const
163{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700164 return Install (NodeContainer::GetGlobal ());
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700165}
166
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700167// void
168// CcnxStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId)
169// {
170// ObjectFactory factory;
171// factory.SetTypeId (typeId);
172// Ptr<Object> protocol = factory.Create <Object> ();
173// node->AggregateObject (protocol);
174// }
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700175
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700176Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700177CcnxStackHelper::Install (Ptr<Node> node) const
178{
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700179 // NS_ASSERT_MSG (m_forwarding, "SetForwardingHelper() should be set prior calling Install() method");
180 Ptr<CcnxFaceContainer> faces = Create<CcnxFaceContainer> ();
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700181
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700182 if (node->GetObject<Ccnx> () != 0)
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700183 {
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700184 NS_FATAL_ERROR ("CcnxStackHelper::Install (): Installing "
185 "a CcnxStack to a node with an existing Ccnx object");
186 return 0;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700187 }
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700188
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700189 Ptr<CcnxFib> fib = CreateObject<CcnxFib> ();
190 node->AggregateObject (fib);
191
192 Ptr<Ccnx> ccnx = CreateObject<CcnxL3Protocol> ();
193 node->AggregateObject (ccnx);
194
195 for (uint32_t index=0; index < node->GetNDevices (); index++)
196 {
197 Ptr<CcnxNetDeviceFace> face = Create<CcnxNetDeviceFace> (node->GetDevice (index));
198 face->SetNode (node);
199 uint32_t __attribute__ ((unused)) face_id = ccnx->AddFace (face);
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700200 NS_LOG_LOGIC ("Node " << node->GetId () << ": added CcnxNetDeviceFace as face #" << face_id);
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700201
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700202 face->SetUp ();
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700203 faces->Add (face);
204 }
Ilya Moiseenko25f7d4d2011-09-29 18:41:06 -0700205
206 m_forwardingHelper.SetForwarding(ccnx);
207
208 // Ptr<CcnxForwardingStrategy> ccnxForwarding = m_forwarding->Create (node);
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700209 // ccnx->SetForwardingStrategy (ccnxForwarding);
210
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700211 return faces;
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700212}
213
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700214Ptr<CcnxFaceContainer>
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700215CcnxStackHelper::Install (std::string nodeName) const
216{
217 Ptr<Node> node = Names::Find<Node> (nodeName);
Alexander Afanasyev0ab833e2011-08-18 15:49:13 -0700218 return Install (node);
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700219}
220
Alexander Afanasyevc5a23e22011-09-07 00:37:36 -0700221
222void
223CcnxStackHelper::AddRoute (std::string nodeName, std::string prefix, uint32_t faceId, int32_t metric)
224{
225 NS_LOG_LOGIC ("[" << nodeName << "]$ route add " << prefix << " via " << faceId << " metric " << metric);
226
227 Ptr<Node> node = Names::Find<Node> (nodeName);
228 NS_ASSERT_MSG (node != 0, "Node [" << nodeName << "] does not exist");
229
230 Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
231 Ptr<CcnxFib> fib = node->GetObject<CcnxFib> ();
232 Ptr<CcnxFace> face = ccnx->GetFace (faceId);
233 NS_ASSERT_MSG (node != 0, "Face with ID [" << faceId << "] does not exist on node [" << nodeName << "]");
234
235 CcnxNameComponentsValue prefixValue;
236 prefixValue.DeserializeFromString (prefix, MakeCcnxNameComponentsChecker ());
237 fib->Add (prefixValue.Get (), face, metric);
238}
239
240
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700241static void
242CcnxL3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ccnx> ccnx, uint32_t face)
243{
244 NS_LOG_FUNCTION (p << ccnx << face);
245
246 //
247 // Since trace sources are independent of face, if we hook a source
248 // on a particular protocol we will get traces for all of its faces.
249 // We need to filter this to only report faces for which the user
250 // has expressed interest.
251 //
252 FacePairCcnx pair = std::make_pair (ccnx, face);
253 if (g_faceFileMapCcnx.find (pair) == g_faceFileMapCcnx.end ())
254 {
255 NS_LOG_INFO ("Ignoring packet to/from face " << face);
256 return;
257 }
258
259 Ptr<PcapFileWrapper> file = g_faceFileMapCcnx[pair];
260 file->Write (Simulator::Now (), p);
261}
262
263bool
264CcnxStackHelper::PcapHooked (Ptr<Ccnx> ccnx)
265{
266 for (FaceFileMapCcnx::const_iterator i = g_faceFileMapCcnx.begin ();
267 i != g_faceFileMapCcnx.end ();
268 ++i)
269 {
270 if ((*i).first.first == ccnx)
271 {
272 return true;
273 }
274 }
275 return false;
276}
277
278void
279CcnxStackHelper::EnablePcapCcnxInternal (std::string prefix, Ptr<Ccnx> ccnx, uint32_t face, bool explicitFilename)
280{
281 NS_LOG_FUNCTION (prefix << ccnx << face);
282
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700283 //
284 // We have to create a file and a mapping from protocol/face to file
285 // irrespective of how many times we want to trace a particular protocol.
286 //
287 PcapHelper pcapHelper;
288
289 std::string filename;
290 if (explicitFilename)
291 {
292 filename = prefix;
293 }
294 else
295 {
296 filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
297 }
298
299 Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
300
301 //
302 // However, we only hook the trace source once to avoid multiple trace sink
303 // calls per event (connect is independent of face).
304 //
305 if (!PcapHooked (ccnx))
306 {
307 //
308 // Ptr<Ccnx> is aggregated to node and CcnxL3Protocol is aggregated to
309 // node so we can get to CcnxL3Protocol through Ccnx.
310 //
311 Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
312 NS_ASSERT_MSG (ccnxL3Protocol, "CcnxStackHelper::EnablePcapCcnxInternal(): "
313 "m_ccnxEnabled and ccnxL3Protocol inconsistent");
314
315 bool result = ccnxL3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&CcnxL3ProtocolRxTxSink));
316 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal(): "
317 "Unable to connect ccnxL3Protocol \"Tx\"");
318
319 result = ccnxL3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&CcnxL3ProtocolRxTxSink));
320 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal(): "
321 "Unable to connect ccnxL3Protocol \"Rx\"");
322 // cast result to void, to suppress ‘result’ set but not used compiler-warning
323 // for optimized builds
324 (void) result;
325 }
326
327 g_faceFileMapCcnx[std::make_pair (ccnx, face)] = file;
328}
329
330static void
331CcnxL3ProtocolDropSinkWithoutContext (
332 Ptr<OutputStreamWrapper> stream,
333 Ptr<const Packet> packet,
334 CcnxL3Protocol::DropReason reason,
335 Ptr<Ccnx> ccnx,
336 uint32_t face)
337{
338 //
339 // Since trace sources are independent of face, if we hook a source
340 // on a particular protocol we will get traces for all of its faces.
341 // We need to filter this to only report faces for which the user
342 // has expressed interest.
343 //
344 FacePairCcnx pair = std::make_pair (ccnx, face);
345 if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
346 {
347 NS_LOG_INFO ("Ignoring packet to/from face " << face);
348 return;
349 }
350
351 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
352}
353
354static void
355CcnxL3ProtocolDropSinkWithContext (
356 Ptr<OutputStreamWrapper> stream,
357 std::string context,
358 Ptr<const Packet> packet,
359 CcnxL3Protocol::DropReason reason,
360 Ptr<Ccnx> ccnx,
361 uint32_t face)
362{
363 //
364 // Since trace sources are independent of face, if we hook a source
365 // on a particular protocol we will get traces for all of its faces.
366 // We need to filter this to only report faces for which the user
367 // has expressed interest.
368 //
369 FacePairCcnx pair = std::make_pair (ccnx, face);
370 if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
371 {
372 NS_LOG_INFO ("Ignoring packet to/from face " << face);
373 return;
374 }
375
376 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << face << ") "
377 << *packet << std::endl;
378}
379
380bool
381CcnxStackHelper::AsciiHooked (Ptr<Ccnx> ccnx)
382{
383 for ( FaceStreamMapCcnx::const_iterator i = g_faceStreamMapCcnx.begin ();
384 i != g_faceStreamMapCcnx.end ();
385 ++i)
386 {
387 if ((*i).first.first == ccnx)
388 {
389 return true;
390 }
391 }
392 return false;
393}
394
395void
396CcnxStackHelper::EnableAsciiCcnxInternal (
397 Ptr<OutputStreamWrapper> stream,
398 std::string prefix,
399 Ptr<Ccnx> ccnx,
400 uint32_t face,
401 bool explicitFilename)
402{
Alexander Afanasyev45b92d42011-08-14 23:11:38 -0700403 //
404 // Our trace sinks are going to use packet printing, so we have to
405 // make sure that is turned on.
406 //
407 Packet::EnablePrinting ();
408
409 //
410 // If we are not provided an OutputStreamWrapper, we are expected to create
411 // one using the usual trace filename conventions and hook WithoutContext
412 // since there will be one file per context and therefore the context would
413 // be redundant.
414 //
415 if (stream == 0)
416 {
417 //
418 // Set up an output stream object to deal with private ofstream copy
419 // constructor and lifetime issues. Let the helper decide the actual
420 // name of the file given the prefix.
421 //
422 // We have to create a stream and a mapping from protocol/face to
423 // stream irrespective of how many times we want to trace a particular
424 // protocol.
425 //
426 AsciiTraceHelper asciiTraceHelper;
427
428 std::string filename;
429 if (explicitFilename)
430 {
431 filename = prefix;
432 }
433 else
434 {
435 filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
436 }
437
438 Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
439
440 //
441 // However, we only hook the trace sources once to avoid multiple trace sink
442 // calls per event (connect is independent of face).
443 //
444 if (!AsciiHooked (ccnx))
445 {
446 //
447 // The drop sink for the CcnxL3Protocol uses a different signature than
448 // the default sink, so we have to cook one up for ourselves. We can get
449 // to the Ptr<CcnxL3Protocol> through our Ptr<Ccnx> since they must both
450 // be aggregated to the same node.
451 //
452 Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
453 bool __attribute__ ((unused)) result = ccnxL3Protocol->TraceConnectWithoutContext ("Drop",
454 MakeBoundCallback (&CcnxL3ProtocolDropSinkWithoutContext, theStream));
455 NS_ASSERT_MSG (result == true, "CcnxStackHelper::EanableAsciiCcnxInternal(): "
456 "Unable to connect ccnxL3Protocol \"Drop\"");
457 }
458
459 g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = theStream;
460 return;
461 }
462
463 //
464 // If we are provided an OutputStreamWrapper, we are expected to use it, and
465 // to provide a context. We are free to come up with our own context if we
466 // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
467 // compatibility and simplicity, we just use Config::Connect and let it deal
468 // with the context.
469 //
470 // We need to associate the ccnx/face with a stream to express interest
471 // in tracing events on that pair, however, we only hook the trace sources
472 // once to avoid multiple trace sink calls per event (connect is independent
473 // of face).
474 //
475 if (!AsciiHooked (ccnx))
476 {
477 Ptr<Node> node = ccnx->GetObject<Node> ();
478 std::ostringstream oss;
479
480 //
481 // This has all kinds of parameters coming with, so we have to cook up our
482 // own sink.
483 //
484 oss.str ("");
485 oss << "/NodeList/" << node->GetId () << "/$ns3::CcnxL3Protocol/Drop";
486 Config::Connect (oss.str (), MakeBoundCallback (&CcnxL3ProtocolDropSinkWithContext, stream));
487 }
488
489 g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = stream;
490}
491
492} // namespace ns3