|
fw@4685
|
1 |
#include <dlfcn.h>
|
|
fw@4685
|
2 |
|
|
fw@4685
|
3 |
#include "ns3/boolean.h"
|
|
fw@4685
|
4 |
#include "ns3/log.h"
|
|
fw@4685
|
5 |
#include "ns3/ipv4-l3-protocol.h"
|
|
fw@4685
|
6 |
|
|
fw@4685
|
7 |
#include "ns3/ipv4-interface.h"
|
|
fw@4685
|
8 |
#include "ns3/object.h"
|
|
fw@4685
|
9 |
#include "ns3/packet.h"
|
|
fw@4685
|
10 |
#include "ns3/ptr.h"
|
|
fw@4685
|
11 |
#include "ns3/nstime.h"
|
|
fw@4685
|
12 |
|
|
fw@4685
|
13 |
#include "nsc-glue.h"
|
|
fw@4685
|
14 |
#include "node.h"
|
|
fw@4685
|
15 |
|
|
fw@4685
|
16 |
#include <netinet/ip.h>
|
|
fw@4685
|
17 |
#include <arpa/inet.h>
|
|
fw@4685
|
18 |
|
|
fw@4685
|
19 |
namespace ns3 {
|
|
fw@4685
|
20 |
|
|
fw@4685
|
21 |
NS_OBJECT_ENSURE_REGISTERED (NscGlue);
|
|
fw@4685
|
22 |
|
|
fw@4685
|
23 |
TypeId
|
|
fw@4685
|
24 |
NscGlue::GetTypeId (void)
|
|
fw@4685
|
25 |
{
|
|
fw@4685
|
26 |
static TypeId tid = TypeId ("ns3::NscGlue")
|
|
fw@4685
|
27 |
.SetParent <Object> ()
|
|
fw@4685
|
28 |
;
|
|
fw@4685
|
29 |
return tid;
|
|
fw@4685
|
30 |
}
|
|
fw@4685
|
31 |
|
|
fw@4685
|
32 |
NscGlue::NscGlue(void)
|
|
fw@4685
|
33 |
: m_wakeupCallbacks(0),
|
|
fw@4685
|
34 |
m_dlopenHandle(0)
|
|
fw@4685
|
35 |
{
|
|
fw@4685
|
36 |
}
|
|
fw@4685
|
37 |
|
|
fw@4685
|
38 |
void
|
|
fw@4685
|
39 |
NscGlue::SetNode(Ptr<Node> n)
|
|
fw@4685
|
40 |
{
|
|
fw@4685
|
41 |
m_node = n;
|
|
fw@4685
|
42 |
}
|
|
fw@4685
|
43 |
|
|
fw@4685
|
44 |
void
|
|
fw@4685
|
45 |
NscGlue::PassPacketToNsc (Ptr<const Packet> packet, int idx)
|
|
fw@4685
|
46 |
{
|
|
fw@4685
|
47 |
uint32_t packetSize = packet->GetSize();
|
|
fw@4685
|
48 |
const uint8_t *data = const_cast<uint8_t *>(packet->PeekData());
|
|
fw@4685
|
49 |
|
|
fw@4685
|
50 |
// deliver complete packet to the NSC network stack
|
|
fw@4685
|
51 |
m_nscStack->if_receive_packet(idx, data, packetSize);
|
|
fw@4685
|
52 |
wakeup ();
|
|
fw@4685
|
53 |
}
|
|
fw@4685
|
54 |
|
|
fw@4685
|
55 |
bool
|
|
fw@4685
|
56 |
NscGlue::IsNscProtocol (uint16_t proto)
|
|
fw@4685
|
57 |
{
|
|
fw@4685
|
58 |
return proto == 0x0800; // NSC can only handle ipv4 at the moment.
|
|
fw@4685
|
59 |
}
|
|
fw@4685
|
60 |
|
|
fw@4685
|
61 |
static int external_rand(void)
|
|
fw@4685
|
62 |
{
|
|
fw@4685
|
63 |
return 1; // XXX: check which NSC stacks actually use this
|
|
fw@4685
|
64 |
}
|
|
fw@4685
|
65 |
|
|
fw@4685
|
66 |
void
|
|
fw@4685
|
67 |
NscGlue::SetNscLibrary(const std::string &soname)
|
|
fw@4685
|
68 |
{
|
|
fw@4685
|
69 |
NS_ASSERT(!m_dlopenHandle);
|
|
fw@4685
|
70 |
m_dlopenHandle = dlopen(soname.c_str (), RTLD_NOW);
|
|
fw@4685
|
71 |
if (m_dlopenHandle == NULL)
|
|
fw@4685
|
72 |
NS_FATAL_ERROR (dlerror());
|
|
fw@4685
|
73 |
|
|
fw@4685
|
74 |
FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack");
|
|
fw@4685
|
75 |
|
|
fw@4685
|
76 |
m_nscStack = create(this, this, external_rand);
|
|
fw@4685
|
77 |
int hzval = m_nscStack->get_hz();
|
|
fw@4685
|
78 |
|
|
fw@4685
|
79 |
NS_ASSERT(hzval > 0);
|
|
fw@4685
|
80 |
|
|
fw@4685
|
81 |
m_softTimer.SetFunction (&NscGlue::SoftRtcInterrupt, this);
|
|
fw@4685
|
82 |
m_softTimer.SetDelay (MilliSeconds (1000/hzval));
|
|
fw@4685
|
83 |
// This enables stack and NSC debug messages
|
|
fw@4685
|
84 |
m_nscStack->set_diagnostic(10);
|
|
fw@4685
|
85 |
m_nscStack->init(hzval);
|
|
fw@4685
|
86 |
|
|
fw@4685
|
87 |
Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
|
|
fw@4685
|
88 |
nscStack->SetStack (m_nscStack);
|
|
fw@4685
|
89 |
m_node->AggregateObject (nscStack);
|
|
fw@4685
|
90 |
|
|
fw@4685
|
91 |
m_softTimer.Schedule ();
|
|
fw@4685
|
92 |
// its likely no ns-3 interface exits at this point, so
|
|
fw@4685
|
93 |
// we delay adding the nsc interface until the start of the simulation.
|
|
fw@4685
|
94 |
Simulator::ScheduleNow(&NscGlue::AddIface, this);
|
|
fw@4685
|
95 |
|
|
fw@4685
|
96 |
m_nscLibrary = soname;
|
|
fw@4685
|
97 |
}
|
|
fw@4685
|
98 |
|
|
fw@4685
|
99 |
std::string
|
|
fw@4685
|
100 |
NscGlue::GetNscLibrary () const
|
|
fw@4685
|
101 |
{
|
|
fw@4685
|
102 |
return m_nscLibrary;
|
|
fw@4685
|
103 |
}
|
|
fw@4685
|
104 |
|
|
fw@4685
|
105 |
|
|
fw@4685
|
106 |
void NscGlue::wakeup()
|
|
fw@4685
|
107 |
{
|
|
fw@4685
|
108 |
// TODO
|
|
fw@4685
|
109 |
// this should schedule a timer to read from all tcp sockets now... this is
|
|
fw@4685
|
110 |
// an indication that data might be waiting on the socket
|
|
fw@4685
|
111 |
for (std::list<Callback<void> >::iterator i = m_wakeupCallbacks.begin ();
|
|
fw@4685
|
112 |
i != m_wakeupCallbacks.end (); i++)
|
|
fw@4685
|
113 |
{
|
|
fw@4685
|
114 |
Callback<void> cb = *i;
|
|
fw@4685
|
115 |
cb ();
|
|
fw@4685
|
116 |
}
|
|
fw@4685
|
117 |
}
|
|
fw@4685
|
118 |
|
|
fw@4685
|
119 |
void NscGlue::SoftRtcInterrupt (void)
|
|
fw@4685
|
120 |
{
|
|
fw@4685
|
121 |
m_nscStack->timer_interrupt ();
|
|
fw@4685
|
122 |
m_nscStack->increment_ticks ();
|
|
fw@4685
|
123 |
m_softTimer.Schedule ();
|
|
fw@4685
|
124 |
}
|
|
fw@4685
|
125 |
|
|
fw@4685
|
126 |
void NscGlue::gettime(unsigned int* sec, unsigned int* usec)
|
|
fw@4685
|
127 |
{
|
|
fw@4685
|
128 |
// Only used by the Linux network stack, e.g. during ISN generation
|
|
fw@4685
|
129 |
// and in the kernel rng initialization routine. Also used in Linux
|
|
fw@4685
|
130 |
// printk output.
|
|
fw@4685
|
131 |
Time t = Simulator::Now ();
|
|
fw@4685
|
132 |
int64_t us = t.GetMicroSeconds ();
|
|
fw@4685
|
133 |
*sec = us / (1000*1000);
|
|
fw@4685
|
134 |
*usec = us - *sec * (1000*1000);
|
|
fw@4685
|
135 |
}
|
|
fw@4685
|
136 |
|
|
fw@4685
|
137 |
#ifdef NSC_NEXT
|
|
fw@4685
|
138 |
void NscGlue::send_callback(int idx, const void* data, unsigned int datalen)
|
|
fw@4685
|
139 |
#else
|
|
fw@4685
|
140 |
void NscGlue::send_callback(/* int idx,*/ const void* data, unsigned int datalen)
|
|
fw@4685
|
141 |
#endif
|
|
fw@4685
|
142 |
{
|
|
fw@4685
|
143 |
#ifndef NSC_NEXT
|
|
fw@4685
|
144 |
int idx = 0;
|
|
fw@4685
|
145 |
#endif
|
|
fw@4685
|
146 |
Ptr<Packet> p;
|
|
fw@4685
|
147 |
uint32_t ipv4Daddr;
|
|
fw@4685
|
148 |
|
|
fw@4685
|
149 |
NS_ASSERT(datalen > 20);
|
|
fw@4685
|
150 |
|
|
fw@4685
|
151 |
// FIXME: XXX: This won't really work when NSC is able to use
|
|
fw@4685
|
152 |
// L3 protocols other than AF_INET. We really really really
|
|
fw@4685
|
153 |
// should be able to do all routing decisions inside nsc and just
|
|
fw@4685
|
154 |
// pass packets to whatever network interface without looking at its contents.
|
|
fw@4685
|
155 |
const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
|
|
fw@4685
|
156 |
|
|
fw@4685
|
157 |
p = Create<Packet> (rawdata, datalen);
|
|
fw@4685
|
158 |
|
|
fw@4685
|
159 |
// we need the destination ipv4 address for Send ().
|
|
fw@4685
|
160 |
const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
|
|
fw@4685
|
161 |
|
|
fw@4685
|
162 |
ipv4Daddr = *(ipheader+4);
|
|
fw@4685
|
163 |
|
|
fw@4685
|
164 |
Ipv4Address daddr(ntohl(ipv4Daddr));
|
|
fw@4685
|
165 |
|
|
fw@4685
|
166 |
Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
|
|
fw@4685
|
167 |
NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
|
|
fw@4685
|
168 |
// FIXME: do _all_ routing via NSC and provide a ns3-nsc mapping that
|
|
fw@4685
|
169 |
// tells us which ns-3 interface the nsc interface "idx" is corresponding to.
|
|
fw@4685
|
170 |
//NS_LOG_LOGIC ("ns3: xmit via device number " << idx);
|
|
fw@4685
|
171 |
Ptr<Ipv4Interface> outInterface = ipv4->GetInterface ( idx + 1);
|
|
fw@4685
|
172 |
|
|
fw@4685
|
173 |
NS_ASSERT (outInterface);
|
|
fw@4685
|
174 |
outInterface->Send (p, daddr);
|
|
fw@4685
|
175 |
m_nscStack->if_send_finish(0);
|
|
fw@4685
|
176 |
}
|
|
fw@4685
|
177 |
|
|
fw@4685
|
178 |
|
|
fw@4685
|
179 |
void NscGlue::RegisterWakeupCallback(Callback<void> cb)
|
|
fw@4685
|
180 |
{
|
|
fw@4685
|
181 |
m_wakeupCallbacks.push_back (cb);
|
|
fw@4685
|
182 |
}
|
|
fw@4685
|
183 |
|
|
fw@4685
|
184 |
void NscGlue::AddIface(void)
|
|
fw@4685
|
185 |
{
|
|
fw@4685
|
186 |
Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
|
|
fw@4685
|
187 |
|
|
fw@4685
|
188 |
const uint32_t nInterfaces = ip->GetNInterfaces ();
|
|
fw@4685
|
189 |
// start from 1, ignore the loopback interface (HACK)
|
|
fw@4685
|
190 |
|
|
fw@4685
|
191 |
for (uint32_t i = 1; i < nInterfaces; i++)
|
|
fw@4685
|
192 |
{
|
|
fw@4685
|
193 |
Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
|
|
fw@4685
|
194 |
Ipv4Address addr = ifAddr.GetLocal ();
|
|
fw@4685
|
195 |
Ipv4Mask mask = ifAddr.GetMask ();
|
|
fw@4685
|
196 |
|
|
fw@4685
|
197 |
uint16_t mtu = ip->GetMtu (i);
|
|
fw@4685
|
198 |
|
|
fw@4685
|
199 |
std::ostringstream addrOss, maskOss;
|
|
fw@4685
|
200 |
|
|
fw@4685
|
201 |
addr.Print(addrOss);
|
|
fw@4685
|
202 |
mask.Print(maskOss);
|
|
fw@4685
|
203 |
|
|
fw@4685
|
204 |
// NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu);
|
|
fw@4685
|
205 |
|
|
fw@4685
|
206 |
std::string addrStr = addrOss.str();
|
|
fw@4685
|
207 |
std::string maskStr = maskOss.str();
|
|
fw@4685
|
208 |
const char* addrCStr = addrStr.c_str();
|
|
fw@4685
|
209 |
const char* maskCStr = maskStr.c_str();
|
|
fw@4685
|
210 |
NS_ASSERT_MSG (m_nscStack, "m_nscStackError");
|
|
fw@4685
|
211 |
m_nscStack->if_attach(addrCStr, maskCStr, mtu);
|
|
fw@4685
|
212 |
|
|
fw@4685
|
213 |
if (i == 1)
|
|
fw@4685
|
214 |
{
|
|
fw@4685
|
215 |
// We need to come up with a default gateway here. Can't guarantee this to be
|
|
fw@4685
|
216 |
// correct really...
|
|
fw@4685
|
217 |
|
|
fw@4685
|
218 |
uint8_t addrBytes[4];
|
|
fw@4685
|
219 |
addr.Serialize(addrBytes);
|
|
fw@4685
|
220 |
|
|
fw@4685
|
221 |
// XXX: this is all a bit of a horrible hack
|
|
fw@4685
|
222 |
//
|
|
fw@4685
|
223 |
// Just increment the last octet, this gives a decent chance of this being
|
|
fw@4685
|
224 |
// 'enough'.
|
|
fw@4685
|
225 |
//
|
|
fw@4685
|
226 |
// All we need is another address on the same network as the interface. This
|
|
fw@4685
|
227 |
// will force the stack to output the packet out of the network interface.
|
|
fw@4685
|
228 |
addrBytes[3]++;
|
|
fw@4685
|
229 |
addr.Deserialize(addrBytes);
|
|
fw@4685
|
230 |
addrOss.str("");
|
|
fw@4685
|
231 |
addr.Print(addrOss);
|
|
fw@4685
|
232 |
m_nscStack->add_default_gateway(addrOss.str().c_str());
|
|
fw@4685
|
233 |
}
|
|
fw@4685
|
234 |
}
|
|
fw@4685
|
235 |
}
|
|
fw@4685
|
236 |
} // namespace ns3
|