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