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 if (ifid >= 0 && ifid < (
int)m_ipv4->GetNInterfaces())
241Ipv4ClickRouting::GetIpAddressFromInterfaceId(
int ifid)
243 std::stringstream addr;
244 m_ipv4->GetAddress(ifid, 0).GetLocal().Print(addr);
250Ipv4ClickRouting::GetIpPrefixFromInterfaceId(
int ifid)
252 std::stringstream addr;
253 m_ipv4->GetAddress(ifid, 0).GetMask().Print(addr);
259Ipv4ClickRouting::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);
271Ipv4ClickRouting::AddSimNodeToClickMapping()
273 m_clickInstanceFromSimNode.insert(std::make_pair(m_simNode,
this));
279 return m_clickInstanceFromSimNode[simnode];
283Ipv4ClickRouting::GetTimevalFromNow() const
285 struct timeval curtime;
286 uint64_t remainder = 0;
288 curtime.tv_sec = Simulator::Now().GetSeconds();
289 curtime.tv_usec = Simulator::Now().GetMicroSeconds() % 1000000;
291 switch (Simulator::Now().GetResolution())
294 remainder = Simulator::Now().GetNanoSeconds() % 1000;
297 remainder = Simulator::Now().GetPicoSeconds() % 1000000;
300 remainder = Simulator::Now().GetFemtoSeconds() % 1000000000;
309 if (curtime.tv_usec == 1000000)
320Ipv4ClickRouting::RunClickEvent()
322 m_simNode->curtime = GetTimevalFromNow();
324 NS_LOG_DEBUG(
"RunClickEvent at " << m_simNode->curtime.tv_sec <<
" "
325 << m_simNode->curtime.tv_usec <<
" " << Simulator::Now());
326 simclick_click_run(m_simNode);
330Ipv4ClickRouting::HandleScheduleFromClick(
const struct timeval* when)
332 NS_LOG_DEBUG(
"HandleScheduleFromClick at " << when->tv_sec <<
" " << when->tv_usec <<
" "
333 << Simulator::Now());
336 Time::FromInteger(when->tv_sec, Time::S) + Time::FromInteger(when->tv_usec, Time::US);
337 Time simdelay = simtime - Simulator::Now();
339 Simulator::Schedule(simdelay, &Ipv4ClickRouting::RunClickEvent,
this);
343Ipv4ClickRouting::HandlePacketFromClick(
int ifid,
int ptype,
const unsigned char*
data,
int len)
352 NS_LOG_DEBUG(
"Incoming packet from tap0. Sending Packet up the stack.");
353 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol>(m_ipv4);
355 Ptr<Packet> p = Create<Packet>(
data, len);
358 p->RemoveHeader(ipHeader);
360 ipv4l3->LocalDeliver(p, ipHeader, (
uint32_t)ifid);
364 NS_LOG_DEBUG(
"Incoming packet from eth" << ifid - 1 <<
" of type " << ptype
365 <<
". Sending packet down the stack.");
367 Ptr<Packet> p = Create<Packet>(
data, len);
369 DynamicCast<Ipv4L3ClickProtocol>(m_ipv4)->SendDown(p, ifid);
374Ipv4ClickRouting::SendPacketToClick(
int ifid,
int ptype,
const unsigned char*
data,
int len)
377 m_simNode->curtime = GetTimevalFromNow();
381 simclick_simpacketinfo pinfo;
385 simclick_click_send(m_simNode, ifid, ptype,
data, len, &pinfo);
389Ipv4ClickRouting::Send(Ptr<Packet> p, Ipv4Address src, Ipv4Address dst)
394 for (ifid = 0; ifid < m_ipv4->GetNInterfaces(); ifid++)
396 Ipv4Address addr = m_ipv4->GetAddress(ifid, 0).GetLocal();
404 int len = p->GetSize();
405 uint8_t* buf =
new uint8_t[len];
406 p->CopyData(buf, len);
409 SendPacketToClick(0, SIMCLICK_PTYPE_IP, buf, len);
415Ipv4ClickRouting::Receive(Ptr<Packet> p, Mac48Address receiverAddr, Mac48Address dest)
422 for (ifid = 0; ifid < m_ipv4->GetNInterfaces(); ifid++)
424 Ptr<NetDevice> device = m_ipv4->GetNetDevice(ifid);
426 if (Mac48Address::ConvertFrom(device->GetAddress()) == receiverAddr)
432 int len = p->GetSize();
433 uint8_t* buf =
new uint8_t[len];
434 p->CopyData(buf, len);
437 SendPacketToClick(ifid, SIMCLICK_PTYPE_ETHER, buf, len);
443Ipv4ClickRouting::ReadHandler(std::string elementName, std::string handlerName)
445 char* handle = simclick_click_read_handler(m_simNode,
450 std::string ret(handle);
461Ipv4ClickRouting::WriteHandler(std::string elementName,
462 std::string handlerName,
463 std::string writeString)
465 int r = simclick_click_write_handler(m_simNode,
468 writeString.c_str());
480Ipv4ClickRouting::SetPromisc(
int ifid)
482 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol>(m_ipv4);
484 ipv4l3->SetPromisc(ifid);
488Ipv4ClickRouting::RouteOutput(Ptr<Packet> p,
489 const Ipv4Header& header,
491 Socket::SocketErrno& sockerr)
493 Ptr<Ipv4Route> rtentry;
495 std::stringstream addr;
497 header.GetDestination().Print(addr);
500 NS_LOG_DEBUG(
"Probe click routing table for " << addr.str());
501 std::string s = ReadHandler(m_clickRoutingTableElement, addr.str());
504 size_t pos = s.find(
' ');
505 Ipv4Address destination;
507 if (pos == std::string::npos)
510 destination = Ipv4Address(
"0.0.0.0");
511 interfaceId = atoi(s.c_str());
512 NS_LOG_DEBUG(
"case 1: destination " << destination <<
" interfaceId " << interfaceId);
516 interfaceId = atoi(s.substr(0, pos).c_str());
517 Ipv4Address destination(s.substr(pos + 1).c_str());
518 NS_LOG_DEBUG(
"case 2: destination " << destination <<
" interfaceId " << interfaceId);
521 if (interfaceId != -1)
523 rtentry = Create<Ipv4Route>();
524 rtentry->SetDestination(header.GetDestination());
529 uint32_t numOifAddresses = m_ipv4->GetNAddresses(interfaceId);
531 Ipv4InterfaceAddress ifAddr;
532 if (numOifAddresses == 1)
534 ifAddr = m_ipv4->GetAddress(interfaceId, 0);
541 rtentry->SetSource(ifAddr.GetLocal());
542 rtentry->SetGateway(destination);
543 rtentry->SetOutputDevice(m_ipv4->GetNetDevice(interfaceId));
544 sockerr = Socket::ERROR_NOTERROR;
545 NS_LOG_DEBUG(
"Found route to " << rtentry->GetDestination() <<
" via nh "
546 << rtentry->GetGateway() <<
" with source addr "
547 << rtentry->GetSource() <<
" and output dev "
548 << rtentry->GetOutputDevice());
552 NS_LOG_DEBUG(
"Click node " << m_nodeName <<
": RouteOutput for dest="
553 << header.GetDestination() <<
" No route to host");
554 sockerr = Socket::ERROR_NOROUTETOHOST;
563Ipv4ClickRouting::RouteInput(Ptr<const Packet> p,
564 const Ipv4Header& header,
565 Ptr<const NetDevice> idev,
566 UnicastForwardCallback ucb,
567 MulticastForwardCallback mcb,
568 LocalDeliverCallback lcb,
571 NS_FATAL_ERROR(
"Click router does not have a RouteInput() interface!");
576Ipv4ClickRouting::PrintRoutingTable(Ptr<OutputStreamWrapper> stream, Time::Unit unit)
const
578 *stream->GetStream() <<
"\nCLICK Routing table printing is not yet implemented, skipping.\n";
582Ipv4ClickRouting::NotifyInterfaceUp(
uint32_t i)
587Ipv4ClickRouting::NotifyInterfaceDown(
uint32_t i)
592Ipv4ClickRouting::NotifyAddAddress(
uint32_t interface, Ipv4InterfaceAddress address)
597Ipv4ClickRouting::NotifyRemoveAddress(
uint32_t interface, Ipv4InterfaceAddress address)
606simstrlcpy(
char* buf,
int len,
const std::string& s)
612 if ((
unsigned)len > s.length())
629 const unsigned char*
data,
631 simclick_simpacketinfo* pinfo)
634 << ifid <<
" " << type <<
" " <<
data <<
" "
643 ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode(simnode);
645 clickInstance->HandlePacketFromClick(ifid, type,
data, len);
660 ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode(simnode);
663 case SIMCLICK_VERSION: {
668 case SIMCLICK_SUPPORTS: {
669 int othercmd = va_arg(val,
int);
670 retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_DEFINES);
674 case SIMCLICK_IFID_FROM_NAME: {
675 const char* ifname = va_arg(val,
const char*);
677 retval = clickInstance->GetInterfaceId(ifname);
680 <<
" SIMCLICK_IFID_FROM_NAME: " << ifname <<
" " << retval);
684 case SIMCLICK_IPADDR_FROM_NAME: {
685 const char* ifname = va_arg(val,
const char*);
686 char* buf = va_arg(val,
char*);
687 int len = va_arg(val,
int);
689 int ifid = clickInstance->GetInterfaceId(ifname);
693 retval = simstrlcpy(buf, len, clickInstance->GetIpAddressFromInterfaceId(ifid));
701 <<
" SIMCLICK_IPADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
705 case SIMCLICK_IPPREFIX_FROM_NAME: {
706 const char* ifname = va_arg(val,
const char*);
707 char* buf = va_arg(val,
char*);
708 int len = va_arg(val,
int);
710 int ifid = clickInstance->GetInterfaceId(ifname);
714 retval = simstrlcpy(buf, len, clickInstance->GetIpPrefixFromInterfaceId(ifid));
722 <<
" SIMCLICK_IPPREFIX_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
726 case SIMCLICK_MACADDR_FROM_NAME: {
727 const char* ifname = va_arg(val,
const char*);
728 char* buf = va_arg(val,
char*);
729 int len = va_arg(val,
int);
730 int ifid = clickInstance->GetInterfaceId(ifname);
734 retval = simstrlcpy(buf, len, clickInstance->GetMacAddressFromInterfaceId(ifid));
742 <<
" SIMCLICK_MACADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
746 case SIMCLICK_SCHEDULE: {
747 const struct timeval* when = va_arg(val,
const struct timeval*);
749 clickInstance->HandleScheduleFromClick(when);
752 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" SIMCLICK_SCHEDULE at " << when->tv_sec
753 <<
"s and " << when->tv_usec <<
"usecs.");
758 case SIMCLICK_GET_NODE_NAME: {
759 char* buf = va_arg(val,
char*);
760 int len = va_arg(val,
int);
761 retval = simstrlcpy(buf, len, clickInstance->GetNodeName());
764 <<
" SIMCLICK_GET_NODE_NAME: " << buf <<
" " << len);
768 case SIMCLICK_IF_PROMISC: {
769 int ifid = va_arg(val,
int);
770 clickInstance->SetPromisc(ifid);
778 case SIMCLICK_IF_READY: {
779 int ifid = va_arg(val,
int);
782 retval = clickInstance->IsInterfaceReady(ifid);
789 case SIMCLICK_TRACE: {
791 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" Received a call for SIMCLICK_TRACE");
795 case SIMCLICK_GET_NODE_ID: {
797 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" Received a call for SIMCLICK_GET_NODE_ID");
801 case SIMCLICK_GET_RANDOM_INT: {
805 *randomValue =
static_cast<uint32_t>(
806 clickInstance->GetRandomVariable()->GetValue(0.0,
static_cast<double>(maxValue) + 1.0));
808 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" SIMCLICK_RANDOM: " << *randomValue <<
" "
813 case SIMCLICK_GET_DEFINES: {
814 char* buf = va_arg(val,
char*);
815 size_t* size = va_arg(val,
size_t*);
824 std::map<std::string, std::string> defines = clickInstance->GetDefines();
825 std::map<std::string, std::string>::const_iterator it = defines.begin();
826 while (it != defines.end())
828 size_t available = *size - required;
829 if (it->first.length() + it->second.length() + 2 <= available)
831 simstrlcpy(buf + required, available, it->first);
832 required += it->first.length() + 1;
833 available -= it->first.length() + 1;
834 simstrlcpy(buf + required, available, it->second);
835 required += it->second.length() + 1;
839 required += it->first.length() + it->second.length() + 2;
843 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.