A Discrete-Event Network Simulator
Home
Tutorials ▼
English
Documentation ▼
Installation
Manual
Models
Contributing
Wiki
Development ▼
API Docs
Issue Tracker
Merge Requests
API
Loading...
Searching...
No Matches
tap-device-creator.cc
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2009 University of Washington
3
*
4
* SPDX-License-Identifier: GPL-2.0-only
5
*/
6
7
#include "
creator-utils.h
"
8
9
#include "ns3/mac48-address.h"
10
11
#include <arpa/inet.h>
12
#include <cstring>
13
#include <errno.h>
14
#include <fcntl.h>
15
#include <iomanip>
16
#include <iostream>
17
#include <linux/if_tun.h>
18
#include <net/if.h>
19
#include <net/route.h>
20
#include <netinet/in.h>
21
#include <sstream>
22
#include <stdint.h>
23
#include <stdlib.h>
24
#include <sys/ioctl.h>
25
#include <sys/socket.h>
26
#include <sys/types.h>
27
#include <sys/un.h>
28
#include <unistd.h>
29
30
#define TAP_MAGIC 95549
31
32
using namespace
ns3
;
33
34
/**
35
* Struct holding IPv6 address data
36
*/
37
struct
in6_ifreq
38
{
39
struct
in6_addr
ifr6_addr
;
//!< IPv6 address
40
uint32_t
ifr6_prefixlen
;
//!< IPv6 prefix length
41
int32_t
ifr6_ifindex
;
//!< interface index
42
};
43
44
void
45
SetIpv4
(
const
char
* deviceName,
const
char
* ip,
const
char
* netmask)
46
{
47
struct
ifreq ifr;
48
struct
sockaddr_in* sin;
49
50
int
sock = socket(AF_INET, SOCK_DGRAM, 0);
51
52
//
53
// Set the IP address of the new interface/device.
54
//
55
memset(&ifr, 0,
sizeof
(
struct
ifreq));
56
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
57
58
sin = (
struct
sockaddr_in*)&ifr.ifr_addr;
59
inet_pton(AF_INET, ip, &sin->sin_addr);
60
ifr.ifr_addr.sa_family = AF_INET;
61
62
ABORT_IF
(ioctl(sock, SIOCSIFADDR, &ifr) == -1,
"Could not set IP address"
,
true
);
63
64
LOG
(
"Set device IP address to "
<< ip);
65
66
//
67
// Set the net mask of the new interface/device
68
//
69
memset(&ifr, 0,
sizeof
(
struct
ifreq));
70
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
71
72
sin = (
struct
sockaddr_in*)&ifr.ifr_netmask;
73
inet_pton(AF_INET, netmask, &sin->sin_addr);
74
ifr.ifr_addr.sa_family = AF_INET;
75
76
ABORT_IF
(ioctl(sock, SIOCSIFNETMASK, &ifr) == -1,
"Could not set net mask"
,
true
);
77
78
LOG
(
"Set device Net Mask to "
<< netmask);
79
close(sock);
80
}
81
82
void
83
SetIpv6
(
const
char
* deviceName,
const
char
* ip,
int
netprefix)
84
{
85
struct
ifreq ifr;
86
struct
sockaddr_in6 sin;
87
struct
in6_ifreq
ifr6;
88
89
int
sock = socket(AF_INET6, SOCK_DGRAM, 0);
90
memset(&ifr, 0,
sizeof
(
struct
ifreq));
91
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
92
93
ABORT_IF
(ioctl(sock, SIOGIFINDEX, &ifr) == -1,
"Could not get interface index"
,
true
);
94
95
LOG
(
"Set device IP v6 address to "
<< ip);
96
97
memset(&sin, 0,
sizeof
(
struct
sockaddr_in6));
98
sin.sin6_family = AF_INET6;
99
inet_pton(AF_INET6, ip, (
void
*)&sin.sin6_addr);
100
101
memset(&ifr6, 0,
sizeof
(
in6_ifreq
));
102
memcpy((
char
*)&ifr6.
ifr6_addr
, (
char
*)&sin.sin6_addr,
sizeof
(
struct
in6_addr));
103
104
ifr6.
ifr6_ifindex
= ifr.ifr_ifindex;
105
ifr6.
ifr6_prefixlen
= netprefix;
106
107
//
108
// Set the IP address of the new interface/device.
109
//
110
ABORT_IF
(ioctl(sock, SIOCSIFADDR, &ifr6) == -1,
"Could not set IP v6 address"
,
true
);
111
112
LOG
(
"Set device IP v6 address to "
<< ip);
113
close(sock);
114
}
115
116
void
117
SetMacAddress
(
int
fd,
const
char
* mac)
118
{
119
struct
ifreq ifr;
120
memset(&ifr, 0,
sizeof
(
struct
ifreq));
121
122
ifr.ifr_hwaddr.sa_family = 1;
// this is ARPHRD_ETHER from if_arp.h
123
Mac48Address
(mac).
CopyTo
((uint8_t*)ifr.ifr_hwaddr.sa_data);
124
ABORT_IF
(ioctl(fd, SIOCSIFHWADDR, &ifr) == -1,
"Could not set MAC address"
,
true
);
125
LOG
(
"Set device MAC address to "
<< mac);
126
}
127
128
void
129
SetUp
(
char
* deviceName)
130
{
131
struct
ifreq ifr;
132
133
int
sock = socket(AF_INET, SOCK_DGRAM, 0);
134
135
memset(&ifr, 0,
sizeof
(
struct
ifreq));
136
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
137
138
ABORT_IF
(ioctl(sock, SIOCGIFFLAGS, &ifr) == -1,
"Could not get flags for interface"
,
true
);
139
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
140
141
ABORT_IF
(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1,
"Could not bring interface up"
,
true
);
142
143
LOG
(
"Device is up"
);
144
close(sock);
145
}
146
147
int
148
CreateTap
(
char
* deviceName,
149
const
char
* mac,
150
bool
ifftap,
151
bool
iffpi,
152
const
char
* ip4,
153
const
char
* netmask,
154
const
char
* ip6,
155
const
int
netprefix)
156
{
157
//
158
// Creation and management of Tap devices is done via the tun device
159
//
160
int
fd = open(
"/dev/net/tun"
, O_RDWR);
161
ABORT_IF
(fd == -1,
"Could not open /dev/net/tun"
,
true
);
162
163
//
164
// Set flags for device type and PI header.
165
//
166
struct
ifreq ifr;
167
168
memset(&ifr, 0,
sizeof
(
struct
ifreq));
169
170
ifr.ifr_flags = (ifftap ? IFF_TAP : IFF_TUN);
171
if
(!iffpi)
172
{
173
ifr.ifr_flags |= IFF_NO_PI;
174
}
175
176
//
177
// If device name is not specified, the kernel chooses one.
178
//
179
if
(*deviceName)
180
{
181
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
182
}
183
184
ABORT_IF
(ioctl(fd, TUNSETIFF, (
void
*)&ifr) == -1,
"Could not allocate tap device"
,
true
);
185
186
LOG
(
"Allocated TAP device "
<< deviceName);
187
188
//
189
// Set the hardware (MAC) address of the new device
190
//
191
if
(ifftap)
192
{
193
SetMacAddress
(fd, mac);
194
}
195
196
//
197
// Set the IP address and netmask of the new interface/device.
198
//
199
if
(ip4)
200
{
201
SetIpv4
(deviceName, ip4, netmask);
202
}
203
204
if
(ip6)
205
{
206
SetIpv6
(deviceName, ip6, netprefix);
207
}
208
209
//
210
// Bring the interface up.
211
//
212
SetUp
(deviceName);
213
214
return
fd;
215
}
216
217
int
218
main(
int
argc,
char
* argv[])
219
{
220
int
c;
221
char
* dev =
nullptr
;
222
char
* ip4 =
nullptr
;
223
char
* ip6 =
nullptr
;
224
char
*
mac
=
nullptr
;
225
char
* netmask =
nullptr
;
226
char
* path =
nullptr
;
227
bool
tap =
false
;
228
bool
pi =
false
;
229
int
prefix = -1;
230
231
while
((c = getopt(argc, argv,
"vd:i:m:n:I:P:thp:"
)) != -1)
232
{
233
switch
(c)
234
{
235
case
'd'
:
236
dev = optarg;
// name of the new tap device
237
break
;
238
case
'i'
:
239
ip4 = optarg;
// ip v4 address of the new device
240
break
;
241
case
'I'
:
242
ip6 = optarg;
// ip v6 address of the new device
243
break
;
244
case
'm'
:
245
mac
= optarg;
// mac address of the new device
246
break
;
247
case
'n'
:
248
netmask = optarg;
// ip v4 net mask for the new device
249
break
;
250
case
'P'
:
251
prefix = atoi(optarg);
// ip v6 prefix for the new device
252
break
;
253
case
't'
:
254
tap =
true
;
// mode for the device (TAP or TUN)
255
break
;
256
case
'h'
:
257
pi =
true
;
// set the IFF_NO_PI flag
258
break
;
259
case
'p'
:
260
path = optarg;
// path back to the tap bridge
261
break
;
262
case
'v'
:
263
gVerbose
=
true
;
264
break
;
265
}
266
}
267
268
//
269
// We have got to be able to coordinate the name of the tap device we are
270
// going to create and or open with the device that an external Linux host
271
// will use. If this name is provided we use it. If not we let the system
272
// create the device for us. This name is given in dev
273
//
274
LOG
(
"Provided Device Name is \""
<< dev <<
"\""
);
275
276
//
277
// We have got to be able to assign an IP address to the tap device we are
278
// allocating. This address is allocated in the simulation and assigned to
279
// the tap bridge. This address is given in ip.
280
//
281
ABORT_IF
(ip4 ==
nullptr
&& ip6 ==
nullptr
,
"IP Address is a required argument"
, 0);
282
if
(ip4)
283
{
284
ABORT_IF
(netmask ==
nullptr
,
"Net mask is a required argument"
, 0);
285
LOG
(
"Provided IP v4 Address is \""
<< ip4 <<
"\""
);
286
LOG
(
"Provided IP v4 Net Mask is \""
<< netmask <<
"\""
);
287
}
288
if
(ip6)
289
{
290
ABORT_IF
(prefix == -1,
"Prefix is a required argument"
, 0);
291
LOG
(
"Provided IP v6 Address is \""
<< ip6 <<
"\""
);
292
LOG
(
"Provided IP v6 Prefix is \""
<< prefix <<
"\""
);
293
}
294
295
//
296
// We have got to be able to assign a Mac address to the tap device we are
297
// allocating. This address is allocated in the simulation and assigned to
298
// the bridged device. This allows packets addressed to the bridged device
299
// to appear in the Linux host as if they were received there.
300
//
301
ABORT_IF
(mac ==
nullptr
,
"MAC Address is a required argument"
, 0);
302
LOG
(
"Provided MAC Address is \""
<< mac <<
"\""
);
303
304
//
305
// We have got to know whether or not to create the TAP.
306
//
307
if
(tap)
308
{
309
LOG
(
"Provided device Mode is TAP"
);
310
}
311
else
312
{
313
LOG
(
"Provided device Mode is TUN"
);
314
}
315
316
//
317
// IFF_NO_PI flag.
318
//
319
if
(pi)
320
{
321
LOG
(
"IFF_NO_PI flag set. Packet Information will be present in the traffic"
);
322
}
323
324
//
325
// This program is spawned by a tap bridge running in a simulation. It
326
// wants to create a socket as described below. We are going to do the
327
// work here since we're running suid root. Once we create the socket,
328
// we have to send it back to the tap bridge. We do that over a Unix
329
// (local interprocess) socket. The tap bridge created a socket to
330
// listen for our response on, and it is expected to have encoded the address
331
// information as a string and to have passed that string as an argument to
332
// us. We see it here as the "path" string. We can't do anything useful
333
// unless we have that string.
334
//
335
ABORT_IF
(path ==
nullptr
,
"path is a required argument"
, 0);
336
LOG
(
"Provided path is \""
<< path <<
"\""
);
337
338
//
339
// The whole reason for all of the hoops we went through to call out to this
340
// program will pay off here. We created this program to run as suid root
341
// in order to keep the main simulation program from having to be run with
342
// root privileges. We need root privileges to be able to futz with the
343
// Tap device underlying all of this. So all of these hoops are to allow
344
// us to execute the following code:
345
//
346
LOG
(
"Creating Tap"
);
347
int
sock =
CreateTap
(dev, mac, tap, pi, ip4, netmask, ip6, prefix);
348
ABORT_IF
(sock == -1,
"main(): Unable to create tap socket"
, 1);
349
350
//
351
// Send the socket back to the tap net device so it can go about its business
352
//
353
SendSocket
(path, sock,
TAP_MAGIC
);
354
355
return
0;
356
}
LOG
#define LOG(x)
Log to std::cout.
Definition
bench-scheduler.cc:26
int32_t
ns3::Mac48Address
an EUI-48 address
Definition
mac48-address.h:35
ns3::Mac48Address::CopyTo
void CopyTo(uint8_t buffer[6]) const
Definition
mac48-address.cc:58
uint32_t
creator-utils.h
ABORT_IF
#define ABORT_IF(cond, msg, printErrno)
Definition
creator-utils.h:40
ns3::SendSocket
void SendSocket(const char *path, int fd, const int magic_number)
Send the file descriptor back to the code that invoked the creation.
Definition
creator-utils.cc:43
ns3
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::gVerbose
bool gVerbose
Flag to enable / disable verbose log mode.
Definition
creator-utils.cc:31
third.mac
mac
Definition
third.py:81
in6_ifreq
Struct holding IPv6 address data.
Definition
tap-device-creator.cc:38
in6_ifreq::ifr6_ifindex
int32_t ifr6_ifindex
interface index
Definition
tap-device-creator.cc:41
in6_ifreq::ifr6_prefixlen
uint32_t ifr6_prefixlen
IPv6 prefix length.
Definition
tap-device-creator.cc:40
in6_ifreq::ifr6_addr
struct in6_addr ifr6_addr
IPv6 address.
Definition
tap-device-creator.cc:39
SetIpv6
void SetIpv6(const char *deviceName, const char *ip, int netprefix)
Definition
tap-device-creator.cc:83
SetIpv4
void SetIpv4(const char *deviceName, const char *ip, const char *netmask)
Definition
tap-device-creator.cc:45
SetUp
void SetUp(char *deviceName)
Definition
tap-device-creator.cc:129
CreateTap
int CreateTap(char *deviceName, const char *mac, bool ifftap, bool iffpi, const char *ip4, const char *netmask, const char *ip6, const int netprefix)
Definition
tap-device-creator.cc:148
SetMacAddress
void SetMacAddress(int fd, const char *mac)
Definition
tap-device-creator.cc:117
TAP_MAGIC
#define TAP_MAGIC
Definition
tap-device-creator.cc:30
src
fd-net-device
helper
tap-device-creator.cc
Generated on Tue Dec 10 2024 18:20:39 for ns-3 by
1.11.0