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);
509 NS_FATAL_ERROR (
"XXX Not implemented yet: IP aliasing and Click");
511 rtentry->SetSource (ifAddr.GetLocal ());
512 rtentry->SetGateway (destination);
513 rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceId));
514 sockerr = Socket::ERROR_NOTERROR;
515 NS_LOG_DEBUG (
"Found route to " << rtentry->GetDestination ()
516 <<
" via nh " << rtentry->GetGateway ()
517 <<
" with source addr " << rtentry->GetSource ()
518 <<
" and output dev " << rtentry->GetOutputDevice ());
523 <<
": RouteOutput for dest=" << header.GetDestination ()
524 <<
" No route to host");
525 sockerr = Socket::ERROR_NOROUTETOHOST;
534 Ipv4ClickRouting::RouteInput (Ptr<const Packet> p,
const Ipv4Header &header,
535 Ptr<const NetDevice> idev, UnicastForwardCallback ucb,
536 MulticastForwardCallback mcb, LocalDeliverCallback lcb,
539 NS_FATAL_ERROR (
"Click router does not have a RouteInput() interface!");
544 Ipv4ClickRouting::PrintRoutingTable (Ptr<OutputStreamWrapper> stream)
const
549 Ipv4ClickRouting::NotifyInterfaceUp (uint32_t i)
554 Ipv4ClickRouting::NotifyInterfaceDown (uint32_t i)
559 Ipv4ClickRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address)
564 Ipv4ClickRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address)
571 static int simstrlcpy (
char *buf,
int len,
const std::string &s)
577 if ((
unsigned) len > s.length ())
590 int simclick_sim_send (simclick_node_t *simnode,
591 int ifid,
int type,
const unsigned char* data,
int len,
592 simclick_simpacketinfo *pinfo)
603 clickInstance->HandlePacketFromClick (ifid, type, data, len);
609 int simclick_sim_command (simclick_node_t *simnode,
int cmd, ...)
619 case SIMCLICK_VERSION:
625 case SIMCLICK_SUPPORTS:
627 int othercmd = va_arg (val,
int);
628 retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_DEFINES);
632 case SIMCLICK_IFID_FROM_NAME:
634 const char *ifname = va_arg (val,
const char *);
636 retval = clickInstance->GetInterfaceId (ifname);
638 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_IFID_FROM_NAME: " << ifname <<
" " << retval);
642 case SIMCLICK_IPADDR_FROM_NAME:
644 const char *ifname = va_arg (val,
const char *);
645 char *buf = va_arg (val,
char *);
646 int len = va_arg (val,
int);
648 int ifid = clickInstance->GetInterfaceId (ifname);
652 retval = simstrlcpy (buf, len, clickInstance->GetIpAddressFromInterfaceId (ifid));
659 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_IPADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
663 case SIMCLICK_IPPREFIX_FROM_NAME:
665 const char *ifname = va_arg (val,
const char *);
666 char *buf = va_arg (val,
char *);
667 int len = va_arg (val,
int);
669 int ifid = clickInstance->GetInterfaceId (ifname);
673 retval = simstrlcpy (buf, len, clickInstance->GetIpPrefixFromInterfaceId (ifid));
680 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_IPPREFIX_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
684 case SIMCLICK_MACADDR_FROM_NAME:
686 const char *ifname = va_arg (val,
const char *);
687 char *buf = va_arg (val,
char *);
688 int len = va_arg (val,
int);
689 int ifid = clickInstance->GetInterfaceId (ifname);
693 retval = simstrlcpy (buf, len, clickInstance->GetMacAddressFromInterfaceId (ifid));
700 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_MACADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
704 case SIMCLICK_SCHEDULE:
706 const struct timeval *when = va_arg (val,
const struct timeval *);
708 clickInstance->HandleScheduleFromClick (when);
711 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_SCHEDULE at " << when->tv_sec <<
"s and " << when->tv_usec <<
"usecs.");
716 case SIMCLICK_GET_NODE_NAME:
718 char *buf = va_arg (val,
char *);
719 int len = va_arg (val,
int);
720 retval = simstrlcpy (buf, len, clickInstance->GetNodeName ());
722 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" SIMCLICK_GET_NODE_NAME: " << buf <<
" " << len);
726 case SIMCLICK_IF_PROMISC:
728 int ifid = va_arg(val,
int);
729 clickInstance->SetPromisc (ifid);
736 case SIMCLICK_IF_READY:
738 int ifid = va_arg (val,
int);
741 retval = clickInstance->IsInterfaceReady (ifid);
750 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" Received a call for SIMCLICK_TRACE");
754 case SIMCLICK_GET_NODE_ID:
757 NS_LOG_DEBUG (clickInstance->GetNodeName () <<
" Received a call for SIMCLICK_GET_NODE_ID");
761 case SIMCLICK_GET_RANDOM_INT:
763 uint32_t *randomValue = va_arg (val, uint32_t *);
764 uint32_t maxValue = va_arg (val, uint32_t);
766 *randomValue =
static_cast<uint32_t
> (clickInstance->GetRandomVariable ()->GetValue (0.0, static_cast<double> (maxValue) + 1.0));
772 case SIMCLICK_GET_DEFINES:
774 char *buf = va_arg (val,
char *);
775 size_t *size = va_arg (val,
size_t *);
776 uint32_t required = 0;
784 std::map<std::string, std::string> defines = clickInstance->GetDefines ();
785 std::map<std::string, std::string>::const_iterator it = defines.begin ();
786 while (it != defines.end ())
788 size_t available = *size - required;
789 if (it->first.length() + it->second.length() + 2 <= available)
791 simstrlcpy(buf + required, available, it->first);
792 required += it->first.length() + 1;
793 available -= it->first.length() + 1;
794 simstrlcpy(buf + required, available, it->second);
795 required += it->second.length() + 1;
799 required += it->first.length() + it->second.length() + 2;
803 if (required > *size)