A Discrete-Event Network Simulator
API
tap-device-creator.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2009 University of Washington
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
19#include <arpa/inet.h>
20#include <unistd.h>
21#include <stdint.h>
22#include <iostream>
23#include <iomanip>
24#include <sstream>
25#include <cstring>
26#include <stdlib.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <sys/ioctl.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33#include <net/if.h>
34#include <linux/if_tun.h>
35#include <net/route.h>
36#include <netinet/in.h>
37
38#include "creator-utils.h"
39
40#define TAP_MAGIC 95549
41
42//
43// Lots of the following helper code taken from corresponding functions in src/node.
44//
45#define ASCII_DOT (0x2e)
46#define ASCII_ZERO (0x30)
47#define ASCII_a (0x41)
48#define ASCII_z (0x5a)
49#define ASCII_A (0x61)
50#define ASCII_Z (0x7a)
51#define ASCII_COLON (0x3a)
52#define ASCII_ZERO (0x30)
53
54using namespace ns3;
55
59struct in6_ifreq {
60 struct in6_addr ifr6_addr;
63};
64
65char
67{
68 if (c >= ASCII_a && c <= ASCII_z)
69 {
70 return c;
71 }
72 else if (c >= ASCII_A && c <= ASCII_Z)
73 {
74 return c + (ASCII_a - ASCII_A);
75 }
76 else
77 {
78 return c;
79 }
80}
81
82void
83AsciiToMac48 (const char *str, uint8_t addr[6])
84{
85 int i = 0;
86 while (*str != 0 && i < 6)
87 {
88 uint8_t byte = 0;
89 while (*str != ASCII_COLON && *str != 0)
90 {
91 byte <<= 4;
92 char low = AsciiToLowCase (*str);
93 if (low >= ASCII_a)
94 {
95 byte |= low - ASCII_a + 10;
96 }
97 else
98 {
99 byte |= low - ASCII_ZERO;
100 }
101 str++;
102 }
103 addr[i] = byte;
104 i++;
105 if (*str == 0)
106 {
107 break;
108 }
109 str++;
110 }
111}
112
113void
114SetIpv4 (const char *deviceName, const char *ip, const char *netmask)
115{
116 struct ifreq ifr;
117 struct sockaddr_in *sin;
118
119 int sock = socket(AF_INET, SOCK_DGRAM, 0);
120
121 //
122 // Set the IP address of the new interface/device.
123 //
124 memset(&ifr, 0, sizeof(struct ifreq));
125 strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
126
127 sin = (struct sockaddr_in*) &ifr.ifr_addr;
128 inet_pton(AF_INET, ip, &sin->sin_addr);
129 ifr.ifr_addr.sa_family = AF_INET;
130
131 ABORT_IF (ioctl (sock, SIOCSIFADDR, &ifr) == -1,
132 "Could not set IP address", true);
133
134 LOG ("Set device IP address to " << ip);
135
136 //
137 // Set the net mask of the new interface/device
138 //
139 memset(&ifr, 0, sizeof(struct ifreq));
140 strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
141
142 sin = (struct sockaddr_in*) &ifr.ifr_netmask;
143 inet_pton(AF_INET, netmask, &sin->sin_addr);
144 ifr.ifr_addr.sa_family = AF_INET;
145
146 ABORT_IF (ioctl (sock, SIOCSIFNETMASK, &ifr) == -1,
147 "Could not set net mask", true);
148
149 LOG ("Set device Net Mask to " << netmask);
150 close(sock);
151}
152
153void
154SetIpv6 (const char* deviceName, const char *ip, int netprefix)
155{
156 struct ifreq ifr;
157 struct sockaddr_in6 sin;
158 struct in6_ifreq ifr6;
159
160 int sock = socket(AF_INET6, SOCK_DGRAM, 0);
161 memset(&ifr, 0, sizeof(struct ifreq));
162 strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
163
164 ABORT_IF (ioctl (sock, SIOGIFINDEX, &ifr) == -1,
165 "Could not get interface index", true);
166
167 LOG ("Set device IP v6 address to " << ip);
168
169 memset(&sin, 0, sizeof(struct sockaddr_in6));
170 sin.sin6_family = AF_INET6;
171 inet_pton(AF_INET6, ip, (void *) &sin.sin6_addr);
172
173 memset(&ifr6, 0, sizeof(in6_ifreq));
174 memcpy((char *) &ifr6.ifr6_addr, (char *) &sin.sin6_addr, sizeof(struct in6_addr));
175
176 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
177 ifr6.ifr6_prefixlen = netprefix;
178
179 //
180 // Set the IP address of the new interface/device.
181 //
182 ABORT_IF (ioctl (sock, SIOCSIFADDR, &ifr6) == -1,
183 "Could not set IP v6 address", true);
184
185 LOG ("Set device IP v6 address to " << ip);
186 close (sock);
187
188}
189
190void
191SetMacAddress (int fd, const char* mac)
192{
193 struct ifreq ifr;
194 memset(&ifr, 0, sizeof(struct ifreq));
195
196 ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
197 AsciiToMac48 (mac, (uint8_t*)ifr.ifr_hwaddr.sa_data);
198 ABORT_IF (ioctl (fd, SIOCSIFHWADDR, &ifr) == -1, "Could not set MAC address", true);
199 LOG ("Set device MAC address to " << mac);
200}
201
202void
203SetUp (char *deviceName)
204{
205 struct ifreq ifr;
206
207 int sock = socket(AF_INET, SOCK_DGRAM, 0);
208
209 memset(&ifr, 0, sizeof(struct ifreq));
210 strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
211
212 ABORT_IF (ioctl (sock, SIOCGIFFLAGS, &ifr) == -1,
213 "Could not get flags for interface", true);
214 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
215
216 ABORT_IF (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1,
217 "Could not bring interface up", true);
218
219 LOG ("Device is up");
220 close (sock);
221}
222
223int
224CreateTap (char *deviceName, const char *mac, const int ifftap, const int iffpi,
225 const char *ip4, const char *netmask, const char *ip6, const int netprefix)
226{
227
228 //
229 // Creation and management of Tap devices is done via the tun device
230 //
231 int fd = open ("/dev/net/tun", O_RDWR);
232 ABORT_IF (fd == -1, "Could not open /dev/net/tun", true);
233
234 //
235 // Set flags for device type and PI header.
236 //
237 struct ifreq ifr;
238
239 memset(&ifr, 0, sizeof(struct ifreq));
240
241 ifr.ifr_flags = (ifftap ? IFF_TAP : IFF_TUN);
242 if (!iffpi)
243 {
244 ifr.ifr_flags |= IFF_NO_PI;
245 }
246
247 //
248 // If device name is not specified, the kernel chooses one.
249 //
250 if (*deviceName)
251 {
252 strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1);
253 }
254
255
256 ABORT_IF (ioctl (fd, TUNSETIFF, (void *) &ifr) == -1,
257 "Could not allocate tap device", true);
258
259 LOG ("Allocated TAP device " << deviceName);
260
261 //
262 // Set the hardware (MAC) address of the new device
263 //
264 if (ifftap)
265 {
266 SetMacAddress(fd, mac);
267 }
268
269 //
270 // Set the IP address and netmask of the new interface/device.
271 //
272 if (ip4)
273 {
274 SetIpv4(deviceName, ip4, netmask);
275 }
276
277 if (ip6)
278 {
279 SetIpv6(deviceName, ip6, netprefix);
280 }
281
282 //
283 // Bring the interface up.
284 //
285 SetUp(deviceName);
286
287 return fd;
288}
289
290
291int
292main (int argc, char *argv[])
293{
294 int c;
295 char *dev = NULL;
296 char *ip4 = NULL;
297 char *ip6 = NULL;
298 char *mac = NULL;
299 char *netmask = NULL;
300 char *path = NULL;
301 int tap = false;
302 int pi = false;
303 int prefix = -1;
304
305 while ((c = getopt (argc, argv, "vd:i:m:n:I:P:thp:")) != -1)
306 {
307 switch (c)
308 {
309 case 'd':
310 dev = optarg; // name of the new tap device
311 break;
312 case 'i':
313 ip4 = optarg; // ip v4 address of the new device
314 break;
315 case 'I':
316 ip6 = optarg; // ip v6 address of the new device
317 break;
318 case 'm':
319 mac = optarg; // mac address of the new device
320 break;
321 case 'n':
322 netmask = optarg; // ip v4 net mask for the new device
323 break;
324 case 'P':
325 prefix = atoi(optarg); // ip v6 prefix for the new device
326 break;
327 case 't':
328 tap = true; // mode for the device (TAP or TUN)
329 break;
330 case 'h':
331 pi = true; // set the IFF_NO_PI flag
332 break;
333 case 'p':
334 path = optarg; // path back to the tap bridge
335 break;
336 case 'v':
337 gVerbose = true;
338 break;
339 }
340 }
341
342 //
343 // We have got to be able to coordinate the name of the tap device we are
344 // going to create and or open with the device that an external Linux host
345 // will use. If this name is provided we use it. If not we let the system
346 // create the device for us. This name is given in dev
347 //
348 LOG ("Provided Device Name is \"" << dev << "\"");
349
350 //
351 // We have got to be able to assign an IP address to the tap device we are
352 // allocating. This address is allocated in the simulation and assigned to
353 // the tap bridge. This address is given in ip.
354 //
355 ABORT_IF (ip4 == NULL && ip6 == NULL, "IP Address is a required argument", 0);
356 if (ip4)
357 {
358 ABORT_IF (netmask == NULL, "Net mask is a required argument", 0);
359 LOG ("Provided IP v4 Address is \"" << ip4 << "\"");
360 LOG ("Provided IP v4 Net Mask is \"" << netmask << "\"");
361 }
362 if (ip6)
363 {
364 ABORT_IF (prefix == -1, "Prefix is a required argument", 0);
365 LOG ("Provided IP v6 Address is \"" << ip6 << "\"");
366 LOG ("Provided IP v6 Prefix is \"" << prefix << "\"");
367 }
368
369 //
370 // We have got to be able to assign a Mac address to the tap device we are
371 // allocating. This address is allocated in the simulation and assigned to
372 // the bridged device. This allows packets addressed to the bridged device
373 // to appear in the Linux host as if they were received there.
374 //
375 ABORT_IF (mac == NULL, "MAC Address is a required argument", 0);
376 LOG ("Provided MAC Address is \"" << mac << "\"");
377
378 //
379 // We have got to know whether or not to create the TAP.
380 //
381 if (tap)
382 {
383 LOG ("Provided device Mode is TAP");
384 }
385 else
386 {
387 LOG ("Provided device Mode is TUN");
388 }
389
390 //
391 // IFF_NO_PI flag.
392 //
393 if (pi)
394 {
395 LOG ("IFF_NO_PI flag set. Packet Information will be present in the traffic");
396 }
397
398 //
399 // This program is spawned by a tap bridge running in a simulation. It
400 // wants to create a socket as described below. We are going to do the
401 // work here since we're running suid root. Once we create the socket,
402 // we have to send it back to the tap bridge. We do that over a Unix
403 // (local interprocess) socket. The tap bridge created a socket to
404 // listen for our response on, and it is expected to have encoded the address
405 // information as a string and to have passed that string as an argument to
406 // us. We see it here as the "path" string. We can't do anything useful
407 // unless we have that string.
408 //
409 ABORT_IF (path == NULL, "path is a required argument", 0);
410 LOG ("Provided path is \"" << path << "\"");
411
412 //
413 // The whole reason for all of the hoops we went through to call out to this
414 // program will pay off here. We created this program to run as suid root
415 // in order to keep the main simulation program from having to be run with
416 // root privileges. We need root privileges to be able to futz with the
417 // Tap device underlying all of this. So all of these hoops are to allow
418 // us to execute the following code:
419 //
420 LOG ("Creating Tap");
421 int sock = CreateTap (dev, mac, tap, pi, ip4, netmask, ip6, prefix);
422 ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
423
424 //
425 // Send the socket back to the tap net device so it can go about its business
426 //
427 SendSocket (path, sock, TAP_MAGIC);
428
429 return 0;
430}
#define LOG(x)
#define ABORT_IF(cond, msg, printErrno)
Definition: creator-utils.h:51
Every class exported by the ns3 library is enclosed in the ns3 namespace.
mac
Definition: third.py:96
Struct holding IPv6 address data.
int32_t ifr6_ifindex
interface index
uint32_t ifr6_prefixlen
IPv6 prefix length.
struct in6_addr ifr6_addr
IPv6 address.
static void SendSocket(const char *path, int fd)
Definition: tap-creator.cc:155
static int gVerbose
Definition: tap-creator.cc:42
void SetIpv6(const char *deviceName, const char *ip, int netprefix)
#define ASCII_Z
void SetIpv4(const char *deviceName, const char *ip, const char *netmask)
#define ASCII_A
#define ASCII_z
void AsciiToMac48(const char *str, uint8_t addr[6])
#define ASCII_COLON
void SetUp(char *deviceName)
char AsciiToLowCase(char c)
#define ASCII_ZERO
#define ASCII_a
void SetMacAddress(int fd, const char *mac)
int CreateTap(char *deviceName, const char *mac, const int ifftap, const int iffpi, const char *ip4, const char *netmask, const char *ip6, const int netprefix)
#define TAP_MAGIC