25 #include "ns3/simulator.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"
44 #define INTERFACE_ID_KERNELTAP 0
45 #define INTERFACE_ID_FIRST 1
46 #define INTERFACE_ID_FIRST_DROP 33
50 std::map < simclick_node_t *, Ptr<Ipv4ClickRouting> > Ipv4ClickRouting::m_clickInstanceFromSimNode;
55 static TypeId tid = TypeId (
"ns3::Ipv4ClickRouting")
57 .AddConstructor<Ipv4ClickRouting> ()
63 Ipv4ClickRouting::Ipv4ClickRouting ()
64 : m_nonDefaultName (false),
67 m_random = CreateObject<UniformRandomVariable> ();
68 m_simNode =
new simclick_node_t;
69 timerclear (&m_simNode->curtime);
71 AddSimNodeToClickMapping ();
74 Ipv4ClickRouting::~Ipv4ClickRouting ()
79 Ipv4ClickRouting::DoInitialize ()
81 uint32_t
id = m_ipv4->GetObject<Node> ()->GetId ();
83 if (!m_nonDefaultName)
85 std::stringstream name;
87 m_nodeName = name.str ();
94 if (simclick_click_create (m_simNode, m_clickFile.c_str ()) >= 0)
96 NS_LOG_DEBUG (m_nodeName <<
" has initialised a Click Router");
97 m_clickInitialised =
true;
101 NS_LOG_DEBUG (
"Click Router Initialisation failed for " << m_nodeName);
102 m_clickInitialised =
false;
106 simclick_click_run (m_simNode);
115 Ptr<UniformRandomVariable>
116 Ipv4ClickRouting::GetRandomVariable (
void)
122 Ipv4ClickRouting::DoDispose ()
124 if (m_clickInitialised)
126 simclick_click_kill (m_simNode);
130 Ipv4RoutingProtocol::DoDispose ();
134 Ipv4ClickRouting::SetClickFile (std::string clickfile)
136 m_clickFile = clickfile;
140 Ipv4ClickRouting::SetDefines (std::map<std::string, std::string> defines)
145 std::map<std::string, std::string>
146 Ipv4ClickRouting::GetDefines (
void)
152 Ipv4ClickRouting::SetClickRoutingTableElement (std::string name)
154 m_clickRoutingTableElement = name;
158 Ipv4ClickRouting::SetNodeName (std::string name)
161 m_nonDefaultName =
true;
165 Ipv4ClickRouting::GetNodeName ()
171 Ipv4ClickRouting::GetInterfaceId (
const char *ifname)
187 if (strstr (ifname,
"tap") || strstr (ifname,
"tun"))
191 else if (
const char *devname = strstr (ifname,
"eth"))
193 while (*devname && !isdigit ((
unsigned char) *devname))
200 retval = atoi (devname) + INTERFACE_ID_FIRST;
203 else if (
const char *devname = strstr (ifname,
"drop"))
205 while (*devname && !isdigit ((
unsigned char) *devname))
211 retval = atoi (devname) + INTERFACE_ID_FIRST_DROP;
219 if (retval >= (
int) m_ipv4->GetNInterfaces ())
228 Ipv4ClickRouting::IsInterfaceReady (
int ifid)
230 if (ifid >= 0 && ifid < (
int) m_ipv4->GetNInterfaces ())
241 Ipv4ClickRouting::GetIpAddressFromInterfaceId (
int ifid)
243 std::stringstream addr;
244 m_ipv4->GetAddress (ifid, 0).GetLocal ().Print (addr);
250 Ipv4ClickRouting::GetIpPrefixFromInterfaceId (
int ifid)
252 std::stringstream addr;
253 m_ipv4->GetAddress (ifid, 0).GetMask ().Print (addr);
259 Ipv4ClickRouting::GetMacAddressFromInterfaceId (
int ifid)
261 std::stringstream addr;
263 Ptr<NetDevice> device = m_ipv4->GetNetDevice (ifid);
264 Address devAddr = device->GetAddress ();
265 addr << Mac48Address::ConvertFrom (devAddr);
271 Ipv4ClickRouting::AddSimNodeToClickMapping ()
273 m_clickInstanceFromSimNode.insert (std::make_pair (m_simNode,
this));
276 Ptr<Ipv4ClickRouting>
277 Ipv4ClickRouting::GetClickInstanceFromSimNode (simclick_node_t *simnode)
279 return m_clickInstanceFromSimNode[simnode];
283 Ipv4ClickRouting::GetTimevalFromNow () const
285 struct timeval curtime;
286 uint64_t remainder = 0;
309 if (curtime.tv_usec == 1000000)
320 Ipv4ClickRouting::RunClickEvent ()
322 m_simNode->curtime = GetTimevalFromNow ();
324 NS_LOG_DEBUG (
"RunClickEvent at " << m_simNode->curtime.tv_sec <<
" " <<
326 simclick_click_run (m_simNode);
330 Ipv4ClickRouting::HandleScheduleFromClick (
const struct timeval *when)
334 Time simtime = Time::FromInteger(when->tv_sec, Time::S) + Time::FromInteger(when->tv_usec, Time::US);
337 Simulator::Schedule (simdelay, &Ipv4ClickRouting::RunClickEvent,
this);
341 Ipv4ClickRouting::HandlePacketFromClick (
int ifid,
int ptype,
const unsigned char*
data,
int len)
350 NS_LOG_DEBUG (
"Incoming packet from tap0. Sending Packet up the stack.");
351 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol> (m_ipv4);
353 Ptr<Packet> p = Create<Packet> (
data, len);
356 p->RemoveHeader (ipHeader);
358 ipv4l3->LocalDeliver (p, ipHeader, (uint32_t) ifid);
362 NS_LOG_DEBUG (
"Incoming packet from eth" << ifid - 1 <<
" of type " << ptype <<
". Sending packet down the stack.");
364 Ptr<Packet> p = Create<Packet> (
data, len);
366 DynamicCast<Ipv4L3ClickProtocol> (m_ipv4)->SendDown (p, ifid);
371 Ipv4ClickRouting::SendPacketToClick (
int ifid,
int ptype,
const unsigned char* data,
int len)
374 m_simNode->curtime = GetTimevalFromNow ();
378 simclick_simpacketinfo pinfo;
382 simclick_click_send (m_simNode,ifid,ptype,data,len,&pinfo);
386 Ipv4ClickRouting::Send (Ptr<Packet> p, Ipv4Address src, Ipv4Address dst)
391 for (ifid = 0; ifid < m_ipv4->GetNInterfaces (); ifid++)
393 Ipv4Address addr = m_ipv4->GetAddress (ifid, 0).GetLocal ();
401 int len = p->GetSize ();
402 uint8_t *buf =
new uint8_t [len];
403 p->CopyData (buf, len);
406 SendPacketToClick (0, SIMCLICK_PTYPE_IP, buf, len);
412 Ipv4ClickRouting::Receive (Ptr<Packet> p, Mac48Address receiverAddr, Mac48Address dest)
419 for (ifid = 0; ifid < m_ipv4->GetNInterfaces (); ifid++)
421 Ptr<NetDevice> device = m_ipv4->GetNetDevice (ifid);
423 if (Mac48Address::ConvertFrom (device->GetAddress ()) == receiverAddr)
429 int len = p->GetSize ();
430 uint8_t *buf =
new uint8_t [len];
431 p->CopyData (buf, len);
434 SendPacketToClick (ifid, SIMCLICK_PTYPE_ETHER, buf, len);
440 Ipv4ClickRouting::ReadHandler (std::string elementName, std::string handlerName)
442 char *handle = simclick_click_read_handler (m_simNode, elementName.c_str (), handlerName.c_str (), 0, 0);
443 std::string ret (handle);
454 Ipv4ClickRouting::WriteHandler (std::string elementName, std::string handlerName, std::string writeString)
456 int r = simclick_click_write_handler (m_simNode, elementName.c_str (), handlerName.c_str (), writeString.c_str ());
468 Ipv4ClickRouting::SetPromisc (
int ifid)
470 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol> (m_ipv4);
472 ipv4l3->SetPromisc (ifid);
476 Ipv4ClickRouting::RouteOutput (Ptr<Packet> p,
const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
478 Ptr<Ipv4Route> rtentry;
480 std::stringstream addr;
482 header.GetDestination ().Print (addr);
485 std::string
s = ReadHandler (m_clickRoutingTableElement, addr.str ());
487 int pos = s.find (
" ");
489 int interfaceId = atoi (s.substr (0, pos).c_str ());
490 Ipv4Address destination (s.substr (pos + 1).c_str ());
492 if (interfaceId != -1)
494 rtentry = Create<Ipv4Route> ();
495 rtentry->SetDestination (header.GetDestination ());
500 uint32_t numOifAddresses = m_ipv4->GetNAddresses (interfaceId);
502 Ipv4InterfaceAddress ifAddr;
503 if (numOifAddresses == 1)
505 ifAddr = m_ipv4->GetAddress (interfaceId, 0);
510 NS_FATAL_ERROR (
"XXX Not implemented yet: IP aliasing and Click");
512 rtentry->SetSource (ifAddr.GetLocal ());
513 rtentry->SetGateway (destination);
514 rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceId));
515 sockerr = Socket::ERROR_NOTERROR;
516 NS_LOG_DEBUG (
"Found route to " << rtentry->GetDestination ()
517 <<
" via nh " << rtentry->GetGateway ()
518 <<
" with source addr " << rtentry->GetSource ()
519 <<
" and output dev " << rtentry->GetOutputDevice ());
524 <<
": RouteOutput for dest=" << header.GetDestination ()
525 <<
" No route to host");
526 sockerr = Socket::ERROR_NOROUTETOHOST;
535 Ipv4ClickRouting::RouteInput (Ptr<const Packet> p,
const Ipv4Header &header,
536 Ptr<const NetDevice> idev, UnicastForwardCallback ucb,
537 MulticastForwardCallback mcb, LocalDeliverCallback lcb,
540 NS_FATAL_ERROR (
"Click router does not have a RouteInput() interface!");
545 Ipv4ClickRouting::PrintRoutingTable (Ptr<OutputStreamWrapper> stream)
const
550 Ipv4ClickRouting::NotifyInterfaceUp (uint32_t i)
555 Ipv4ClickRouting::NotifyInterfaceDown (uint32_t i)
560 Ipv4ClickRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress
address)
565 Ipv4ClickRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress
address)
572 static int simstrlcpy (
char *buf,
int len,
const std::string &s)
578 if ((
unsigned) len > s.length ())
591 int simclick_sim_send (simclick_node_t *simnode,
592 int ifid,
int type,
const unsigned char* data,
int len,
593 simclick_simpacketinfo *pinfo)
604 clickInstance->HandlePacketFromClick (ifid, type, data, len);
610 int simclick_sim_command (simclick_node_t *simnode,
int cmd, ...)
620 case SIMCLICK_VERSION:
626 case SIMCLICK_SUPPORTS:
628 int othercmd = va_arg (val,
int);
629 retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_DEFINES);
633 case SIMCLICK_IFID_FROM_NAME:
635 const char *ifname = va_arg (val,
const char *);
637 retval = clickInstance->GetInterfaceId (ifname);
639 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_IFID_FROM_NAME: " << ifname <<
" " << retval);
643 case SIMCLICK_IPADDR_FROM_NAME:
645 const char *ifname = va_arg (val,
const char *);
646 char *buf = va_arg (val,
char *);
647 int len = va_arg (val,
int);
649 int ifid = clickInstance->GetInterfaceId (ifname);
653 retval = simstrlcpy (buf, len, clickInstance->GetIpAddressFromInterfaceId (ifid));
660 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_IPADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
664 case SIMCLICK_IPPREFIX_FROM_NAME:
666 const char *ifname = va_arg (val,
const char *);
667 char *buf = va_arg (val,
char *);
668 int len = va_arg (val,
int);
670 int ifid = clickInstance->GetInterfaceId (ifname);
674 retval = simstrlcpy (buf, len, clickInstance->GetIpPrefixFromInterfaceId (ifid));
681 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_IPPREFIX_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
685 case SIMCLICK_MACADDR_FROM_NAME:
687 const char *ifname = va_arg (val,
const char *);
688 char *buf = va_arg (val,
char *);
689 int len = va_arg (val,
int);
690 int ifid = clickInstance->GetInterfaceId (ifname);
694 retval = simstrlcpy (buf, len, clickInstance->GetMacAddressFromInterfaceId (ifid));
701 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_MACADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
705 case SIMCLICK_SCHEDULE:
707 const struct timeval *when = va_arg (val,
const struct timeval *);
709 clickInstance->HandleScheduleFromClick (when);
712 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_SCHEDULE at " << when->tv_sec <<
"s and " << when->tv_usec <<
"usecs.");
717 case SIMCLICK_GET_NODE_NAME:
719 char *buf = va_arg (val,
char *);
720 int len = va_arg (val,
int);
721 retval = simstrlcpy (buf, len, clickInstance->GetNodeName ());
723 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_GET_NODE_NAME: " << buf <<
" " << len);
727 case SIMCLICK_IF_PROMISC:
729 int ifid = va_arg(val,
int);
730 clickInstance->SetPromisc (ifid);
737 case SIMCLICK_IF_READY:
739 int ifid = va_arg (val,
int);
742 retval = clickInstance->IsInterfaceReady (ifid);
751 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" Received a call for SIMCLICK_TRACE");
755 case SIMCLICK_GET_NODE_ID:
758 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" Received a call for SIMCLICK_GET_NODE_ID");
762 case SIMCLICK_GET_RANDOM_INT:
764 uint32_t *randomValue = va_arg (val, uint32_t *);
765 uint32_t maxValue = va_arg (val, uint32_t);
767 *randomValue =
static_cast<uint32_t
> (clickInstance->GetRandomVariable ()->GetValue (0.0, static_cast<double> (maxValue) + 1.0));
773 case SIMCLICK_GET_DEFINES:
775 char *buf = va_arg (val,
char *);
776 size_t *size = va_arg (val,
size_t *);
777 uint32_t required = 0;
785 std::map<std::string, std::string> defines = clickInstance->GetDefines ();
786 std::map<std::string, std::string>::const_iterator it = defines.begin ();
787 while (it != defines.end ())
789 size_t available = *size - required;
790 if (it->first.length() + it->second.length() + 2 <= available)
792 simstrlcpy(buf + required, available, it->first);
793 required += it->first.length() + 1;
794 available -= it->first.length() + 1;
795 simstrlcpy(buf + required, available, it->second);
796 required += it->second.length() + 1;
800 required += it->first.length() + it->second.length() + 2;
804 if (required > *size)