A Discrete-Event Network Simulator
Home
Tutorials ▼
English
Portuguese
Docs ▼
Wiki
Manual
Models
Develop ▼
API
Bugs
API
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Properties
Friends
Macros
Groups
Pages
planetlab-fd-net-device-helper.cc
Go to the documentation of this file.
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/*
3
* Copyright (c) 2012 INRIA
4
*
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation;
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
*
18
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
* Claudio Freire <klaussfreire@sourceforge.net>
20
*
21
*/
22
23
#include "
planetlab-fd-net-device-helper.h
"
24
#include "
encode-decode.h
"
25
26
#include "ns3/abort.h"
27
#include "ns3/config.h"
28
#include "ns3/fd-net-device.h"
29
#include "ns3/log.h"
30
#include "ns3/names.h"
31
#include "ns3/object-factory.h"
32
#include "ns3/packet.h"
33
#include "ns3/simulator.h"
34
#include "ns3/trace-helper.h"
35
#include "ns3/internet-module.h"
36
37
#include <arpa/inet.h>
38
#include <errno.h>
39
#include <iostream>
40
#include <iomanip>
41
#include <limits>
42
#include <linux/if_tun.h>
43
#include <memory>
44
#include <net/ethernet.h>
45
#include <net/if.h>
46
#include <netinet/in.h>
47
#include <netpacket/packet.h>
48
49
#include <stdlib.h>
50
#include <
string.h
>
51
#include <sys/wait.h>
52
#include <sys/stat.h>
53
#include <sys/socket.h>
54
#include <sys/un.h>
55
#include <sys/ioctl.h>
56
#include <time.h>
57
#include <unistd.h>
58
59
#include <string>
60
61
NS_LOG_COMPONENT_DEFINE
(
"PlanetLabFdNetDeviceHelper"
);
62
63
namespace
ns3 {
64
65
#define PLANETLAB_MAGIC 75867
66
67
PlanetLabFdNetDeviceHelper::PlanetLabFdNetDeviceHelper
()
68
{
69
m_tapIp
=
Ipv4Address
(
"255.255.255.255"
);
70
m_tapMask
=
Ipv4Mask
(
"255.255.255.255"
);
71
}
72
73
void
74
PlanetLabFdNetDeviceHelper::SetTapIpAddress
(
Ipv4Address
address)
75
{
76
m_tapIp
= address;
77
}
78
79
void
80
PlanetLabFdNetDeviceHelper::SetTapMask
(
Ipv4Mask
mask)
81
{
82
m_tapMask
= mask;
83
}
84
85
Ptr<NetDevice>
86
PlanetLabFdNetDeviceHelper::InstallPriv
(
Ptr<Node>
node)
const
87
{
88
Ptr<NetDevice>
d =
FdNetDeviceHelper::InstallPriv
(node);
89
Ptr<FdNetDevice>
device = d->
GetObject
<
FdNetDevice
> ();
90
91
//
92
// The PlanetLab mechanism to create a TAP device doesn't allow
93
// for the moment to set the IFF_NOPI flag. In consequence, a PI
94
// header will be present in the traffic.
95
// We need to explicitly set the encapsulation mode to DIXPI,
96
// so the FdNetDevice is able to treat correctly the traffic
97
// traversing TAP device.
98
//
99
Ptr<FdNetDevice>
fdnd = device->GetObject<
FdNetDevice
> ();
100
fdnd->
SetEncapsulationMode
(
FdNetDevice::DIXPI
);
101
102
SetFileDescriptor
(device);
103
return
device;
104
}
105
106
void
107
PlanetLabFdNetDeviceHelper::SetFileDescriptor
(
Ptr<FdNetDevice>
device)
const
108
{
109
NS_LOG_LOGIC
(
"Creating TAP device"
);
110
111
//
112
// Call out to a separate process running as suid root in order to create a
113
// TAP device. We do this to avoid having the entire simulation running as root.
114
//
115
int
fd =
CreateFileDescriptor
();
116
device->SetFileDescriptor (fd);
117
}
118
119
int
120
PlanetLabFdNetDeviceHelper::CreateFileDescriptor
(
void
)
const
121
{
122
NS_LOG_FUNCTION
(
this
);
123
124
//
125
// We're going to fork and exec that program soon, but first we need to have
126
// a socket to talk to it with. So we create a local interprocess (Unix)
127
// socket for that purpose.
128
//
129
int
sock = socket (PF_UNIX, SOCK_DGRAM, 0);
130
NS_ABORT_MSG_IF
(sock == -1,
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Unix socket creation error, errno = "
<< strerror (errno));
131
132
//
133
// Bind to that socket and let the kernel allocate an endpoint
134
//
135
struct
sockaddr_un un;
136
memset (&un, 0,
sizeof
(un));
137
un.sun_family = AF_UNIX;
138
int
status = bind (sock, (
struct
sockaddr*)&un,
sizeof
(sa_family_t));
139
NS_ABORT_MSG_IF
(status == -1,
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Could not bind(): errno = "
<< strerror (errno));
140
NS_LOG_INFO
(
"Created Unix socket"
);
141
NS_LOG_INFO
(
"sun_family = "
<< un.sun_family);
142
NS_LOG_INFO
(
"sun_path = "
<< un.sun_path);
143
144
//
145
// We have a socket here, but we want to get it there -- to the program we're
146
// going to exec. What we'll do is to do a getsockname and then encode the
147
// resulting address information as a string, and then send the string to the
148
// program as an argument. So we need to get the sock name.
149
//
150
socklen_t len =
sizeof
(un);
151
status = getsockname (sock, (
struct
sockaddr*)&un, &len);
152
NS_ABORT_MSG_IF
(status == -1,
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Could not getsockname(): errno = "
<< strerror (errno));
153
154
//
155
// Now encode that socket name (family and path) as a string of hex digits
156
//
157
std::string path =
BufferToString
((uint8_t *)&un, len);
158
NS_LOG_INFO
(
"Encoded Unix socket as \""
<< path <<
"\""
);
159
160
//
161
// Fork and exec the process to create our socket. If we're us (the parent)
162
// we wait for the child (the creator) to complete and read the socket it
163
// created and passed back using the ancillary data mechanism.
164
//
165
pid_t pid = ::fork ();
166
if
(pid == 0)
167
{
168
NS_LOG_DEBUG
(
"Child process"
);
169
170
//
171
// build a command line argument from the encoded endpoint string that
172
// the socket creation process will use to figure out how to respond to
173
// the (now) parent process. We're going to have to give this program
174
// quite a bit of information.
175
//
176
// -i<IP-address> The IP address to assign to the new tap device;
177
// -n<network-prefix> The network prefix to assign to the new tap device;
178
// -t Set teh IFF_TAP flag
179
// -p<path> the path to the unix socket described above.
180
//
181
// Example tap-creator -i1.2.3.1 -n24 -t -pblah
182
//
183
184
std::ostringstream ossIp;
185
ossIp <<
"-i"
<<
m_tapIp
;
186
187
std::ostringstream ossPrefix;
188
ossPrefix <<
"-n"
<<
m_tapMask
.
GetPrefixLength
();
189
190
std::ostringstream ossMode;
191
ossMode <<
"-t"
;
192
193
std::ostringstream ossPath;
194
ossPath <<
"-p"
<< path;
195
196
//
197
// Execute the socket creation process image.
198
//
199
status = ::execlp (PLANETLAB_TAP_CREATOR,
200
PLANETLAB_TAP_CREATOR,
// argv[0] (filename)
201
ossIp.str ().c_str (),
// argv[1] (-i<IP address>)
202
ossPrefix.str ().c_str (),
// argv[2] (-n<prefix>)
203
ossMode.str ().c_str (),
// argv[3] (-t <tap>)
204
ossPath.str ().c_str (),
// argv[4] (-p<path>)
205
(
char
*)NULL);
206
207
//
208
// If the execlp successfully completes, it never returns. If it returns it failed or the OS is
209
// broken. In either case, we bail.
210
//
211
NS_FATAL_ERROR
(
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Back from execlp(), errno = "
<< ::strerror (errno));
212
}
213
else
214
{
215
NS_LOG_DEBUG
(
"Parent process"
);
216
//
217
// We're the process running the emu net device. We need to wait for the
218
// socket creator process to finish its job.
219
//
220
int
st;
221
pid_t waited = waitpid (pid, &st, 0);
222
NS_ABORT_MSG_IF
(waited == -1,
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): waitpid() fails, errno = "
<< strerror (errno));
223
NS_ASSERT_MSG
(pid == waited,
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): pid mismatch"
);
224
225
//
226
// Check to see if the socket creator exited normally and then take a
227
// look at the exit code. If it bailed, so should we. If it didn't
228
// even exit normally, we bail too.
229
//
230
if
(WIFEXITED (st))
231
{
232
int
exitStatus = WEXITSTATUS (st);
233
NS_ABORT_MSG_IF
(exitStatus != 0,
234
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited normally with status "
<< exitStatus);
235
}
236
else
237
{
238
NS_FATAL_ERROR
(
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited abnormally"
);
239
}
240
241
//
242
// At this point, the socket creator has run successfully and should
243
// have created our tap device, initialized it with the information we
244
// passed and sent it back to the socket address we provided. A socket
245
// (fd) we can use to talk to this tap device should be waiting on the
246
// Unix socket we set up to receive information back from the creator
247
// program. We've got to do a bunch of grunt work to get at it, though.
248
//
249
// The struct iovec below is part of a scatter-gather list. It describes a
250
// buffer. In this case, it describes a buffer (an integer) that will
251
// get the data that comes back from the socket creator process. It will
252
// be a magic number that we use as a consistency/sanity check.
253
//
254
struct
iovec iov;
255
uint32_t magic;
256
iov.iov_base = &magic;
257
iov.iov_len =
sizeof
(magic);
258
259
//
260
// The CMSG macros you'll see below are used to create and access control
261
// messages (which is another name for ancillary data). The ancillary
262
// data is made up of pairs of struct cmsghdr structures and associated
263
// data arrays.
264
//
265
// First, we're going to allocate a buffer on the stack to receive our
266
// data array (that contains the socket). Sometimes you'll see this called
267
// an "ancillary element" but the msghdr uses the control message termimology
268
// so we call it "control."
269
//
270
size_t
msg_size =
sizeof
(int);
271
char
control[CMSG_SPACE (msg_size)];
272
273
//
274
// There is a msghdr that is used to minimize the number of parameters
275
// passed to recvmsg (which we will use to receive our ancillary data).
276
// This structure uses terminology corresponding to control messages, so
277
// you'll see msg_control, which is the pointer to the ancillary data and
278
// controllen which is the size of the ancillary data array.
279
//
280
// So, initialize the message header that describes the ancillary/control
281
// data we expect to receive and point it to buffer.
282
//
283
struct
msghdr msg;
284
msg.msg_name = 0;
285
msg.msg_namelen = 0;
286
msg.msg_iov = &iov;
287
msg.msg_iovlen = 1;
288
msg.msg_control = control;
289
msg.msg_controllen =
sizeof
(control);
290
msg.msg_flags = 0;
291
292
//
293
// Now we can actually receive the interesting bits from the tap
294
// creator process. Lots of pain to get four bytes.
295
//
296
ssize_t bytesRead = recvmsg (sock, &msg, 0);
297
NS_ABORT_MSG_IF
(bytesRead !=
sizeof
(
int
),
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Wrong byte count from socket creator"
);
298
299
//
300
// There may be a number of message headers/ancillary data arrays coming in.
301
// Let's look for the one with a type SCM_RIGHTS which indicates it's the
302
// one we're interested in.
303
//
304
struct
cmsghdr *cmsg;
305
for
(cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg))
306
{
307
if
(cmsg->cmsg_level == SOL_SOCKET
308
&& cmsg->cmsg_type == SCM_RIGHTS)
309
{
310
//
311
// This is the type of message we want. Check to see if the magic
312
// number is correct and then pull out the socket we care about if
313
// it matches
314
//
315
if
(magic ==
PLANETLAB_MAGIC
)
316
{
317
NS_LOG_INFO
(
"Got SCM_RIGHTS with correct magic "
<< magic);
318
int
*rawSocket = (
int
*)CMSG_DATA (cmsg);
319
NS_LOG_INFO
(
"Got the socket from the socket creator = "
<< *rawSocket);
320
return
*rawSocket;
321
}
322
else
323
{
324
NS_LOG_INFO
(
"Got SCM_RIGHTS, but with bad magic "
<< magic);
325
}
326
}
327
}
328
NS_FATAL_ERROR
(
"Did not get the raw socket from the socket creator"
);
329
}
330
331
}
332
333
}
// namespace ns3
334
335
src
fd-net-device
helper
planetlab-fd-net-device-helper.cc
Generated on Tue May 14 2013 11:08:20 for ns-3 by
1.8.1.2