| OLD | NEW |
| (Empty) | |
| 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| 2 /* |
| 3 * Copyright (c) 2008 INRIA |
| 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 * |
| 18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
| 19 * Author: Faker Moatamri <faker.moatamri@sophia.inria.fr> |
| 20 * Author: Lalith Suresh <suresh.lalith@gmail.com> |
| 21 */ |
| 22 |
| 23 #ifdef NS3_CLICK |
| 24 |
| 25 #include "ns3/assert.h" |
| 26 #include "ns3/log.h" |
| 27 #include "ns3/object.h" |
| 28 #include "ns3/names.h" |
| 29 #include "ns3/ipv4.h" |
| 30 #include "ns3/packet-socket-factory.h" |
| 31 #include "ns3/config.h" |
| 32 #include "ns3/simulator.h" |
| 33 #include "ns3/string.h" |
| 34 #include "ns3/net-device.h" |
| 35 #include "ns3/callback.h" |
| 36 #include "ns3/node.h" |
| 37 #include "ns3/core-config.h" |
| 38 #include "ns3/arp-l3-protocol.h" |
| 39 #include "ns3/ipv4-click-routing.h" |
| 40 #include "ns3/ipv4-l3-click-protocol.h" |
| 41 #include "ns3/trace-helper.h" |
| 42 #include "click-internet-stack-helper.h" |
| 43 #include <limits> |
| 44 #include <map> |
| 45 |
| 46 NS_LOG_COMPONENT_DEFINE ("ClickInternetStackHelper"); |
| 47 |
| 48 namespace ns3 { |
| 49 |
| 50 #define INTERFACE_CONTEXT |
| 51 |
| 52 typedef std::pair<Ptr<Ipv4>, uint32_t> InterfacePairIpv4;· |
| 53 typedef std::map<InterfacePairIpv4, Ptr<PcapFileWrapper> > InterfaceFileMapIpv4; |
| 54 typedef std::map<InterfacePairIpv4, Ptr<OutputStreamWrapper> > InterfaceStreamMa
pIpv4; |
| 55 |
| 56 static InterfaceFileMapIpv4 g_interfaceFileMapIpv4; /**< A mapping of Ipv4/inter
face pairs to pcap files */ |
| 57 static InterfaceStreamMapIpv4 g_interfaceStreamMapIpv4; /**< A mapping of Ipv4/i
nterface pairs to ascii streams */ |
| 58 |
| 59 ClickInternetStackHelper::ClickInternetStackHelper () |
| 60 : m_ipv4Enabled (true) |
| 61 { |
| 62 Initialize (); |
| 63 } |
| 64 |
| 65 // private method called by both constructor and Reset () |
| 66 void |
| 67 ClickInternetStackHelper::Initialize () |
| 68 { |
| 69 SetTcp ("ns3::TcpL4Protocol"); |
| 70 } |
| 71 |
| 72 ClickInternetStackHelper::~ClickInternetStackHelper () |
| 73 { |
| 74 } |
| 75 |
| 76 ClickInternetStackHelper::ClickInternetStackHelper (const ClickInternetStackHelp
er &o) |
| 77 { |
| 78 m_ipv4Enabled = o.m_ipv4Enabled; |
| 79 m_tcpFactory = o.m_tcpFactory; |
| 80 } |
| 81 |
| 82 ClickInternetStackHelper & |
| 83 ClickInternetStackHelper::operator = (const ClickInternetStackHelper &o) |
| 84 { |
| 85 if (this == &o) |
| 86 { |
| 87 return *this; |
| 88 } |
| 89 return *this; |
| 90 } |
| 91 |
| 92 void |
| 93 ClickInternetStackHelper::Reset (void) |
| 94 { |
| 95 m_ipv4Enabled = true; |
| 96 Initialize (); |
| 97 } |
| 98 |
| 99 void |
| 100 ClickInternetStackHelper::SetTcp (const std::string tid) |
| 101 { |
| 102 m_tcpFactory.SetTypeId (tid); |
| 103 } |
| 104 |
| 105 void· |
| 106 ClickInternetStackHelper::SetTcp (std::string tid, std::string n0, const Attribu
teValue &v0) |
| 107 { |
| 108 m_tcpFactory.SetTypeId (tid); |
| 109 m_tcpFactory.Set (n0,v0); |
| 110 } |
| 111 |
| 112 void |
| 113 ClickInternetStackHelper::SetClickFile (NodeContainer c, std::string clickfile) |
| 114 { |
| 115 for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) |
| 116 { |
| 117 SetClickFile (*i, clickfile); |
| 118 } |
| 119 } |
| 120 |
| 121 void |
| 122 ClickInternetStackHelper::SetClickFile (Ptr<Node> node, std::string clickfile) |
| 123 { |
| 124 m_nodeToClickFileMap.insert (std::make_pair (node, clickfile)); |
| 125 } |
| 126 |
| 127 void |
| 128 ClickInternetStackHelper::SetRoutingTableElement (NodeContainer c, std::string r
t) |
| 129 { |
| 130 for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) |
| 131 { |
| 132 SetRoutingTableElement (*i, rt); |
| 133 } |
| 134 } |
| 135 |
| 136 void |
| 137 ClickInternetStackHelper::SetRoutingTableElement (Ptr<Node> node, std::string rt
) |
| 138 { |
| 139 m_nodeToRoutingTableElementMap.insert (std::make_pair (node, rt)); |
| 140 } |
| 141 |
| 142 void· |
| 143 ClickInternetStackHelper::Install (NodeContainer c) const |
| 144 { |
| 145 for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i) |
| 146 { |
| 147 Install (*i); |
| 148 } |
| 149 } |
| 150 |
| 151 void· |
| 152 ClickInternetStackHelper::InstallAll (void) const |
| 153 { |
| 154 Install (NodeContainer::GetGlobal ()); |
| 155 } |
| 156 |
| 157 void |
| 158 ClickInternetStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, co
nst std::string typeId) |
| 159 { |
| 160 ObjectFactory factory; |
| 161 factory.SetTypeId (typeId); |
| 162 Ptr<Object> protocol = factory.Create <Object> (); |
| 163 node->AggregateObject (protocol); |
| 164 } |
| 165 |
| 166 void |
| 167 ClickInternetStackHelper::Install (Ptr<Node> node) const |
| 168 { |
| 169 if (m_ipv4Enabled) |
| 170 { |
| 171 if (node->GetObject<Ipv4> () != 0) |
| 172 { |
| 173 NS_FATAL_ERROR ("ClickInternetStackHelper::Install (): Aggregating "· |
| 174 "an InternetStack to a node with an existing Ipv4 obje
ct"); |
| 175 return; |
| 176 } |
| 177 |
| 178 CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol"); |
| 179 CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3ClickProtocol"); |
| 180 CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol"); |
| 181 CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol"); |
| 182 node->AggregateObject (m_tcpFactory.Create<Object> ()); |
| 183 Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> (); |
| 184 node->AggregateObject (factory); |
| 185 // Set routing |
| 186 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> (); |
| 187 Ptr<Ipv4ClickRouting> ipv4Routing = CreateObject<Ipv4ClickRouting> (); |
| 188 std::map< Ptr<Node>, std::string >::const_iterator it; |
| 189 it = m_nodeToClickFileMap.find (node); |
| 190 |
| 191 if (it != m_nodeToClickFileMap.end ()) |
| 192 { |
| 193 ipv4Routing->SetClickFile (it->second); |
| 194 } |
| 195 |
| 196 it = m_nodeToRoutingTableElementMap.find (node); |
| 197 if (it != m_nodeToRoutingTableElementMap.end ()) |
| 198 { |
| 199 ipv4Routing->SetClickRoutingTableElement (it->second); |
| 200 } |
| 201 ipv4->SetRoutingProtocol (ipv4Routing); |
| 202 node->AggregateObject (ipv4Routing); |
| 203 } |
| 204 } |
| 205 |
| 206 void |
| 207 ClickInternetStackHelper::Install (std::string nodeName) const |
| 208 { |
| 209 Ptr<Node> node = Names::Find<Node> (nodeName); |
| 210 Install (node); |
| 211 } |
| 212 |
| 213 static void |
| 214 Ipv4L3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ipv4> ipv4, uint32_t interface) |
| 215 { |
| 216 NS_LOG_FUNCTION (p << ipv4 << interface); |
| 217 |
| 218 // |
| 219 // Since trace sources are independent of interface, if we hook a source |
| 220 // on a particular protocol we will get traces for all of its interfaces. |
| 221 // We need to filter this to only report interfaces for which the user· |
| 222 // has expressed interest. |
| 223 // |
| 224 InterfacePairIpv4 pair = std::make_pair (ipv4, interface); |
| 225 if (g_interfaceFileMapIpv4.find (pair) == g_interfaceFileMapIpv4.end ()) |
| 226 { |
| 227 NS_LOG_INFO ("Ignoring packet to/from interface " << interface); |
| 228 return; |
| 229 } |
| 230 |
| 231 Ptr<PcapFileWrapper> file = g_interfaceFileMapIpv4[pair]; |
| 232 file->Write(Simulator::Now(), p); |
| 233 } |
| 234 |
| 235 bool |
| 236 ClickInternetStackHelper::PcapHooked (Ptr<Ipv4> ipv4) |
| 237 { |
| 238 for ( InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin (
);· |
| 239 i != g_interfaceFileMapIpv4.end ();· |
| 240 ++i) |
| 241 { |
| 242 if ((*i).first.first == ipv4) |
| 243 { |
| 244 return true; |
| 245 } |
| 246 } |
| 247 return false; |
| 248 } |
| 249 |
| 250 void· |
| 251 ClickInternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4>
ipv4, uint32_t interface, bool explicitFilename) |
| 252 { |
| 253 NS_LOG_FUNCTION (prefix << ipv4 << interface); |
| 254 |
| 255 if (!m_ipv4Enabled) |
| 256 { |
| 257 NS_LOG_INFO ("Call to enable Ipv4 pcap tracing but Ipv4 not enabled"); |
| 258 return; |
| 259 } |
| 260 |
| 261 // |
| 262 // We have to create a file and a mapping from protocol/interface to file· |
| 263 // irrespective of how many times we want to trace a particular protocol. |
| 264 // |
| 265 PcapHelper pcapHelper; |
| 266 |
| 267 std::string filename; |
| 268 if (explicitFilename) |
| 269 { |
| 270 filename = prefix; |
| 271 } |
| 272 else |
| 273 { |
| 274 filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interfac
e); |
| 275 } |
| 276 |
| 277 Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, Pc
apHelper::DLT_RAW); |
| 278 |
| 279 // |
| 280 // However, we only hook the trace source once to avoid multiple trace sink |
| 281 // calls per event (connect is independent of interface). |
| 282 // |
| 283 if (!PcapHooked (ipv4)) |
| 284 { |
| 285 // |
| 286 // Ptr<Ipv4> is aggregated to node and Ipv4L3Protocol is aggregated to· |
| 287 // node so we can get to Ipv4L3Protocol through Ipv4. |
| 288 // |
| 289 Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> (); |
| 290 NS_ASSERT_MSG (ipv4L3Protocol, "ClickInternetStackHelper::EnablePcapIpv4In
ternal(): " |
| 291 "m_ipv4Enabled and ipv4L3Protocol inconsistent"); |
| 292 |
| 293 bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallba
ck (&Ipv4L3ProtocolRxTxSink)); |
| 294 NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4In
ternal(): " |
| 295 "Unable to connect ipv4L3Protocol \"Tx\""); |
| 296 |
| 297 result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&
Ipv4L3ProtocolRxTxSink)); |
| 298 NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4In
ternal(): " |
| 299 "Unable to connect ipv4L3Protocol \"Rx\""); |
| 300 } |
| 301 |
| 302 g_interfaceFileMapIpv4[std::make_pair (ipv4, interface)] = file; |
| 303 } |
| 304 |
| 305 static void |
| 306 Ipv4L3ProtocolDropSinkWithoutContext ( |
| 307 Ptr<OutputStreamWrapper> stream, |
| 308 Ipv4Header const &header,· |
| 309 Ptr<const Packet> packet, |
| 310 Ipv4L3Protocol::DropReason reason,· |
| 311 Ptr<Ipv4> ipv4,· |
| 312 uint32_t interface) |
| 313 { |
| 314 // |
| 315 // Since trace sources are independent of interface, if we hook a source |
| 316 // on a particular protocol we will get traces for all of its interfaces. |
| 317 // We need to filter this to only report interfaces for which the user· |
| 318 // has expressed interest. |
| 319 // |
| 320 InterfacePairIpv4 pair = std::make_pair (ipv4, interface); |
| 321 if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ()) |
| 322 { |
| 323 NS_LOG_INFO ("Ignoring packet to/from interface " << interface); |
| 324 return; |
| 325 } |
| 326 |
| 327 Ptr<Packet> p = packet->Copy (); |
| 328 p->AddHeader (header); |
| 329 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p
<< std::endl; |
| 330 } |
| 331 |
| 332 static void |
| 333 Ipv4L3ProtocolDropSinkWithContext ( |
| 334 Ptr<OutputStreamWrapper> stream, |
| 335 std::string context, |
| 336 Ipv4Header const &header,· |
| 337 Ptr<const Packet> packet, |
| 338 Ipv4L3Protocol::DropReason reason,· |
| 339 Ptr<Ipv4> ipv4,· |
| 340 uint32_t interface) |
| 341 { |
| 342 // |
| 343 // Since trace sources are independent of interface, if we hook a source |
| 344 // on a particular protocol we will get traces for all of its interfaces. |
| 345 // We need to filter this to only report interfaces for which the user· |
| 346 // has expressed interest. |
| 347 // |
| 348 InterfacePairIpv4 pair = std::make_pair (ipv4, interface); |
| 349 if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ()) |
| 350 { |
| 351 NS_LOG_INFO ("Ignoring packet to/from interface " << interface); |
| 352 return; |
| 353 } |
| 354 |
| 355 Ptr<Packet> p = packet->Copy (); |
| 356 p->AddHeader (header); |
| 357 #ifdef INTERFACE_CONTEXT |
| 358 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << con
text << "(" << interface << ") "· |
| 359 << *p << std::endl; |
| 360 #else |
| 361 *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << con
text << " " << *p << std::endl; |
| 362 #endif |
| 363 } |
| 364 |
| 365 bool |
| 366 ClickInternetStackHelper::AsciiHooked (Ptr<Ipv4> ipv4) |
| 367 { |
| 368 for ( InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.beg
in ();· |
| 369 i != g_interfaceStreamMapIpv4.end ();· |
| 370 ++i) |
| 371 { |
| 372 if ((*i).first.first == ipv4) |
| 373 { |
| 374 return true; |
| 375 } |
| 376 } |
| 377 return false; |
| 378 } |
| 379 |
| 380 void· |
| 381 ClickInternetStackHelper::EnableAsciiIpv4Internal ( |
| 382 Ptr<OutputStreamWrapper> stream,· |
| 383 std::string prefix,· |
| 384 Ptr<Ipv4> ipv4,· |
| 385 uint32_t interface, |
| 386 bool explicitFilename) |
| 387 { |
| 388 if (!m_ipv4Enabled) |
| 389 { |
| 390 NS_LOG_INFO ("Call to enable Ipv4 ascii tracing but Ipv4 not enabled"); |
| 391 return; |
| 392 } |
| 393 |
| 394 // |
| 395 // Our trace sinks are going to use packet printing, so we have to· |
| 396 // make sure that is turned on. |
| 397 // |
| 398 Packet::EnablePrinting (); |
| 399 |
| 400 // |
| 401 // If we are not provided an OutputStreamWrapper, we are expected to create· |
| 402 // one using the usual trace filename conventions and hook WithoutContext |
| 403 // since there will be one file per context and therefore the context would |
| 404 // be redundant. |
| 405 // |
| 406 if (stream == 0) |
| 407 { |
| 408 // |
| 409 // Set up an output stream object to deal with private ofstream copy· |
| 410 // constructor and lifetime issues. Let the helper decide the actual |
| 411 // name of the file given the prefix. |
| 412 // |
| 413 // We have to create a stream and a mapping from protocol/interface to· |
| 414 // stream irrespective of how many times we want to trace a particular· |
| 415 // protocol. |
| 416 // |
| 417 AsciiTraceHelper asciiTraceHelper; |
| 418 |
| 419 std::string filename; |
| 420 if (explicitFilename) |
| 421 { |
| 422 filename = prefix; |
| 423 } |
| 424 else |
| 425 { |
| 426 filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4
, interface); |
| 427 } |
| 428 |
| 429 Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (fi
lename); |
| 430 |
| 431 // |
| 432 // However, we only hook the trace sources once to avoid multiple trace si
nk |
| 433 // calls per event (connect is independent of interface). |
| 434 // |
| 435 if (!AsciiHooked (ipv4)) |
| 436 { |
| 437 // |
| 438 // We can use the default drop sink for the ArpL3Protocol since it has |
| 439 // the usual signature. We can get to the Ptr<ArpL3Protocol> through |
| 440 // our Ptr<Ipv4> since they must both be aggregated to the same node. |
| 441 // |
| 442 Ptr<ArpL3Protocol> arpL3Protocol = ipv4->GetObject<ArpL3Protocol> (); |
| 443 asciiTraceHelper.HookDefaultDropSinkWithoutContext<ArpL3Protocol> (arp
L3Protocol, "Drop", theStream); |
| 444 |
| 445 // |
| 446 // The drop sink for the Ipv4L3Protocol uses a different signature tha
n |
| 447 // the default sink, so we have to cook one up for ourselves. We can
get |
| 448 // to the Ptr<Ipv4L3Protocol> through our Ptr<Ipv4> since they must bo
th· |
| 449 // be aggregated to the same node. |
| 450 // |
| 451 Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> (
); |
| 452 bool __attribute__ ((unused)) result = ipv4L3Protocol->TraceConnectWit
houtContext ("Drop",· |
| 453
MakeBoundCallback (&Ipv4L3ProtocolDropSinkWithoutContext, |
| 454
theStream)); |
| 455 NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EanableAscii
Ipv4Internal(): " |
| 456 "Unable to connect ipv4L3Protocol \"Drop\""); |
| 457 } |
| 458 |
| 459 g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = 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 ipv4/interface 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 interface). |
| 474 // |
| 475 if (!AsciiHooked (ipv4)) |
| 476 { |
| 477 Ptr<Node> node = ipv4->GetObject<Node> (); |
| 478 std::ostringstream oss; |
| 479 |
| 480 // |
| 481 // For the ARP Drop, we are going to use the default trace sink provided b
y· |
| 482 // the ascii trace helper. There is actually no AsciiTraceHelper in sight······· |
| 483 // here, but the default trace sinks are actually publicly available stati
c· |
| 484 // functions that are always there waiting for just such a case. |
| 485 // |
| 486 oss << "/NodeList/" << node->GetId () << "/$ns3::ArpL3Protocol/Drop"; |
| 487 Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::Default
DropSinkWithContext, stream)); |
| 488 |
| 489 // |
| 490 // This has all kinds of parameters coming with, so we have to cook up our |
| 491 // own sink. |
| 492 // |
| 493 oss.str (""); |
| 494 oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Drop"; |
| 495 Config::Connect (oss.str (), MakeBoundCallback (&Ipv4L3ProtocolDropSinkWit
hContext, stream)); |
| 496 } |
| 497 |
| 498 g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = stream; |
| 499 } |
| 500 |
| 501 } // namespace ns3 |
| 502 |
| 503 #endif // NS3_CLICK |
| OLD | NEW |