+#if USE_TUNTAP
+
+EtherTap::EtherTap(const Params *p) : EtherTapBase(p)
+{
+ int fd = open(p->tun_clone_device.c_str(), O_RDWR | O_NONBLOCK);
+ if (fd < 0)
+ panic("Couldn't open %s.\n", p->tun_clone_device);
+
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strncpy(ifr.ifr_name, p->tap_device_name.c_str(), IFNAMSIZ - 1);
+
+ if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)
+ panic("Failed to access tap device %s.\n", ifr.ifr_name);
+ // fd now refers to the tap device.
+ tap = fd;
+ pollFd(tap);
+}
+
+EtherTap::~EtherTap()
+{
+ stopPolling();
+ close(tap);
+ tap = -1;
+}
+
+void
+EtherTap::recvReal(int revent)
+{
+ if (revent & POLLERR)
+ panic("Error polling for tap data.\n");
+
+ if (!(revent & POLLIN))
+ return;
+
+ ssize_t ret;
+ while ((ret = read(tap, buffer, buflen))) {
+ if (ret < 0) {
+ if (errno == EAGAIN)
+ break;
+ panic("Failed to read from tap device.\n");
+ }
+
+ sendSimulated(buffer, ret);
+ }
+}
+
+bool
+EtherTap::sendReal(const void *data, size_t len)
+{
+ int n;
+ pollfd pfd[1];
+ pfd->fd = tap;
+ pfd->events = POLLOUT;
+
+ // `tap` is a nonblock fd. Here we try to write until success, and use
+ // poll to make a blocking wait.
+ while ((n = write(tap, data, len)) != len) {
+ if (errno != EAGAIN)
+ panic("Failed to write data to tap device.\n");
+ pfd->revents = 0;
+ int ret = poll(pfd, 1, -1);
+ // timeout is set to inf, we shouldn't get 0 in any case.
+ assert(ret != 0);
+ if (ret == -1 || (ret == 1 && (pfd->revents & POLLERR))) {
+ panic("Failed when polling to write data to tap device.\n");
+ }
+ }
+ return true;
+}
+
+EtherTap *
+EtherTapParams::create()
+{
+ return new EtherTap(this);
+}
+
+#endif
+