#include #include #include #include #include #include #include #include #include static char * mr4_ethdev_send_prepare(struct traffic_mirror_ethdev * ethdev, unsigned int tid) { struct traffic_mirror_ethdev_mr4 * detail_mr4 = ethdev->detail_mr4; assert(tid < detail_mr4->nr_tx_threads); marsio_buff_t * buff; int ret = marsio_buff_malloc_device(detail_mr4->device, &buff, 1, MARSIO_SOCKET_ID_ANY, MARSIO_LCORE_ID_ANY); if (unlikely(ret < 0)) { assert(0); return NULL; } char * buff_start = marsio_buff_mtod(buff); if (unlikely(!buff_start)) { assert(0); return NULL; } detail_mr4->sendbuf[tid] = buff; return buff_start; } static int mr4_ethdev_send_finish(struct traffic_mirror_ethdev * ethdev, unsigned int tid, unsigned int pktlen) { struct traffic_mirror_ethdev_mr4 * detail_mr4 = ethdev->detail_mr4; assert(detail_mr4 != NULL && detail_mr4->sendbuf[tid] != NULL); marsio_buff_t * buff = detail_mr4->sendbuf[tid]; UNUSED char * append_ptr = marsio_buff_append(buff, pktlen); assert(append_ptr != NULL); int ret = marsio_send_burst_with_options(detail_mr4->sendpath, tid, &buff, 1, MARSIO_SEND_OPT_REHASH); if (unlikely(ret < 0)) { marsio_buff_free(detail_mr4->instance, &buff, 1, MARSIO_SOCKET_ID_ANY, MARSIO_LCORE_ID_ANY); return -1; } detail_mr4->sendbuf[tid] = NULL; return 0; } static void mr4_ethdev_send_abort(struct traffic_mirror_ethdev * ethdev, unsigned int tid) { struct traffic_mirror_ethdev_mr4 * detail_mr4 = ethdev->detail_mr4; assert(detail_mr4 != NULL && detail_mr4->sendbuf[tid] != NULL); marsio_buff_t * buff = detail_mr4->sendbuf[tid]; marsio_buff_free(detail_mr4->instance, &buff, 1, MARSIO_SOCKET_ID_ANY, MARSIO_LCORE_ID_ANY); detail_mr4->sendbuf[tid] = NULL; } static void mr4_ethdev_destroy(struct traffic_mirror_ethdev * ethdev) { struct traffic_mirror_ethdev_mr4 * detail_mr4 = ethdev->detail_mr4; if(detail_mr4 && detail_mr4->sendpath) { marsio_sendpath_destory(detail_mr4->sendpath); } if(detail_mr4 && detail_mr4->device) { marsio_close_device(detail_mr4->device); } if(detail_mr4 && detail_mr4->instance) { marsio_destory(detail_mr4->instance); } if(detail_mr4) { free(detail_mr4); } free(ethdev); } /* =============================== MODE LIBPCAP ========================================== */ static char * pcap_ethdev_send_prepare(struct traffic_mirror_ethdev *ethdev, unsigned int tid) { struct traffic_mirror_ethdev_pcap * detail_pcap = ethdev->detail_pcap; return detail_pcap->sendbuf[tid]; } static int pcap_ethdev_send_finish(struct traffic_mirror_ethdev * ethdev, unsigned int tid, unsigned int pktlen) { struct traffic_mirror_ethdev_pcap * detail_pcap = ethdev->detail_pcap; assert(detail_pcap != NULL && detail_pcap->sendbuf[tid] != NULL); char * sendbuf = detail_pcap->sendbuf[tid]; return pcap_sendpacket(detail_pcap->pcap_device_handle, (const u_char *)sendbuf, pktlen); } static void pcap_ethdev_send_abort(struct traffic_mirror_ethdev * ethdev, unsigned int tid) { return; } static void pcap_ethdev_destroy(struct traffic_mirror_ethdev * ethdev) { pcap_close(ethdev->detail_pcap->pcap_device_handle); return free(ethdev); } /* =============================== VIRTUAL INTERFACE START ========================================== */ void traffic_mirror_ethdev_destroy(struct traffic_mirror_ethdev * ethdev) { ethdev->fn_destroy(ethdev); } int traffic_mirror_ethdev_finish(struct traffic_mirror_ethdev * ethdev, unsigned int tid, unsigned int pktlen) { return ethdev->fn_send_finish(ethdev, tid, pktlen); } char * traffic_mirror_ethdev_send_prepare(struct traffic_mirror_ethdev * ethdev, unsigned int tid) { return ethdev->fn_send_prepare(ethdev, tid); } /* =============================== VIRTUAL INTERFACE END =========================================== */ struct traffic_mirror_ethdev * traffic_mirror_ethdev_mr4_create(const char * str_ethdev, unsigned int nr_threads, void * logger) { struct traffic_mirror_ethdev * ethdev = ALLOC(struct traffic_mirror_ethdev, 1); ethdev->type = TRAFFIC_MIRROR_ETHDEV_MARSIO; ethdev->detail_mr4 = ALLOC(struct traffic_mirror_ethdev_mr4, 1); strncpy(ethdev->str_device, str_ethdev, sizeof(ethdev->str_device) - 1); /* PREPARE MR4 INSTANCES */ struct traffic_mirror_ethdev_mr4 * detail_mr4 = ethdev->detail_mr4; detail_mr4->nr_tx_threads = nr_threads; /* create a marsio instance and setup options, * the instance need to run in no-thread-affinity mode */ detail_mr4->instance = marsio_create(); assert(detail_mr4->instance != NULL); if (marsio_init(detail_mr4->instance, "tfe-traffic-mirror") < 0) { TFE_LOG_ERROR(logger, "failed at init MARSIOv4 instance."); goto errout; } detail_mr4->device = marsio_open_device(detail_mr4->instance, str_ethdev, 0, nr_threads); if (!detail_mr4->device) { TFE_LOG_ERROR(logger, "failed at open device %s, nr_threads = %u", str_ethdev, nr_threads); goto errout; } detail_mr4->sendpath = marsio_sendpath_create_by_vdev(detail_mr4->device); if (!detail_mr4->sendpath) { TFE_LOG_ERROR(logger, "failed at creating sendpath for device %s", str_ethdev); goto errout; } /* TODO: load the mtu and mac address from mrzcpd */ ethdev->mtu = ETHER_MAX_LEN; ethdev->fn_send_prepare = mr4_ethdev_send_prepare; ethdev->fn_send_finish = mr4_ethdev_send_finish; ethdev->fn_send_abort = mr4_ethdev_send_abort; ethdev->fn_destroy = mr4_ethdev_destroy; return ethdev; errout: if (ethdev) { mr4_ethdev_destroy(ethdev); } return NULL; } struct traffic_mirror_ethdev * traffic_mirror_ethdev_pcap_create(const char * str_ethdev, void * logger) { struct traffic_mirror_ethdev * ethdev = ALLOC(struct traffic_mirror_ethdev, 1); char pcap_errbuf[PCAP_ERRBUF_SIZE] = {}; int fd = 0; struct ifreq if_req{}; ethdev->en_offload_ip_cksum = 0; ethdev->en_offload_tcp_cksum = 0; ethdev->en_offload_vlan = 0; ethdev->detail_pcap = ALLOC(struct traffic_mirror_ethdev_pcap, 1); ethdev->detail_pcap->pcap_device_handle = pcap_open_live(str_ethdev, 0, 0, 0, pcap_errbuf); if (!ethdev->detail_pcap->pcap_device_handle) { TFE_LOG_ERROR(logger, "failed at pcap_open_live(), device = %s: %s", str_ethdev, pcap_errbuf); goto errout; } /* local ether address */ fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd < 0) { TFE_LOG_ERROR(logger, "failed at create socket: %s", strerror(errno)); goto errout; } memset(&if_req, 0, sizeof(if_req)); strncpy(if_req.ifr_ifrn.ifrn_name, str_ethdev, IFNAMSIZ - 1); if(ioctl(fd, SIOCGIFHWADDR, &if_req) < 0) { TFE_LOG_ERROR(logger, "failed at read hwaddr of device %s: %s", str_ethdev, strerror(errno)); goto errout; } for(int i = 0; i < 6; i++) { ethdev->local_ether_addr[i] = if_req.ifr_ifru.ifru_hwaddr.sa_data[i]; } /* MTU */ memset(&if_req, 0, sizeof(if_req)); strncpy(if_req.ifr_ifrn.ifrn_name, str_ethdev, IFNAMSIZ - 1); if (ioctl(fd, SIOCGIFMTU, &if_req) < 0) { TFE_LOG_ERROR(logger, "failed at read mtu of device %s: %s", str_ethdev, strerror(errno)); goto errout; } ethdev->mtu = if_req.ifr_ifru.ifru_mtu; strncpy(ethdev->str_device, str_ethdev, sizeof(ethdev->str_device) - 1); TFE_LOG_INFO(logger, "traffic mirror device %s (pcap mode): %02X:%02X:%02X:%02X:%02X:%02X, mtu=%u", ethdev->str_device, ethdev->local_ether_addr[0], ethdev->local_ether_addr[1], ethdev->local_ether_addr[2], ethdev->local_ether_addr[3], ethdev->local_ether_addr[4], ethdev->local_ether_addr[5], ethdev->mtu); ethdev->fn_send_prepare = pcap_ethdev_send_prepare; ethdev->fn_send_finish = pcap_ethdev_send_finish; ethdev->fn_send_abort = pcap_ethdev_send_abort; ethdev->fn_destroy = pcap_ethdev_destroy; close(fd); return ethdev; errout: if (fd > 0) close(fd); if (ethdev->detail_pcap->pcap_device_handle) pcap_close(ethdev->detail_pcap->pcap_device_handle); if (ethdev) FREE(ðdev); return nullptr; }