24#include "ns3/ipv4-interface.h"
25#include "ns3/ipv4-l3-click-protocol.h"
27#include "ns3/mac48-address.h"
29#include "ns3/random-variable-stream.h"
30#include "ns3/simulator.h"
32#include <click/simclick.h>
44#define INTERFACE_ID_KERNELTAP 0
45#define INTERFACE_ID_FIRST 1
46#define INTERFACE_ID_FIRST_DROP 33
50std::map<simclick_node_t*, Ptr<Ipv4ClickRouting>> Ipv4ClickRouting::m_clickInstanceFromSimNode;
55 static TypeId tid = TypeId(
"ns3::Ipv4ClickRouting")
57 .AddConstructor<Ipv4ClickRouting>()
63Ipv4ClickRouting::Ipv4ClickRouting()
64 : m_nonDefaultName(false),
67 m_random = CreateObject<UniformRandomVariable>();
69 timerclear(&m_simNode->curtime);
71 AddSimNodeToClickMapping();
74Ipv4ClickRouting::~Ipv4ClickRouting()
79Ipv4ClickRouting::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);
110Ipv4ClickRouting::SetIpv4(Ptr<Ipv4> ipv4)
115Ptr<UniformRandomVariable>
116Ipv4ClickRouting::GetRandomVariable()
122Ipv4ClickRouting::DoDispose()
124 if (m_clickInitialised)
126 simclick_click_kill(m_simNode);
130 Ipv4RoutingProtocol::DoDispose();
134Ipv4ClickRouting::SetClickFile(std::string clickfile)
136 m_clickFile = clickfile;
140Ipv4ClickRouting::SetDefines(std::map<std::string, std::string> defines)
145std::map<std::string, std::string>
146Ipv4ClickRouting::GetDefines()
152Ipv4ClickRouting::SetClickRoutingTableElement(std::string name)
154 m_clickRoutingTableElement = name;
158Ipv4ClickRouting::SetNodeName(std::string name)
161 m_nonDefaultName =
true;
165Ipv4ClickRouting::GetNodeName()
171Ipv4ClickRouting::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())
228Ipv4ClickRouting::IsInterfaceReady(
int ifid)
230 return ifid >= 0 && ifid < static_cast<int>(m_ipv4->GetNInterfaces());
234Ipv4ClickRouting::GetIpAddressFromInterfaceId(
int ifid)
236 std::stringstream addr;
237 m_ipv4->GetAddress(ifid, 0).GetLocal().Print(addr);
243Ipv4ClickRouting::GetIpPrefixFromInterfaceId(
int ifid)
245 std::stringstream addr;
246 m_ipv4->GetAddress(ifid, 0).GetMask().Print(addr);
252Ipv4ClickRouting::GetMacAddressFromInterfaceId(
int ifid)
254 std::stringstream addr;
256 Ptr<NetDevice> device = m_ipv4->GetNetDevice(ifid);
257 Address devAddr = device->GetAddress();
258 addr << Mac48Address::ConvertFrom(devAddr);
264Ipv4ClickRouting::AddSimNodeToClickMapping()
266 m_clickInstanceFromSimNode.insert(std::make_pair(m_simNode,
this));
272 return m_clickInstanceFromSimNode[simnode];
276Ipv4ClickRouting::GetTimevalFromNow() const
278 struct timeval curtime;
279 uint64_t remainder = 0;
281 Time now = Simulator::Now();
283 curtime.tv_sec = now.GetSeconds();
284 curtime.tv_usec = now.GetMicroSeconds() % 1000000;
286 switch (Time::GetResolution())
289 remainder = now.GetNanoSeconds() % 1000;
292 remainder = now.GetPicoSeconds() % 1000000;
295 remainder = now.GetFemtoSeconds() % 1000000000;
304 if (curtime.tv_usec == 1000000)
315Ipv4ClickRouting::RunClickEvent()
317 m_simNode->curtime = GetTimevalFromNow();
319 NS_LOG_DEBUG(
"RunClickEvent at " << m_simNode->curtime.tv_sec <<
" "
320 << m_simNode->curtime.tv_usec <<
" " << Simulator::Now());
321 simclick_click_run(m_simNode);
325Ipv4ClickRouting::HandleScheduleFromClick(
const struct timeval* when)
327 NS_LOG_DEBUG(
"HandleScheduleFromClick at " << when->tv_sec <<
" " << when->tv_usec <<
" "
328 << Simulator::Now());
331 Time::FromInteger(when->tv_sec, Time::S) + Time::FromInteger(when->tv_usec, Time::US);
332 Time simdelay = simtime - Simulator::Now();
334 Simulator::Schedule(simdelay, &Ipv4ClickRouting::RunClickEvent,
this);
338Ipv4ClickRouting::HandlePacketFromClick(
int ifid,
int ptype,
const unsigned char*
data,
int len)
347 NS_LOG_DEBUG(
"Incoming packet from tap0. Sending Packet up the stack.");
348 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol>(m_ipv4);
350 Ptr<Packet> p = Create<Packet>(
data, len);
353 p->RemoveHeader(ipHeader);
355 ipv4l3->LocalDeliver(p, ipHeader, (
uint32_t)ifid);
359 NS_LOG_DEBUG(
"Incoming packet from eth" << ifid - 1 <<
" of type " << ptype
360 <<
". Sending packet down the stack.");
362 Ptr<Packet> p = Create<Packet>(
data, len);
364 DynamicCast<Ipv4L3ClickProtocol>(m_ipv4)->SendDown(p, ifid);
369Ipv4ClickRouting::SendPacketToClick(
int ifid,
int ptype,
const unsigned char*
data,
int len)
372 m_simNode->curtime = GetTimevalFromNow();
376 simclick_simpacketinfo pinfo;
380 simclick_click_send(m_simNode, ifid, ptype,
data, len, &pinfo);
384Ipv4ClickRouting::Send(Ptr<Packet> p, Ipv4Address src, Ipv4Address dst)
389 for (ifid = 0; ifid < m_ipv4->GetNInterfaces(); ifid++)
391 Ipv4Address addr = m_ipv4->GetAddress(ifid, 0).GetLocal();
399 int len = p->GetSize();
400 uint8_t* buf =
new uint8_t[len];
401 p->CopyData(buf, len);
404 SendPacketToClick(0, SIMCLICK_PTYPE_IP, buf, len);
410Ipv4ClickRouting::Receive(Ptr<Packet> p, Mac48Address receiverAddr, Mac48Address dest)
417 for (ifid = 0; ifid < m_ipv4->GetNInterfaces(); ifid++)
419 Ptr<NetDevice> device = m_ipv4->GetNetDevice(ifid);
421 if (Mac48Address::ConvertFrom(device->GetAddress()) == receiverAddr)
427 int len = p->GetSize();
428 uint8_t* buf =
new uint8_t[len];
429 p->CopyData(buf, len);
432 SendPacketToClick(ifid, SIMCLICK_PTYPE_ETHER, buf, len);
438Ipv4ClickRouting::ReadHandler(std::string elementName, std::string handlerName)
440 char* handle = simclick_click_read_handler(m_simNode,
445 std::string ret(handle);
456Ipv4ClickRouting::WriteHandler(std::string elementName,
457 std::string handlerName,
458 std::string writeString)
460 int r = simclick_click_write_handler(m_simNode,
463 writeString.c_str());
475Ipv4ClickRouting::SetPromisc(
int ifid)
477 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol>(m_ipv4);
479 ipv4l3->SetPromisc(ifid);
483Ipv4ClickRouting::RouteOutput(Ptr<Packet> p,
484 const Ipv4Header& header,
486 Socket::SocketErrno& sockerr)
488 Ptr<Ipv4Route> rtentry;
490 std::stringstream addr;
492 header.GetDestination().Print(addr);
495 NS_LOG_DEBUG(
"Probe click routing table for " << addr.str());
496 std::string s = ReadHandler(m_clickRoutingTableElement, addr.str());
499 size_t pos = s.find(
' ');
500 Ipv4Address destination;
502 if (pos == std::string::npos)
505 destination = Ipv4Address(
"0.0.0.0");
506 interfaceId = atoi(s.c_str());
507 NS_LOG_DEBUG(
"case 1: destination " << destination <<
" interfaceId " << interfaceId);
511 interfaceId = atoi(s.substr(0, pos).c_str());
512 Ipv4Address destination(s.substr(pos + 1).c_str());
513 NS_LOG_DEBUG(
"case 2: destination " << destination <<
" interfaceId " << interfaceId);
516 if (interfaceId != -1)
518 rtentry = Create<Ipv4Route>();
519 rtentry->SetDestination(header.GetDestination());
524 uint32_t numOifAddresses = m_ipv4->GetNAddresses(interfaceId);
526 Ipv4InterfaceAddress ifAddr;
527 if (numOifAddresses == 1)
529 ifAddr = m_ipv4->GetAddress(interfaceId, 0);
536 rtentry->SetSource(ifAddr.GetLocal());
537 rtentry->SetGateway(destination);
538 rtentry->SetOutputDevice(m_ipv4->GetNetDevice(interfaceId));
539 sockerr = Socket::ERROR_NOTERROR;
540 NS_LOG_DEBUG(
"Found route to " << rtentry->GetDestination() <<
" via nh "
541 << rtentry->GetGateway() <<
" with source addr "
542 << rtentry->GetSource() <<
" and output dev "
543 << rtentry->GetOutputDevice());
547 NS_LOG_DEBUG(
"Click node " << m_nodeName <<
": RouteOutput for dest="
548 << header.GetDestination() <<
" No route to host");
549 sockerr = Socket::ERROR_NOROUTETOHOST;
558Ipv4ClickRouting::RouteInput(Ptr<const Packet> p,
559 const Ipv4Header& header,
560 Ptr<const NetDevice> idev,
561 const UnicastForwardCallback& ucb,
562 const MulticastForwardCallback& mcb,
563 const LocalDeliverCallback& lcb,
564 const ErrorCallback& ecb)
566 NS_FATAL_ERROR(
"Click router does not have a RouteInput() interface!");
571Ipv4ClickRouting::PrintRoutingTable(Ptr<OutputStreamWrapper> stream, Time::Unit unit)
const
573 *stream->GetStream() <<
"\nCLICK Routing table printing is not yet implemented, skipping.\n";
577Ipv4ClickRouting::NotifyInterfaceUp(
uint32_t i)
582Ipv4ClickRouting::NotifyInterfaceDown(
uint32_t i)
587Ipv4ClickRouting::NotifyAddAddress(
uint32_t interface, Ipv4InterfaceAddress address)
592Ipv4ClickRouting::NotifyRemoveAddress(
uint32_t interface, Ipv4InterfaceAddress address)
601simstrlcpy(
char* buf,
int len,
const std::string& s)
607 if ((
unsigned)len > s.length())
624 const unsigned char*
data,
626 simclick_simpacketinfo* pinfo)
629 << ifid <<
" " << type <<
" " <<
data <<
" "
638 ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode(simnode);
640 clickInstance->HandlePacketFromClick(ifid, type,
data, len);
655 ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode(simnode);
658 case SIMCLICK_VERSION: {
663 case SIMCLICK_SUPPORTS: {
664 int othercmd = va_arg(val,
int);
665 retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_DEFINES);
669 case SIMCLICK_IFID_FROM_NAME: {
670 const char* ifname = va_arg(val,
const char*);
672 retval = clickInstance->GetInterfaceId(ifname);
675 <<
" SIMCLICK_IFID_FROM_NAME: " << ifname <<
" " << retval);
679 case SIMCLICK_IPADDR_FROM_NAME: {
680 const char* ifname = va_arg(val,
const char*);
681 char* buf = va_arg(val,
char*);
682 int len = va_arg(val,
int);
684 int ifid = clickInstance->GetInterfaceId(ifname);
688 retval = simstrlcpy(buf, len, clickInstance->GetIpAddressFromInterfaceId(ifid));
696 <<
" SIMCLICK_IPADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
700 case SIMCLICK_IPPREFIX_FROM_NAME: {
701 const char* ifname = va_arg(val,
const char*);
702 char* buf = va_arg(val,
char*);
703 int len = va_arg(val,
int);
705 int ifid = clickInstance->GetInterfaceId(ifname);
709 retval = simstrlcpy(buf, len, clickInstance->GetIpPrefixFromInterfaceId(ifid));
717 <<
" SIMCLICK_IPPREFIX_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
721 case SIMCLICK_MACADDR_FROM_NAME: {
722 const char* ifname = va_arg(val,
const char*);
723 char* buf = va_arg(val,
char*);
724 int len = va_arg(val,
int);
725 int ifid = clickInstance->GetInterfaceId(ifname);
729 retval = simstrlcpy(buf, len, clickInstance->GetMacAddressFromInterfaceId(ifid));
737 <<
" SIMCLICK_MACADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
741 case SIMCLICK_SCHEDULE: {
742 const struct timeval* when = va_arg(val,
const struct timeval*);
744 clickInstance->HandleScheduleFromClick(when);
747 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" SIMCLICK_SCHEDULE at " << when->tv_sec
748 <<
"s and " << when->tv_usec <<
"usecs.");
753 case SIMCLICK_GET_NODE_NAME: {
754 char* buf = va_arg(val,
char*);
755 int len = va_arg(val,
int);
756 retval = simstrlcpy(buf, len, clickInstance->GetNodeName());
759 <<
" SIMCLICK_GET_NODE_NAME: " << buf <<
" " << len);
763 case SIMCLICK_IF_PROMISC: {
764 int ifid = va_arg(val,
int);
765 clickInstance->SetPromisc(ifid);
773 case SIMCLICK_IF_READY: {
774 int ifid = va_arg(val,
int);
777 retval = clickInstance->IsInterfaceReady(ifid);
784 case SIMCLICK_TRACE: {
786 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" Received a call for SIMCLICK_TRACE");
790 case SIMCLICK_GET_NODE_ID: {
792 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" Received a call for SIMCLICK_GET_NODE_ID");
796 case SIMCLICK_GET_RANDOM_INT: {
800 *randomValue =
static_cast<uint32_t>(
801 clickInstance->GetRandomVariable()->GetValue(0.0,
static_cast<double>(maxValue) + 1.0));
803 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" SIMCLICK_RANDOM: " << *randomValue <<
" "
808 case SIMCLICK_GET_DEFINES: {
809 char* buf = va_arg(val,
char*);
810 size_t* size = va_arg(val,
size_t*);
819 std::map<std::string, std::string> defines = clickInstance->GetDefines();
820 std::map<std::string, std::string>::const_iterator it = defines.begin();
821 while (it != defines.end())
823 size_t available = *size - required;
824 if (it->first.length() + it->second.length() + 2 <= available)
826 simstrlcpy(buf + required, available, it->first);
827 required += it->first.length() + 1;
828 available -= it->first.length() + 1;
829 simstrlcpy(buf + required, available, it->second);
830 required += it->second.length() + 1;
834 required += it->first.length() + it->second.length() + 2;
838 if (required > *size)
static TypeId GetTypeId()
Get the type ID.
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
TypeId SetGroupName(std::string groupName)
Set the group name.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
struct simclick_node simclick_node_t
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.