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"
43#define INTERFACE_ID_KERNELTAP 0
44#define INTERFACE_ID_FIRST 1
45#define INTERFACE_ID_FIRST_DROP 33
49std::map<simclick_node_t*, Ptr<Ipv4ClickRouting>> Ipv4ClickRouting::m_clickInstanceFromSimNode;
54 static TypeId tid = TypeId(
"ns3::Ipv4ClickRouting")
56 .AddConstructor<Ipv4ClickRouting>()
62Ipv4ClickRouting::Ipv4ClickRouting()
63 : m_nonDefaultName(false),
66 m_random = CreateObject<UniformRandomVariable>();
67 m_simNode =
new simclick_node_t;
68 timerclear(&m_simNode->curtime);
70 AddSimNodeToClickMapping();
73Ipv4ClickRouting::~Ipv4ClickRouting()
78Ipv4ClickRouting::DoInitialize()
80 uint32_t id = m_ipv4->GetObject<Node>()->GetId();
82 if (!m_nonDefaultName)
84 std::stringstream name;
86 m_nodeName = name.str();
93 if (simclick_click_create(m_simNode, m_clickFile.c_str()) >= 0)
95 NS_LOG_DEBUG(m_nodeName <<
" has initialised a Click Router");
96 m_clickInitialised =
true;
100 NS_LOG_DEBUG(
"Click Router Initialisation failed for " << m_nodeName);
101 m_clickInitialised =
false;
105 simclick_click_run(m_simNode);
114Ptr<UniformRandomVariable>
115Ipv4ClickRouting::GetRandomVariable()
121Ipv4ClickRouting::DoDispose()
123 if (m_clickInitialised)
125 simclick_click_kill(m_simNode);
129 Ipv4RoutingProtocol::DoDispose();
133Ipv4ClickRouting::SetClickFile(std::string clickfile)
135 m_clickFile = clickfile;
139Ipv4ClickRouting::SetDefines(std::map<std::string, std::string> defines)
144std::map<std::string, std::string>
145Ipv4ClickRouting::GetDefines()
151Ipv4ClickRouting::SetClickRoutingTableElement(std::string name)
153 m_clickRoutingTableElement = name;
157Ipv4ClickRouting::SetNodeName(std::string name)
160 m_nonDefaultName =
true;
164Ipv4ClickRouting::GetNodeName()
170Ipv4ClickRouting::GetInterfaceId(
const char* ifname)
186 if (strstr(ifname,
"tap") || strstr(ifname,
"tun"))
190 else if (
const char* devname = strstr(ifname,
"eth"))
192 while (*devname && !isdigit((
unsigned char)*devname))
199 retval = atoi(devname) + INTERFACE_ID_FIRST;
202 else if (
const char* devname = strstr(ifname,
"drop"))
204 while (*devname && !isdigit((
unsigned char)*devname))
210 retval = atoi(devname) + INTERFACE_ID_FIRST_DROP;
218 if (retval >= (
int)m_ipv4->GetNInterfaces())
227Ipv4ClickRouting::IsInterfaceReady(
int ifid)
229 if (ifid >= 0 && ifid < (
int)m_ipv4->GetNInterfaces())
240Ipv4ClickRouting::GetIpAddressFromInterfaceId(
int ifid)
242 std::stringstream addr;
243 m_ipv4->GetAddress(ifid, 0).GetLocal().Print(addr);
249Ipv4ClickRouting::GetIpPrefixFromInterfaceId(
int ifid)
251 std::stringstream addr;
252 m_ipv4->GetAddress(ifid, 0).GetMask().Print(addr);
258Ipv4ClickRouting::GetMacAddressFromInterfaceId(
int ifid)
260 std::stringstream addr;
262 Ptr<NetDevice> device = m_ipv4->GetNetDevice(ifid);
263 Address devAddr = device->GetAddress();
264 addr << Mac48Address::ConvertFrom(devAddr);
270Ipv4ClickRouting::AddSimNodeToClickMapping()
272 m_clickInstanceFromSimNode.insert(std::make_pair(m_simNode,
this));
276Ipv4ClickRouting::GetClickInstanceFromSimNode(simclick_node_t* simnode)
278 return m_clickInstanceFromSimNode[simnode];
282Ipv4ClickRouting::GetTimevalFromNow() const
284 struct timeval curtime;
285 uint64_t remainder = 0;
308 if (curtime.tv_usec == 1000000)
319Ipv4ClickRouting::RunClickEvent()
321 m_simNode->curtime = GetTimevalFromNow();
323 NS_LOG_DEBUG(
"RunClickEvent at " << m_simNode->curtime.tv_sec <<
" "
325 simclick_click_run(m_simNode);
329Ipv4ClickRouting::HandleScheduleFromClick(
const struct timeval* when)
331 NS_LOG_DEBUG(
"HandleScheduleFromClick at " << when->tv_sec <<
" " << when->tv_usec <<
" "
335 Time::FromInteger(when->tv_sec, Time::S) + Time::FromInteger(when->tv_usec, Time::US);
338 Simulator::Schedule(simdelay, &Ipv4ClickRouting::RunClickEvent,
this);
342Ipv4ClickRouting::HandlePacketFromClick(
int ifid,
int ptype,
const unsigned char*
data,
int len)
351 NS_LOG_DEBUG(
"Incoming packet from tap0. Sending Packet up the stack.");
352 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol>(m_ipv4);
354 Ptr<Packet> p = Create<Packet>(
data, len);
357 p->RemoveHeader(ipHeader);
359 ipv4l3->LocalDeliver(p, ipHeader, (
uint32_t)ifid);
363 NS_LOG_DEBUG(
"Incoming packet from eth" << ifid - 1 <<
" of type " << ptype
364 <<
". Sending packet down the stack.");
366 Ptr<Packet> p = Create<Packet>(
data, len);
368 DynamicCast<Ipv4L3ClickProtocol>(m_ipv4)->SendDown(p, ifid);
373Ipv4ClickRouting::SendPacketToClick(
int ifid,
int ptype,
const unsigned char*
data,
int len)
376 m_simNode->curtime = GetTimevalFromNow();
380 simclick_simpacketinfo pinfo;
384 simclick_click_send(m_simNode, ifid, ptype,
data, len, &pinfo);
393 for (ifid = 0; ifid < m_ipv4->GetNInterfaces(); ifid++)
395 Ipv4Address addr = m_ipv4->GetAddress(ifid, 0).GetLocal();
403 int len = p->GetSize();
404 uint8_t* buf =
new uint8_t[len];
405 p->CopyData(buf, len);
408 SendPacketToClick(0, SIMCLICK_PTYPE_IP, buf, len);
414Ipv4ClickRouting::Receive(Ptr<Packet> p, Mac48Address receiverAddr, Mac48Address dest)
421 for (ifid = 0; ifid < m_ipv4->GetNInterfaces(); ifid++)
423 Ptr<NetDevice> device = m_ipv4->GetNetDevice(ifid);
425 if (Mac48Address::ConvertFrom(device->GetAddress()) == receiverAddr)
431 int len = p->GetSize();
432 uint8_t* buf =
new uint8_t[len];
433 p->CopyData(buf, len);
436 SendPacketToClick(ifid, SIMCLICK_PTYPE_ETHER, buf, len);
442Ipv4ClickRouting::ReadHandler(std::string elementName, std::string handlerName)
444 char* handle = simclick_click_read_handler(m_simNode,
449 std::string ret(handle);
460Ipv4ClickRouting::WriteHandler(std::string elementName,
461 std::string handlerName,
462 std::string writeString)
464 int r = simclick_click_write_handler(m_simNode,
467 writeString.c_str());
479Ipv4ClickRouting::SetPromisc(
int ifid)
481 Ptr<Ipv4L3ClickProtocol> ipv4l3 = DynamicCast<Ipv4L3ClickProtocol>(m_ipv4);
483 ipv4l3->SetPromisc(ifid);
487Ipv4ClickRouting::RouteOutput(Ptr<Packet> p,
488 const Ipv4Header& header,
490 Socket::SocketErrno& sockerr)
492 Ptr<Ipv4Route> rtentry;
494 std::stringstream addr;
496 header.GetDestination().Print(addr);
499 NS_LOG_DEBUG(
"Probe click routing table for " << addr.str());
500 std::string s = ReadHandler(m_clickRoutingTableElement, addr.str());
503 size_t pos = s.find(
' ');
504 Ipv4Address destination;
506 if (pos == std::string::npos)
509 destination = Ipv4Address(
"0.0.0.0");
510 interfaceId = atoi(s.c_str());
511 NS_LOG_DEBUG(
"case 1: destination " << destination <<
" interfaceId " << interfaceId);
515 interfaceId = atoi(s.substr(0, pos).c_str());
516 Ipv4Address destination(s.substr(pos + 1).c_str());
517 NS_LOG_DEBUG(
"case 2: destination " << destination <<
" interfaceId " << interfaceId);
520 if (interfaceId != -1)
522 rtentry = Create<Ipv4Route>();
523 rtentry->SetDestination(header.GetDestination());
528 uint32_t numOifAddresses = m_ipv4->GetNAddresses(interfaceId);
530 Ipv4InterfaceAddress ifAddr;
531 if (numOifAddresses == 1)
533 ifAddr = m_ipv4->GetAddress(interfaceId, 0);
540 rtentry->SetSource(ifAddr.GetLocal());
541 rtentry->SetGateway(destination);
542 rtentry->SetOutputDevice(m_ipv4->GetNetDevice(interfaceId));
543 sockerr = Socket::ERROR_NOTERROR;
544 NS_LOG_DEBUG(
"Found route to " << rtentry->GetDestination() <<
" via nh "
545 << rtentry->GetGateway() <<
" with source addr "
546 << rtentry->GetSource() <<
" and output dev "
547 << rtentry->GetOutputDevice());
551 NS_LOG_DEBUG(
"Click node " << m_nodeName <<
": RouteOutput for dest="
552 << header.GetDestination() <<
" No route to host");
553 sockerr = Socket::ERROR_NOROUTETOHOST;
562Ipv4ClickRouting::RouteInput(Ptr<const Packet> p,
563 const Ipv4Header& header,
564 Ptr<const NetDevice> idev,
565 UnicastForwardCallback ucb,
566 MulticastForwardCallback mcb,
567 LocalDeliverCallback lcb,
570 NS_FATAL_ERROR(
"Click router does not have a RouteInput() interface!");
575Ipv4ClickRouting::PrintRoutingTable(Ptr<OutputStreamWrapper> stream,
Time::Unit unit)
const
577 *stream->GetStream() <<
"\nCLICK Routing table printing is not yet implemented, skipping.\n";
581Ipv4ClickRouting::NotifyInterfaceUp(
uint32_t i)
586Ipv4ClickRouting::NotifyInterfaceDown(
uint32_t i)
591Ipv4ClickRouting::NotifyAddAddress(
uint32_t interface, Ipv4InterfaceAddress
address)
596Ipv4ClickRouting::NotifyRemoveAddress(
uint32_t interface, Ipv4InterfaceAddress
address)
605simstrlcpy(
char* buf,
int len,
const std::string& s)
611 if ((
unsigned)len > s.length())
625simclick_sim_send(simclick_node_t* simnode,
628 const unsigned char*
data,
630 simclick_simpacketinfo* pinfo)
633 << ifid <<
" " <<
type <<
" " <<
data <<
" "
642 ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode(simnode);
644 clickInstance->HandlePacketFromClick(ifid,
type,
data, len);
651simclick_sim_command(simclick_node_t* simnode,
int cmd, ...)
659 ns3::Ipv4ClickRouting::GetClickInstanceFromSimNode(simnode);
662 case SIMCLICK_VERSION: {
667 case SIMCLICK_SUPPORTS: {
668 int othercmd = va_arg(val,
int);
669 retval = (othercmd >= SIMCLICK_VERSION && othercmd <= SIMCLICK_GET_DEFINES);
673 case SIMCLICK_IFID_FROM_NAME: {
674 const char* ifname = va_arg(val,
const char*);
676 retval = clickInstance->GetInterfaceId(ifname);
679 <<
" SIMCLICK_IFID_FROM_NAME: " << ifname <<
" " << retval);
683 case SIMCLICK_IPADDR_FROM_NAME: {
684 const char* ifname = va_arg(val,
const char*);
685 char* buf = va_arg(val,
char*);
686 int len = va_arg(val,
int);
688 int ifid = clickInstance->GetInterfaceId(ifname);
692 retval = simstrlcpy(buf, len, clickInstance->GetIpAddressFromInterfaceId(ifid));
700 <<
" SIMCLICK_IPADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
704 case SIMCLICK_IPPREFIX_FROM_NAME: {
705 const char* ifname = va_arg(val,
const char*);
706 char* buf = va_arg(val,
char*);
707 int len = va_arg(val,
int);
709 int ifid = clickInstance->GetInterfaceId(ifname);
713 retval = simstrlcpy(buf, len, clickInstance->GetIpPrefixFromInterfaceId(ifid));
721 <<
" SIMCLICK_IPPREFIX_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
725 case SIMCLICK_MACADDR_FROM_NAME: {
726 const char* ifname = va_arg(val,
const char*);
727 char* buf = va_arg(val,
char*);
728 int len = va_arg(val,
int);
729 int ifid = clickInstance->GetInterfaceId(ifname);
733 retval = simstrlcpy(buf, len, clickInstance->GetMacAddressFromInterfaceId(ifid));
741 <<
" SIMCLICK_MACADDR_FROM_NAME: " << ifname <<
" " << buf <<
" " << len);
745 case SIMCLICK_SCHEDULE: {
746 const struct timeval* when = va_arg(val,
const struct timeval*);
748 clickInstance->HandleScheduleFromClick(when);
751 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" SIMCLICK_SCHEDULE at " << when->tv_sec
752 <<
"s and " << when->tv_usec <<
"usecs.");
757 case SIMCLICK_GET_NODE_NAME: {
758 char* buf = va_arg(val,
char*);
759 int len = va_arg(val,
int);
760 retval = simstrlcpy(buf, len, clickInstance->GetNodeName());
763 <<
" SIMCLICK_GET_NODE_NAME: " << buf <<
" " << len);
767 case SIMCLICK_IF_PROMISC: {
768 int ifid = va_arg(val,
int);
769 clickInstance->SetPromisc(ifid);
777 case SIMCLICK_IF_READY: {
778 int ifid = va_arg(val,
int);
781 retval = clickInstance->IsInterfaceReady(ifid);
788 case SIMCLICK_TRACE: {
790 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" Received a call for SIMCLICK_TRACE");
794 case SIMCLICK_GET_NODE_ID: {
796 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" Received a call for SIMCLICK_GET_NODE_ID");
800 case SIMCLICK_GET_RANDOM_INT: {
804 *randomValue =
static_cast<uint32_t>(
805 clickInstance->GetRandomVariable()->GetValue(0.0,
static_cast<double>(maxValue) + 1.0));
807 NS_LOG_DEBUG(clickInstance->GetNodeName() <<
" SIMCLICK_RANDOM: " << *randomValue <<
" "
812 case SIMCLICK_GET_DEFINES: {
813 char* buf = va_arg(val,
char*);
814 size_t* size = va_arg(val,
size_t*);
823 std::map<std::string, std::string> defines = clickInstance->GetDefines();
824 std::map<std::string, std::string>::const_iterator it = defines.begin();
825 while (it != defines.end())
827 size_t available = *size - required;
828 if (it->first.length() + it->second.length() + 2 <= available)
830 simstrlcpy(buf + required, available, it->first);
831 required += it->first.length() + 1;
832 available -= it->first.length() + 1;
833 simstrlcpy(buf + required, available, it->second);
834 required += it->second.length() + 1;
838 required += it->first.length() + it->second.length() + 2;
842 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.
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
int64_t GetFemtoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
int64_t GetPicoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
int64_t GetMicroSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
TypeId SetGroupName(std::string groupName)
Set the group name.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
static void Send(Ptr< NetDevice > dev, int level, std::string emuMode)
#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.
Time Now()
create an ns3::Time instance which contains the current simulation time.
Length::Unit Unit
Save some typing by defining a short alias for Length::Unit.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void SetIpv4(const char *deviceName, const char *ip, const char *netmask)