#include #include #include #include #include #include #include #include #include "tfe_utils.h" #ifndef TUN_PATH #define TUN_PATH "/dev/net/tun" #endif extern void *g_default_logger; /* * IFF_TUN : TUN device (IP) * IFF_TAP : TAP device (Ethernet) * IFF_NO_PI : Do not provide packet information * IFF_MULTI_QUEUE : Create a queue of multiqueue device * IFF_ONE_QUEUE : Create a queue of oniequeue device */ int tap_open(const char *eth, int flags) { int sockfd = open(TUN_PATH, O_RDWR); if (sockfd == -1) { TFE_LOG_ERROR(g_default_logger, "unable to open " TUN_PATH ", %s.\n", strerror(errno)); return -1; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; strcpy(ifr.ifr_name, eth); if (ioctl(sockfd, TUNSETIFF, &ifr) == -1) { TFE_LOG_ERROR(g_default_logger, "unable to attach %s, %s.\n", eth, strerror(errno)); goto error; } /* * The TUNSETPERSIST ioctl can be used to make the TUN/TAP interface persistent. * In this mode, the interface won't be destroyed when the last process closes the associated /dev/net/tun file descriptor. */ if (ioctl(sockfd, TUNSETPERSIST, 1) == -1) { TFE_LOG_ERROR(g_default_logger, "unable to set persist on %s, %s.\n", eth, strerror(errno)); goto error; } if (ioctl(sockfd, TUNSETOWNER, 0) == -1) { TFE_LOG_ERROR(g_default_logger, "unable to set owner on %s, %s.\n", eth, strerror(errno)); goto error; } if (ioctl(sockfd, TUNSETGROUP, 0) == -1) { TFE_LOG_ERROR(g_default_logger, "unable to set group on %s, %s.\n", eth, strerror(errno)); goto error; } if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK) == -1) { TFE_LOG_ERROR(g_default_logger, "unable to set nonblock on fd: %d, %s.\n", sockfd, strerror(errno)); return -1; } return sockfd; error: if (sockfd > 0) { close(sockfd); } return -1; } void tap_close(int sockfd) { if (sockfd > 0) { close(sockfd); } } int tap_up_link(const char *eth) { int sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (sockfd == -1) { TFE_LOG_ERROR(g_default_logger, "unable to create socket, %s.\n", strerror(errno)); return -1; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, eth); if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == -1) { TFE_LOG_ERROR(g_default_logger, "unable to get link status on %s, %s.\n", eth, strerror(errno)); close(sockfd); return -1; } if ((ifr.ifr_flags & IFF_UP) == 0) { ifr.ifr_flags |= IFF_UP; if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { TFE_LOG_ERROR(g_default_logger, "unable to set link up on %s, %s.\n", eth, strerror(errno)); close(sockfd); return -1; } } close(sockfd); return 0; } int tap_get_mtu(const char *eth) { int sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (sockfd == -1) { TFE_LOG_ERROR(g_default_logger, "unable to create socket, %s.\n", strerror(errno)); return -1; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, eth); if (ioctl(sockfd, SIOCGIFMTU, &ifr) < 0) { TFE_LOG_ERROR(g_default_logger, "unable to get mtu on %s, %s.\n", eth, strerror(errno)); close(sockfd); return -1; } close(sockfd); return ifr.ifr_mtu; } int tap_set_rps(const char *eth, int thread_index, const char *rps_mask) { char file[1024] = {0}; snprintf(file, sizeof(file), "/sys/class/net/%s/queues/rx-%d/rps_cpus", eth, thread_index); FILE *fp = fopen(file, "w"); if (fp == NULL) { TFE_LOG_ERROR(g_default_logger, "unable to set rps on %s, file %s, %s", eth, file, strerror(errno)); return -1; } fwrite(rps_mask, strlen(rps_mask), 1, fp); TFE_LOG_DEBUG(g_default_logger, "set rps '%s' to %s", rps_mask, file); fclose(fp); return 0; }