ns-3: src/fd-net-device/helper/tap-fd-net-device-helper.cc Source File 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 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages tap-fd-net-device-helper.cc 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 /* 3 * Copyright (c) 2012 INRIA, 2012 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 "tap-fd-net-device-helper.h" 20 #include "encode-decode.h" 21 22 #include "ns3/abort.h" 23 #include "ns3/config.h" 24 #include "ns3/fd-net-device.h" 25 #include "ns3/log.h" 26 #include "ns3/names.h" 27 #include "ns3/object-factory.h" 28 #include "ns3/packet.h" 29 #include "ns3/simulator.h" 30 #include "ns3/trace-helper.h" 31 #include "ns3/internet-module.h" 32 33 #include
34 #include 35 #include 36 #include 37 #include 38 #include 39 #include 40 #include 41 #include 42 #include 43 #include 44 45 #include 46 #include 47 #include 48 #include 49 #include 50 #include 51 #include 52 #include 53 #include 54 55 #include 56 57 NS_LOG_COMPONENT_DEFINE ("TapFdNetDeviceHelper"); 58 59 namespace ns3 { 60 61 #define TAP_MAGIC 95549 62 63 TapFdNetDeviceHelper::TapFdNetDeviceHelper () 64 { 65 m_deviceName = ""; 66 m_modePi = false; 67 m_tapIp4 = ""; 68 m_tapMask4 = ""; 69 m_tapIp6 = ""; 70 m_tapPrefix6 = 64; 71 m_tapMac = Mac48Address::Allocate (); 72 } 73 74 void 75 TapFdNetDeviceHelper::SetModePi (bool modePi) 76 { 77 m_modePi = modePi; 78 } 79 80 void 81 TapFdNetDeviceHelper::SetTapIpv4Address (Ipv4Address address) 82 { 83 m_tapIp4 = address; 84 } 85 86 void 87 TapFdNetDeviceHelper::SetTapIpv4Mask (Ipv4Mask mask) 88 { 89 m_tapMask4 = mask; 90 } 91 92 void 93 TapFdNetDeviceHelper::SetTapIpv6Address (Ipv6Address address) 94 { 95 m_tapIp6 = address; 96 } 97 98 void 99 TapFdNetDeviceHelper::SetTapIpv6Prefix (int prefix) 100 { 101 m_tapPrefix6 = prefix; 102 } 103 104 void 105 TapFdNetDeviceHelper::SetTapMacAddress (Mac48Address mac) 106 { 107 m_tapMac = mac; 108 } 109 110 Ptr 111 TapFdNetDeviceHelper::InstallPriv (Ptr node) const 112 { 113 Ptr d = FdNetDeviceHelper::InstallPriv (node); 114 Ptr device = d->GetObject (); 115 Ptr fdnd = device->GetObject (); 116 117 // 118 // We need to explicitly set the encapsulation mode for the traffic 119 // traversing the TAP device, so the FdNetDevice is able to know 120 // how to treat the traffic in a way that in compatible with the 121 // TAP device. 122 // 123 if (m_modePi) 124 { 125 fdnd->SetEncapsulationMode (FdNetDevice::DIXPI); 126 } 127 128 SetFileDescriptor (device); 129 return device; 130 } 131 132 void 133 TapFdNetDeviceHelper::SetFileDescriptor (Ptr device) const 134 { 135 NS_LOG_LOGIC ("Creating TAP device"); 136 137 // 138 // Call out to a separate process running as suid root in order to create a 139 // TAP device. We do this to avoid having the entire simulation running as root. 140 // 141 int fd = CreateFileDescriptor (); 142 device->SetFileDescriptor (fd); 143 } 144 145 int 146 TapFdNetDeviceHelper::CreateFileDescriptor (void) const 147 { 148 NS_LOG_FUNCTION (this); 149 150 // 151 // We're going to fork and exec that program soon, but first we need to have 152 // a socket to talk to it with. So we create a local interprocess (Unix) 153 // socket for that purpose. 154 // 155 int sock = socket (PF_UNIX, SOCK_DGRAM, 0); 156 NS_ABORT_MSG_IF (sock == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): Unix socket creation error, errno = " << strerror (errno)); 157 158 // 159 // Bind to that socket and let the kernel allocate an endpoint 160 // 161 struct sockaddr_un un; 162 memset (&un, 0, sizeof (un)); 163 un.sun_family = AF_UNIX; 164 int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t)); 165 NS_ABORT_MSG_IF (status == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): Could not bind(): errno = " << strerror (errno)); 166 NS_LOG_INFO ("Created Unix socket"); 167 NS_LOG_INFO ("sun_family = " << un.sun_family); 168 NS_LOG_INFO ("sun_path = " << un.sun_path); 169 170 // 171 // We have a socket here, but we want to get it there -- to the program we're 172 // going to exec. What we'll do is to do a getsockname and then encode the 173 // resulting address information as a string, and then send the string to the 174 // program as an argument. So we need to get the sock name. 175 // 176 socklen_t len = sizeof (un); 177 status = getsockname (sock, (struct sockaddr*)&un, &len); 178 NS_ABORT_MSG_IF (status == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): Could not getsockname(): errno = " << strerror (errno)); 179 180 // 181 // Now encode that socket name (family and path) as a string of hex digits 182 // 183 std::string path = BufferToString ((uint8_t *)&un, len); 184 NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\""); 185 186 // 187 // Fork and exec the process to create our socket. If we're us (the parent) 188 // we wait for the child (the creator) to complete and read the socket it 189 // created and passed back using the ancillary data mechanism. 190 // 191 pid_t pid = ::fork (); 192 if (pid == 0) 193 { 194 NS_LOG_DEBUG ("Child process"); 195 196 // 197 // build a command line argument from the encoded endpoint string that 198 // the socket creation process will use to figure out how to respond to 199 // the (now) parent process. We're going to have to give this program 200 // quite a bit of information. 201 // 202 // -d The name of the tap device we want to create; 203 // -m The MAC-48 address to assign to the new tap device; 204 // -i The IP v4 address to assign to the new tap device; 205 // -I The IP v6 address to assign to the new tap device; 206 // -n The network IPv4 mask to assign to the new tap device; 207 // -N The network IPv6 mask to assign to the new tap device; 208 // -t Set teh IFF_TAP flag 209 // -h Set the IFF_NO_PI flag 210 // -p the path to the unix socket described above. 211 // 212 // Example tap-creator -dnewdev -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -t -h -pblah 213 // 214 215 // 216 // The device-name is something we may want the system to make up in 217 // every case. We also rely on it being configured via an Attribute 218 // through the helper. By default, it is set to the empty string 219 // which tells the system to make up a device name such as "tap123". 220 // 221 std::ostringstream ossDeviceName; 222 if (m_deviceName != "") 223 { 224 ossDeviceName << "-d" << m_deviceName; 225 } 226 227 std::ostringstream ossMac; 228 ossMac << "-m" << m_tapMac; 229 230 std::ostringstream ossIp4; 231 if (m_tapIp4 != "") 232 { 233 ossIp4 << "-i" << m_tapIp4; 234 } 235 236 std::ostringstream ossIp6; 237 if (m_tapIp6 != "") 238 { 239 ossIp6 << "-I" << m_tapIp6; 240 } 241 242 std::ostringstream ossNetmask4; 243 if (m_tapMask4 != "" ) 244 { 245 ossNetmask4 << "-n" << m_tapMask4; 246 } 247 248 std::ostringstream ossPrefix6; 249 ossPrefix6 << "-P" << m_tapPrefix6; 250 251 std::ostringstream ossMode; 252 ossMode << "-t"; 253 254 std::ostringstream ossPI; 255 if (m_modePi) 256 { 257 ossPI << "-h"; 258 } 259 260 std::ostringstream ossPath; 261 ossPath << "-p" << path; 262 263 // 264 // Execute the socket creation process image. 265 // 266 status = ::execlp (TAP_DEV_CREATOR, 267 TAP_DEV_CREATOR, // argv[0] (filename) 268 ossDeviceName.str ().c_str (), // argv[1] (-d) 269 ossMac.str ().c_str (), // argv[2] (-m 270 ossIp4.str ().c_str (), // argv[3] (-i) 271 ossIp6.str ().c_str (), // argv[4] (-I) 272 ossNetmask4.str ().c_str (), // argv[5] (-n) 273 ossPrefix6.str ().c_str (), // argv[6] (-P) 274 ossMode.str ().c_str (), // argv[7] (-t ) 275 ossPI.str ().c_str (), // argv[8] (-h ) 276 ossPath.str ().c_str (), // argv[9] (-p) 277 (char *)NULL); 278 279 // 280 // If the execlp successfully completes, it never returns. If it returns it failed or the OS is 281 // broken. In either case, we bail. 282 // 283 NS_FATAL_ERROR ("TapFdNetDeviceHelper::CreateFileDescriptor(): Back from execlp(), errno = " << ::strerror (errno)); 284 } 285 else 286 { 287 NS_LOG_DEBUG ("Parent process"); 288 // 289 // We're the process running the emu net device. We need to wait for the 290 // socket creator process to finish its job. 291 // 292 int st; 293 pid_t waited = waitpid (pid, &st, 0); 294 NS_ABORT_MSG_IF (waited == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): waitpid() fails, errno = " << strerror (errno)); 295 NS_ASSERT_MSG (pid == waited, "TapFdNetDeviceHelper::CreateFileDescriptor(): pid mismatch"); 296 297 // 298 // Check to see if the socket creator exited normally and then take a 299 // look at the exit code. If it bailed, so should we. If it didn't 300 // even exit normally, we bail too. 301 // 302 if (WIFEXITED (st)) 303 { 304 int exitStatus = WEXITSTATUS (st); 305 NS_ABORT_MSG_IF (exitStatus != 0, 306 "TapFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited normally with status " << exitStatus); 307 } 308 else 309 { 310 NS_FATAL_ERROR ("TapFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited abnormally"); 311 } 312 313 // 314 // At this point, the socket creator has run successfully and should 315 // have created our tap device, initialized it with the information we 316 // passed and sent it back to the socket address we provided. A socket 317 // (fd) we can use to talk to this tap device should be waiting on the 318 // Unix socket we set up to receive information back from the creator 319 // program. We've got to do a bunch of grunt work to get at it, though. 320 // 321 // The struct iovec below is part of a scatter-gather list. It describes a 322 // buffer. In this case, it describes a buffer (an integer) that will 323 // get the data that comes back from the socket creator process. It will 324 // be a magic number that we use as a consistency/sanity check. 325 // 326 struct iovec iov; 327 uint32_t magic; 328 iov.iov_base = &magic; 329 iov.iov_len = sizeof(magic); 330 331 // 332 // The CMSG macros you'll see below are used to create and access control 333 // messages (which is another name for ancillary data). The ancillary 334 // data is made up of pairs of struct cmsghdr structures and associated 335 // data arrays. 336 // 337 // First, we're going to allocate a buffer on the stack to receive our 338 // data array (that contains the socket). Sometimes you'll see this called 339 // an "ancillary element" but the msghdr uses the control message termimology 340 // so we call it "control." 341 // 342 size_t msg_size = sizeof(int); 343 char control[CMSG_SPACE (msg_size)]; 344 345 // 346 // There is a msghdr that is used to minimize the number of parameters 347 // passed to recvmsg (which we will use to receive our ancillary data). 348 // This structure uses terminology corresponding to control messages, so 349 // you'll see msg_control, which is the pointer to the ancillary data and 350 // controllen which is the size of the ancillary data array. 351 // 352 // So, initialize the message header that describes the ancillary/control 353 // data we expect to receive and point it to buffer. 354 // 355 struct msghdr msg; 356 msg.msg_name = 0; 357 msg.msg_namelen = 0; 358 msg.msg_iov = &iov; 359 msg.msg_iovlen = 1; 360 msg.msg_control = control; 361 msg.msg_controllen = sizeof (control); 362 msg.msg_flags = 0; 363 364 // 365 // Now we can actually receive the interesting bits from the tap 366 // creator process. Lots of pain to get four bytes. 367 // 368 ssize_t bytesRead = recvmsg (sock, &msg, 0); 369 NS_ABORT_MSG_IF (bytesRead != sizeof(int), "TapFdNetDeviceHelper::CreateFileDescriptor(): Wrong byte count from socket creator"); 370 371 // 372 // There may be a number of message headers/ancillary data arrays coming in. 373 // Let's look for the one with a type SCM_RIGHTS which indicates it's the 374 // one we're interested in. 375 // 376 struct cmsghdr *cmsg; 377 for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg)) 378 { 379 if (cmsg->cmsg_level == SOL_SOCKET 380 && cmsg->cmsg_type == SCM_RIGHTS) 381 { 382 // 383 // This is the type of message we want. Check to see if the magic 384 // number is correct and then pull out the socket we care about if 385 // it matches 386 // 387 if (magic == TAP_MAGIC) 388 { 389 NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic); 390 int *rawSocket = (int*)CMSG_DATA (cmsg); 391 NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket); 392 return *rawSocket; 393 } 394 else 395 { 396 NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic); 397 } 398 } 399 } 400 NS_FATAL_ERROR ("Did not get the raw socket from the socket creator"); 401 } 402 403 } 404 405 } // namespace ns3 406 407 ns3::Ptr smart pointer class similar to boost::intrusive_ptr Definition: ptr.h:59 NS_LOG_FUNCTION #define NS_LOG_FUNCTION(parameters) Definition: log.h:311 ns3::TapFdNetDeviceHelper::m_tapIp4 Ipv4Address m_tapIp4 Definition: tap-fd-net-device-helper.h:123 ns3::Ipv4Mask a class to represent an Ipv4 address mask Definition: ipv4-address.h:210 ns3::FdNetDevice::DIXPI Definition: fd-net-device.h:94 ns3::TapFdNetDeviceHelper::SetFileDescriptor virtual void SetFileDescriptor(Ptr< FdNetDevice > device) const Definition: tap-fd-net-device-helper.cc:133 NS_LOG_COMPONENT_DEFINE #define NS_LOG_COMPONENT_DEFINE(name) Definition: log.h:122 ns3::TapFdNetDeviceHelper::m_modePi bool m_modePi Definition: tap-fd-net-device-helper.h:116 NS_LOG_INFO #define NS_LOG_INFO(msg) Definition: log.h:264 NS_FATAL_ERROR #define NS_FATAL_ERROR(msg) fatal error handling Definition: fatal-error.h:72 ns3::TapFdNetDeviceHelper::SetTapIpv4Address void SetTapIpv4Address(Ipv4Address address) Definition: tap-fd-net-device-helper.cc:81 ns3::Mac48Address::Allocate static Mac48Address Allocate(void) Definition: mac48-address.cc:130 ns3::BufferToString std::string BufferToString(uint8_t *buffer, uint32_t len) Convert a byte buffer to a string containing a hex representation of the buffer. Make the string pret... Definition: encode-decode.cc:37 ns3::TapFdNetDeviceHelper::SetTapMacAddress void SetTapMacAddress(Mac48Address mac) Definition: tap-fd-net-device-helper.cc:105 ns3::TapFdNetDeviceHelper::CreateFileDescriptor virtual int CreateFileDescriptor(void) const Definition: tap-fd-net-device-helper.cc:146 ns3::TapFdNetDeviceHelper::TapFdNetDeviceHelper TapFdNetDeviceHelper() Definition: tap-fd-net-device-helper.cc:63 NS_LOG_LOGIC #define NS_LOG_LOGIC(msg) Definition: log.h:334 ns3::FdNetDevice::SetEncapsulationMode void SetEncapsulationMode(FdNetDevice::EncapsulationMode mode) Definition: fd-net-device.cc:184 ns3::TapFdNetDeviceHelper::m_tapPrefix6 int m_tapPrefix6 Definition: tap-fd-net-device-helper.h:145 ns3::Mac48Address an EUI-48 address Definition: mac48-address.h:41 ns3::TapFdNetDeviceHelper::SetTapIpv4Mask void SetTapIpv4Mask(Ipv4Mask mask) Definition: tap-fd-net-device-helper.cc:87 ns3::TapFdNetDeviceHelper::m_tapMac Mac48Address m_tapMac Definition: tap-fd-net-device-helper.h:153 NS_ASSERT_MSG #define NS_ASSERT_MSG(condition, message) Definition: assert.h:86 ns3::Ipv6Address Describes an IPv6 address. Definition: ipv6-address.h:44 ns3::Ipv4Address Ipv4 addresses are stored in host order in this class. Definition: ipv4-address.h:38 ns3::TapFdNetDeviceHelper::SetTapIpv6Prefix void SetTapIpv6Prefix(int prefix) Definition: tap-fd-net-device-helper.cc:99 ns3::TapFdNetDeviceHelper::SetTapIpv6Address void SetTapIpv6Address(Ipv6Address address) Definition: tap-fd-net-device-helper.cc:93 ns3::TapFdNetDeviceHelper::m_tapIp6 Ipv6Address m_tapIp6 Definition: tap-fd-net-device-helper.h:130 NS_LOG_DEBUG #define NS_LOG_DEBUG(msg) Definition: log.h:255 ns3::FdNetDevice a NetDevice to read/write network traffic from/into a file descriptor. Definition: fd-net-device.h:82 ns3::TapFdNetDeviceHelper::m_tapMask4 Ipv4Mask m_tapMask4 Definition: tap-fd-net-device-helper.h:138 NS_ABORT_MSG_IF #define NS_ABORT_MSG_IF(cond, msg) Abnormal program termination if cond is true. Definition: abort.h:98 ns3::TapFdNetDeviceHelper::SetModePi void SetModePi(bool pi) Definition: tap-fd-net-device-helper.cc:75 ns3::EmuFdNetDeviceHelper::m_deviceName std::string m_deviceName Definition: emu-fd-net-device-helper.h:86 src fd-net-device helper tap-fd-net-device-helper.cc Generated on Sun Mar 16 2014 11:25:03 for ns-3 by 1.8.6