1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2010 Lalith Suresh
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  * Authors: Lalith Suresh <suresh.lalith@gmail.com>
19  */
20 
21 
22 #ifdef NS3_CLICK
23 
24 #include "ns3/node.h"
25 #include "ns3/simulator.h"
26 #include "ns3/log.h"
27 #include "ns3/random-variable-stream.h"
28 #include "ns3/mac48-address.h"
29 #include "ns3/ipv4-interface.h"
30 #include "ns3/ipv4-l3-click-protocol.h"
31 
32 #include "ipv4-click-routing.h"
33 #include <string>
34 #include <map>
35 
36 #include <cstdlib>
37 #include <cstdarg>
38 
39 namespace ns3 {
40 
41 NS_LOG_COMPONENT_DEFINE ("Ipv4ClickRouting");
42 
43 // Values from nsclick ExtRouter implementation
44 #define INTERFACE_ID_KERNELTAP 0
45 #define INTERFACE_ID_FIRST 1
46 #define INTERFACE_ID_FIRST_DROP 33
47 
48 NS_OBJECT_ENSURE_REGISTERED (Ipv4ClickRouting);
49 
50 std::map < simclick_node_t *, Ptr<Ipv4ClickRouting> > Ipv4ClickRouting::m_clickInstanceFromSimNode;
51 
52 TypeId
GetTypeId(void)53 Ipv4ClickRouting::GetTypeId (void)
54 {
55   static TypeId tid = TypeId ("ns3::Ipv4ClickRouting")
56     .SetParent<Ipv4RoutingProtocol> ()
57     .AddConstructor<Ipv4ClickRouting> ()
58     .SetGroupName ("Click")
59   ;
60 
61   return tid;
62 }
63 
Ipv4ClickRouting()64 Ipv4ClickRouting::Ipv4ClickRouting ()
65   : m_nonDefaultName (false),
66     m_ipv4 (0)
67 {
68   m_random = CreateObject<UniformRandomVariable> ();
69   m_simNode = new simclick_node_t;
70   timerclear (&m_simNode->curtime);
71 
72   AddSimNodeToClickMapping ();
73 }
74 
~Ipv4ClickRouting()75 Ipv4ClickRouting::~Ipv4ClickRouting ()
76 {
77 }
78 
79 void
DoInitialize()80 Ipv4ClickRouting::DoInitialize ()
81 {
82   uint32_t id = m_ipv4->GetObject<Node> ()->GetId ();
83 
84   if (!m_nonDefaultName)
85     {
86       std::stringstream name;
87       name << "Node" << id;
88       m_nodeName = name.str ();
89     }
90 
91   NS_ASSERT (m_clickFile.length () > 0);
92 
93   // Even though simclick_click_create() will halt programme execution
94   // if it is unable to initialise a Click router, we play safe
95   if (simclick_click_create (m_simNode, m_clickFile.c_str ()) >= 0)
96     {
97       NS_LOG_DEBUG (m_nodeName << " has initialised a Click Router");
98       m_clickInitialised = true;
99     }
100   else
101     {
102       NS_LOG_DEBUG ("Click Router Initialisation failed for " << m_nodeName);
103       m_clickInitialised = false;
104     }
105 
106   NS_ASSERT (m_clickInitialised == true);
107   simclick_click_run (m_simNode);
108 }
109 
110 void
SetIpv4(Ptr<Ipv4> ipv4)111 Ipv4ClickRouting::SetIpv4 (Ptr<Ipv4> ipv4)
112 {
113   m_ipv4 = ipv4;
114 }
115 
116 Ptr<UniformRandomVariable>
GetRandomVariable(void)117 Ipv4ClickRouting::GetRandomVariable (void)
118 {
119   return m_random;
120 }
121 
122 void
DoDispose()123 Ipv4ClickRouting::DoDispose ()
124 {
125   if (m_clickInitialised)
126     {
127       simclick_click_kill (m_simNode);
128     }
129   m_ipv4 = 0;
130   delete m_simNode;
131   Ipv4RoutingProtocol::DoDispose ();
132 }
133 
134 void
SetClickFile(std::string clickfile)135 Ipv4ClickRouting::SetClickFile (std::string clickfile)
136 {
137   m_clickFile = clickfile;
138 }
139 
140 void
SetDefines(std::map<std::string,std::string> defines)141 Ipv4ClickRouting::SetDefines (std::map<std::string, std::string> defines)
142 {
143   m_defines = defines;
144 }
145 
146 std::map<std::string, std::string>
GetDefines(void)147 Ipv4ClickRouting::GetDefines (void)
148 {
149   return m_defines;
150 }
151 
152 void
SetClickRoutingTableElement(std::string name)153 Ipv4ClickRouting::SetClickRoutingTableElement (std::string name)
154 {
155   m_clickRoutingTableElement = name;
156 }
157 
158 void
SetNodeName(std::string name)159 Ipv4ClickRouting::SetNodeName (std::string name)
160 {
161   m_nodeName = name;
162   m_nonDefaultName = true;
163 }
164 
165 std::string
GetNodeName()166 Ipv4ClickRouting::GetNodeName ()
167 {
168   return m_nodeName;
169 }
170 
171 int
GetInterfaceId(const char * ifname)172 Ipv4ClickRouting::GetInterfaceId (const char *ifname)
173 {
174   int retval = -1;
175 
176   // The below hard coding of interface names follows the
177   // same approach as used in the original nsclick code for
178   // ns-2. The interface names map directly to what is to
179   // be used in the Click configuration files.
180   // Thus eth0 will refer to the first network device of
181   // the node, and is to be named so in the Click graph.
182   // This function is called by Click during the initialisation
183   // phase of the Click graph, during which it tries to map
184   // interface IDs to interface names. The return value
185   // corresponds to the interface ID that Click will use.
186 
187   // Tap/tun devices refer to the kernel devices
188   if (strstr (ifname, "tap") || strstr (ifname, "tun"))
189     {
190       retval = 0;
191     }
192   else if (const char *devname = strstr (ifname, "eth"))
193     {
194       while (*devname && !isdigit ((unsigned char) *devname))
195         {
196           devname++;
197         }
198 
199       if (*devname)
200         {
201           retval = atoi (devname) + INTERFACE_ID_FIRST;
202         }
203     }
204   else if (const char *devname = strstr (ifname, "drop"))
205     {
206       while (*devname && !isdigit ((unsigned char) *devname))
207         {
208           devname++;
209         }
210       if (*devname)
211         {
212           retval = atoi (devname) + INTERFACE_ID_FIRST_DROP;
213         }
214     }
215 
216   // This protects against a possible inconsistency of having
217   // more interfaces defined in the Click graph
218   // for a Click node than are defined for it in
219   // the simulation script
220   if (retval >= (int) m_ipv4->GetNInterfaces ())
221     {
222       return -1;
223     }
224 
225   return retval;
226 }
227 
228 bool
IsInterfaceReady(int ifid)229 Ipv4ClickRouting::IsInterfaceReady (int ifid)
230 {
231   if (ifid >= 0 && ifid < (int) m_ipv4->GetNInterfaces ())
232     {
233       return true;
234     }
235   else
236     {
237       return false;
238     }
239 }
240 
241 std::string
GetIpAddressFromInterfaceId(int ifid)242 Ipv4ClickRouting::GetIpAddressFromInterfaceId (int ifid)
243 {
244   std::stringstream addr;
245   m_ipv4->GetAddress (ifid, 0).GetLocal ().Print (addr);
246 
247   return addr.str ();
248 }
249 
250 std::string
GetIpPrefixFromInterfaceId(int ifid)251 Ipv4ClickRouting::GetIpPrefixFromInterfaceId (int ifid)
252 {
253   std::stringstream addr;
254   m_ipv4->GetAddress (ifid, 0).GetMask ().Print (addr);
255 
256   return addr.str ();
257 }
258 
259 std::string
GetMacAddressFromInterfaceId(int ifid)260 Ipv4ClickRouting::GetMacAddressFromInterfaceId (int ifid)
261 {
262   std::stringstream addr;
263 
264   Ptr<NetDevice> device = m_ipv4->GetNetDevice (ifid);
265   Address devAddr = device->GetAddress ();
266   addr << Mac48Address::ConvertFrom (devAddr);
267 
268   return addr.str ();
269 }
270 
271 void
AddSimNodeToClickMapping()272 Ipv4ClickRouting::AddSimNodeToClickMapping ()
273 {
274   m_clickInstanceFromSimNode.insert (std::make_pair (m_simNode, this));
275 }
276 
277 Ptr<Ipv4ClickRouting>
GetClickInstanceFromSimNode(simclick_node_t * simnode)278 Ipv4ClickRouting::GetClickInstanceFromSimNode (simclick_node_t *simnode)
279 {
280   return m_clickInstanceFromSimNode[simnode];
281 }
282 
283 struct timeval
GetTimevalFromNow() const284 Ipv4ClickRouting::GetTimevalFromNow () const
285 {
286   struct timeval curtime;
287   uint64_t remainder = 0;
288 
289   curtime.tv_sec = Simulator::Now ().GetSeconds ();
290   curtime.tv_usec = Simulator::Now ().GetMicroSeconds () % 1000000;
291 
292   switch (Simulator::Now ().GetResolution())
293     {
294       case Time::NS:
295         remainder = Simulator::Now ().GetNanoSeconds () % 1000;
296         break;
297       case Time::PS:
298         remainder = Simulator::Now ().GetPicoSeconds () % 1000000;
299         break;
300       case Time::FS:
301         remainder = Simulator::Now ().GetFemtoSeconds () % 1000000000;
302         break;
303       default:
304         break;
305     }
306 
307   if (remainder)
308     {
309       ++curtime.tv_usec;
310       if (curtime.tv_usec == 1000000)
311         {
312           ++curtime.tv_sec;
313           curtime.tv_usec = 0;
314         }
315     }
316 
317   return curtime;
318 }
319 
320 void
RunClickEvent()321 Ipv4ClickRouting::RunClickEvent ()
322 {
323   m_simNode->curtime = GetTimevalFromNow ();
324 
325   NS_LOG_DEBUG ("RunClickEvent at " << m_simNode->curtime.tv_sec << " " <<
326                                        m_simNode->curtime.tv_usec << " " << Simulator::Now ());
327   simclick_click_run (m_simNode);
328 }
329 
330 void
HandleScheduleFromClick(const struct timeval * when)331 Ipv4ClickRouting::HandleScheduleFromClick (const struct timeval *when)
332 {
333   NS_LOG_DEBUG ("HandleScheduleFromClick at " << when->tv_sec << " " << when->tv_usec << " " << Simulator::Now ());
334 
335   Time simtime  = Time::FromInteger(when->tv_sec, Time::S) + Time::FromInteger(when->tv_usec, Time::US);
336   Time simdelay = simtime - Simulator::Now();
337 
338   Simulator::Schedule (simdelay, &Ipv4ClickRouting::RunClickEvent, this);
339 }
340 
341 void
HandlePacketFromClick(int ifid,int ptype,const unsigned char * data,int len)342 Ipv4ClickRouting::HandlePacketFromClick (int ifid, int ptype, const unsigned char* data, int len)
343 {
344   NS_LOG_DEBUG ("HandlePacketFromClick");
345 
346   // Figure out packet's destination here:
347   // If ifid == 0, then the packet's going up
348   // else, the packet's going down
349   if (ifid == 0)
350     {
351       NS_LOG_DEBUG ("Incoming packet from tap0. Sending Packet up the stack.");
352       Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol> (m_ipv4);
353 
354       Ptr<Packet> p = Create<Packet> (data, len);
355 
356       Ipv4Header ipHeader;
357       p->RemoveHeader (ipHeader);
358 
359       ipv4l3->LocalDeliver (p, ipHeader, (uint32_t) ifid);
360     }
361   else if (ifid)
362     {
363       NS_LOG_DEBUG ("Incoming packet from eth" << ifid - 1 << " of type " << ptype << ". Sending packet down the stack.");
364 
365       Ptr<Packet> p = Create<Packet> (data, len);
366 
367       DynamicCast<Ipv4L3ClickProtocol> (m_ipv4)->SendDown (p, ifid);
368     }
369 }
370 
371 void
SendPacketToClick(int ifid,int ptype,const unsigned char * data,int len)372 Ipv4ClickRouting::SendPacketToClick (int ifid, int ptype, const unsigned char* data, int len)
373 {
374   NS_LOG_FUNCTION (this << ifid);
375   m_simNode->curtime = GetTimevalFromNow ();
376 
377   // Since packets in ns-3 don't have global Packet ID's and Flow ID's, we
378   // feed dummy values into pinfo. This avoids the need to make changes in the Click code
379   simclick_simpacketinfo pinfo;
380   pinfo.id = 0;
381   pinfo.fid = 0;
382 
383   simclick_click_send (m_simNode,ifid,ptype,data,len,&pinfo);
384 }
385 
386 void
Send(Ptr<Packet> p,Ipv4Address src,Ipv4Address dst)387 Ipv4ClickRouting::Send (Ptr<Packet> p, Ipv4Address src, Ipv4Address dst)
388 {
389   uint32_t ifid;
390 
391   // Find out which interface holds the src address of the packet...
392   for (ifid = 0; ifid < m_ipv4->GetNInterfaces (); ifid++)
393     {
394       Ipv4Address addr = m_ipv4->GetAddress (ifid, 0).GetLocal ();
395 
396       if (addr == src)
397         {
398           break;
399         }
400     }
401 
402   int len = p->GetSize ();
403   uint8_t *buf = new uint8_t [len];
404   p->CopyData (buf, len);
405 
406   // ... and send the packet on the corresponding Click interface.
407   SendPacketToClick (0, SIMCLICK_PTYPE_IP, buf, len);
408 
409   delete [] buf;
410 }
411 
412 void
Receive(Ptr<Packet> p,Mac48Address receiverAddr,Mac48Address dest)413 Ipv4ClickRouting::Receive (Ptr<Packet> p, Mac48Address receiverAddr, Mac48Address dest)
414 {
415   NS_LOG_FUNCTION (this << p << receiverAddr << dest);
416 
417   uint32_t ifid;
418 
419   // Find out which device this packet was received from...
420   for (ifid = 0; ifid < m_ipv4->GetNInterfaces (); ifid++)
421     {
422       Ptr<NetDevice> device = m_ipv4->GetNetDevice (ifid);
423 
424       if (Mac48Address::ConvertFrom (device->GetAddress ()) == receiverAddr)
425         {
426           break;
427         }
428     }
429 
430   int len = p->GetSize ();
431   uint8_t *buf = new uint8_t [len];
432   p->CopyData (buf, len);
433 
434   // ... and send the packet to the corresponding Click interface
435   SendPacketToClick (ifid, SIMCLICK_PTYPE_ETHER, buf, len);
436 
437   delete [] buf;
438 }
439 
440 std::string
ReadHandler(std::string elementName,std::string handlerName)441 Ipv4ClickRouting::ReadHandler (std::string elementName, std::string handlerName)
442 {
443   char *handle = simclick_click_read_handler (m_simNode, elementName.c_str (), handlerName.c_str (), 0, 0);
444   std::string ret (handle);
445 
446   // This is required because Click does not free
447   // the memory allocated to the return string
448   // from simclick_click_read_handler()
449   free(handle);
450 
451   return ret;
452 }
453 
454 int
WriteHandler(std::string elementName,std::string handlerName,std::string writeString)455 Ipv4ClickRouting::WriteHandler (std::string elementName, std::string handlerName, std::string writeString)
456 {
457   int r = simclick_click_write_handler (m_simNode, elementName.c_str (), handlerName.c_str (), writeString.c_str ());
458 
459   // Note: There are probably use-cases for returning
460   // a write handler's error code, so don't assert.
461   // For example, the 'add' handler for IPRouteTable
462   // type elements fails if the route to be added
463   // already exists.
464 
465   return r;
466 }
467 
468 void
SetPromisc(int ifid)469 Ipv4ClickRouting::SetPromisc (int ifid)
470 {
471   Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol> (m_ipv4);
472   NS_ASSERT(ipv4l3);
473   ipv4l3->SetPromisc (ifid);
474 }
475 
476 Ptr<Ipv4Route>
RouteOutput(Ptr<Packet> p,const Ipv4Header & header,Ptr<NetDevice> oif,Socket::SocketErrno & sockerr)477 Ipv4ClickRouting::RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
478 {
479   Ptr<Ipv4Route> rtentry;
480 
481   std::stringstream addr;
482   addr << "lookup ";
483   header.GetDestination ().Print (addr);
484   // Probe the Click Routing Table for the required IP
485   // This returns a string of the form "InterfaceID GatewayAddr"
486   NS_LOG_DEBUG ("Probe click routing table for " << addr.str ());
487   std::string s = ReadHandler (m_clickRoutingTableElement, addr.str ());
488   NS_LOG_DEBUG ("string from click routing table: " << s);
489 
490   size_t pos = s.find (" ");
491   Ipv4Address destination;
492   int interfaceId;
493   if (pos == std::string::npos)
494     {
495       // Only an interface ID is found
496       destination = Ipv4Address ("0.0.0.0");
497       interfaceId = atoi (s.c_str ());
498       NS_LOG_DEBUG ("case 1:  destination " << destination << " interfaceId " << interfaceId);
499     }
500   else
501     {
502       interfaceId = atoi (s.substr (0, pos).c_str ());
503       Ipv4Address destination (s.substr (pos + 1).c_str ());
504       NS_LOG_DEBUG ("case 2:  destination " << destination << " interfaceId " << interfaceId);
505     }
506 
507   if (interfaceId != -1)
508     {
509       rtentry = Create<Ipv4Route> ();
510       rtentry->SetDestination (header.GetDestination ());
511       // the source address is the interface address that matches
512       // the destination address (when multiple are present on the
513       // outgoing interface, one is selected via scoping rules)
514       NS_ASSERT (m_ipv4);
515       uint32_t numOifAddresses = m_ipv4->GetNAddresses (interfaceId);
516       NS_ASSERT (numOifAddresses > 0);
517       Ipv4InterfaceAddress ifAddr;
518       if (numOifAddresses == 1)
519         {
520           ifAddr = m_ipv4->GetAddress (interfaceId, 0);
521         }
522       else
523         {
524           /** \todo Implement IP aliasing and Click */
525           NS_FATAL_ERROR ("XXX Not implemented yet:  IP aliasing and Click");
526         }
527       rtentry->SetSource (ifAddr.GetLocal ());
528       rtentry->SetGateway (destination);
529       rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceId));
530       sockerr = Socket::ERROR_NOTERROR;
531       NS_LOG_DEBUG ("Found route to " << rtentry->GetDestination ()
532                                       << " via nh " << rtentry->GetGateway ()
533                                       << " with source addr " << rtentry->GetSource ()
534                                       << " and output dev " << rtentry->GetOutputDevice ());
535     }
536   else
537     {
538       NS_LOG_DEBUG ("Click node " << m_nodeName
539                                   << ": RouteOutput for dest=" << header.GetDestination ()
540                                   << " No route to host");
541       sockerr = Socket::ERROR_NOROUTETOHOST;
542     }
543 
544   return rtentry;
545 }
546 
547 // This method should never be called since Click handles
548 // forwarding directly
549 bool
RouteInput(Ptr<const Packet> p,const Ipv4Header & header,Ptr<const NetDevice> idev,UnicastForwardCallback ucb,MulticastForwardCallback mcb,LocalDeliverCallback lcb,ErrorCallback ecb)550 Ipv4ClickRouting::RouteInput  (Ptr<const Packet> p, const Ipv4Header &header,
551                                Ptr<const NetDevice> idev, UnicastForwardCallback ucb,
552                                MulticastForwardCallback mcb, LocalDeliverCallback lcb,
553                                ErrorCallback ecb)
554 {
555   NS_FATAL_ERROR ("Click router does not have a RouteInput() interface!");
556   return false;
557 }
558 
559 void
PrintRoutingTable(Ptr<OutputStreamWrapper> stream,Time::Unit unit) const560 Ipv4ClickRouting::PrintRoutingTable (Ptr<OutputStreamWrapper> stream, Time::Unit unit) const
561 {
562   *stream->GetStream () << "\nCLICK Routing table printing is not yet implemented, skipping.\n";
563 }
564 
565 void
NotifyInterfaceUp(uint32_t i)566 Ipv4ClickRouting::NotifyInterfaceUp (uint32_t i)
567 {
568 }
569 
570 void
NotifyInterfaceDown(uint32_t i)571 Ipv4ClickRouting::NotifyInterfaceDown (uint32_t i)
572 {
573 }
574 
575 void
NotifyAddAddress(uint32_t interface,Ipv4InterfaceAddress address)576 Ipv4ClickRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address)
577 {
578 }
579 
580 void
NotifyRemoveAddress(uint32_t interface,Ipv4InterfaceAddress address)581 Ipv4ClickRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address)
582 {
583 }
584 
585 
586 } // namespace ns3
587 
588 using ns3::g_log;
589 
simstrlcpy(char * buf,int len,const std::string & s)590 static int simstrlcpy (char *buf, int len, const std::string &s)
591 {
592   if (len)
593     {
594       len--;
595 
596       if ((unsigned) len > s.length ())
597         {
598           len = s.length ();
599         }
600 
601       s.copy (buf, len);
602       buf[len] = '\0';
603     }
604   return 0;
605 }
606 
607 // Sends a Packet from Click to the Simulator: Defined in simclick.h. Click
608 // calls these methods.
simclick_sim_send(simclick_node_t * simnode,int ifid,int type,const unsigned char * data,int len,simclick_simpacketinfo * pinfo)609 int simclick_sim_send (simclick_node_t *simnode,
610                        int ifid, int type, const unsigned char* data, int len,
611                        simclick_simpacketinfo *pinfo)
612 {
613   NS_LOG_DEBUG ("simclick_sim_send called at " << ns3::Simulator::Now ().As (ns3::Time::S) << ": " << ifid << " " << type << " " << data << " " << len);
614 
615   if (simnode == NULL)
616     {
617       return -1;
618     }
619 
620   ns3::Ptr<ns3::Ipv4ClickRouting> clickInstance = ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode (simnode);
621 
622   clickInstance->HandlePacketFromClick (ifid, type, data, len);
623 
624   return 0;
625 }
626 
627 // Click Service Methods: Defined in simclick.h
simclick_sim_command(simclick_node_t * simnode,int cmd,...)628 int simclick_sim_command (simclick_node_t *simnode, int cmd, ...)
629 {
630   va_list val;
631   va_start (val, cmd);
632 
633   int retval = 0;
634 
635   ns3::Ptr<ns3::Ipv4ClickRouting> clickInstance = ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode (simnode);
636   switch (cmd)
637     {
638     case SIMCLICK_VERSION:
639       {
640         retval = 0;
641         break;
642       }
643 
644     case SIMCLICK_SUPPORTS:
645       {
646         int othercmd = va_arg (val, int);
647         retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_DEFINES);
648         break;
649       }
650 
651     case SIMCLICK_IFID_FROM_NAME:
652       {
653         const char *ifname = va_arg (val, const char *);
654 
655         retval = clickInstance->GetInterfaceId (ifname);
656 
657         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IFID_FROM_NAME: " << ifname << " " << retval);
658         break;
659       }
660 
661     case SIMCLICK_IPADDR_FROM_NAME:
662       {
663         const char *ifname = va_arg (val, const char *);
664         char *buf = va_arg (val, char *);
665         int len = va_arg (val, int);
666 
667         int ifid = clickInstance->GetInterfaceId (ifname);
668 
669         if (ifid >= 0)
670           {
671             retval = simstrlcpy (buf, len, clickInstance->GetIpAddressFromInterfaceId (ifid));
672           }
673         else
674           {
675             retval = -1;
676           }
677 
678         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IPADDR_FROM_NAME: " << ifname << " " << buf << " " << len);
679         break;
680       }
681 
682     case SIMCLICK_IPPREFIX_FROM_NAME:
683       {
684         const char *ifname = va_arg (val, const char *);
685         char *buf = va_arg (val, char *);
686         int len = va_arg (val, int);
687 
688         int ifid = clickInstance->GetInterfaceId (ifname);
689 
690         if (ifid >= 0)
691           {
692             retval = simstrlcpy (buf, len, clickInstance->GetIpPrefixFromInterfaceId (ifid));
693           }
694         else
695           {
696             retval = -1;
697           }
698 
699         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IPPREFIX_FROM_NAME: " << ifname << " " << buf << " " << len);
700         break;
701       }
702 
703     case SIMCLICK_MACADDR_FROM_NAME:
704       {
705         const char *ifname = va_arg (val, const char *);
706         char *buf = va_arg (val, char *);
707         int len = va_arg (val, int);
708         int ifid = clickInstance->GetInterfaceId (ifname);
709 
710         if (ifid >= 0)
711           {
712             retval = simstrlcpy (buf, len, clickInstance->GetMacAddressFromInterfaceId (ifid));
713           }
714         else
715           {
716             retval = -1;
717           }
718 
719         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_MACADDR_FROM_NAME: " << ifname << " " << buf << " " << len);
720         break;
721       }
722 
723     case SIMCLICK_SCHEDULE:
724       {
725         const struct timeval *when = va_arg (val, const struct timeval *);
726 
727         clickInstance->HandleScheduleFromClick (when);
728 
729         retval = 0;
730         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_SCHEDULE at " << when->tv_sec << "s and " << when->tv_usec << "usecs.");
731 
732         break;
733       }
734 
735     case SIMCLICK_GET_NODE_NAME:
736       {
737         char *buf = va_arg (val, char *);
738         int len = va_arg (val, int);
739         retval = simstrlcpy (buf, len, clickInstance->GetNodeName ());
740 
741         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_GET_NODE_NAME: " << buf << " " << len);
742         break;
743       }
744 
745     case SIMCLICK_IF_PROMISC:
746       {
747         int ifid = va_arg(val, int);
748         clickInstance->SetPromisc (ifid);
749 
750         retval = 0;
751         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IF_PROMISC: " << ifid << " " << ns3::Simulator::Now ());
752         break;
753       }
754 
755     case SIMCLICK_IF_READY:
756       {
757         int ifid = va_arg (val, int); // Commented out so that optimized build works
758 
759         // We're not using a ClickQueue, so we're always ready (for the timebeing)
760         retval = clickInstance->IsInterfaceReady (ifid);
761 
762         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_IF_READY: " << ifid << " " << ns3::Simulator::Now ());
763         break;
764       }
765 
766     case SIMCLICK_TRACE:
767       {
768         // Used only for tracing
769         NS_LOG_DEBUG (clickInstance->GetNodeName () << " Received a call for SIMCLICK_TRACE");
770         break;
771       }
772 
773     case SIMCLICK_GET_NODE_ID:
774       {
775         // Used only for tracing
776         NS_LOG_DEBUG (clickInstance->GetNodeName () << " Received a call for SIMCLICK_GET_NODE_ID");
777         break;
778       }
779 
780     case SIMCLICK_GET_RANDOM_INT:
781       {
782         uint32_t *randomValue = va_arg (val, uint32_t *);
783         uint32_t maxValue = va_arg (val, uint32_t);
784 
785         *randomValue = static_cast<uint32_t> (clickInstance->GetRandomVariable ()->GetValue (0.0, static_cast<double> (maxValue) + 1.0));
786         retval = 0;
787         NS_LOG_DEBUG (clickInstance->GetNodeName () << " SIMCLICK_RANDOM: " << *randomValue << " " << maxValue << " " << ns3::Simulator::Now ());
788         break;
789       }
790 
791     case SIMCLICK_GET_DEFINES:
792       {
793         char *buf = va_arg (val, char *);
794         size_t *size = va_arg (val, size_t *);
795         uint32_t required = 0;
796 
797         // Try to fill the buffer with up to size bytes.
798         // If this is not enough space, write the required buffer size into
799         // the size variable and return an error code.
800         // Otherwise return the bytes actually writte into the buffer in size.
801 
802         // Append key/value pair, separated by \0.
803         std::map<std::string, std::string> defines = clickInstance->GetDefines ();
804         std::map<std::string, std::string>::const_iterator it = defines.begin ();
805         while (it != defines.end ())
806           {
807             size_t available = *size - required;
808             if (it->first.length() + it->second.length() + 2 <= available)
809               {
810                 simstrlcpy(buf + required, available, it->first);
811                 required += it->first.length() + 1;
812                 available -= it->first.length() + 1;
813                 simstrlcpy(buf + required, available, it->second);
814                 required += it->second.length() + 1;
815               }
816             else
817               {
818                 required += it->first.length() + it->second.length() + 2;
819               }
820             it++;
821           }
822         if (required > *size)
823           {
824             retval = -1;
825           }
826         else
827           {
828             retval = 0;
829           }
830         *size = required;
831       }
832     }
833 
834   va_end (val);
835   return retval;
836 }
837 
838 #endif // NS3_CLICK
839