USocket *usock_accept(int fd, void *cred_p, int clen) { USocket *usock = NULL; struct sockaddr_in addr; socklen_t alen = sizeof(addr); char buf[clen]; Uint32 val, n; while (1) { n = recvfrom(fd, buf, clen, 0, (Sockaddr *)&addr, &alen); if (n < 0) { perror("recvform"); break; } else if (n == clen && memcmp(cred_p, buf, clen) == 0) { usock = create_usock(fd, &addr, cred_p, clen); break; } } if (usock == NULL) return NULL; n = send_accept_msg(fd, &val); if (n == sizeof(val) || val == UMSG_REPLY_ACCEPT) { usock->status |= USOCK_CONNECT; sem_post(&usock->sem); return usock; } sem_post(&usock->sem); usock_close(usock); return NULL; }
USocket * usock_connect(int fd, struct sockaddr_in *addr_p, void *cred_p, Uint32 clen) { USocket *usock; Uint32 val; int n; if (!(usock = create_usock(fd, addr_p, cred_p, clen))) return NULL; n = send_connect_msg(fd, cred_p, clen, &val); if (n != sizeof(val) || val != UMSG_ACCEPT) goto reterr; val = htonl(UMSG_REPLY_ACCEPT); if (write(fd, &val, sizeof(val)) == sizeof(val)) { usock->status |= USOCK_CONNECT; sem_post(&usock->sem); return usock; } reterr: sem_post(&usock->sem); usock_close(usock); return NULL; }
static void usock_close(struct vr_usocket *usockp) { int i; struct vr_usocket *parent; RTE_SET_USED(parent); if (!usockp) return; RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(), usockp->usock_fd); usock_unbind(usockp); usock_deinit_poll(usockp); for (i = 0; i < usockp->usock_cfds; i++) { usock_close(usockp->usock_children[i]); } RTE_LOG(DEBUG, USOCK, "%s: closing FD %d\n", __func__, usockp->usock_fd); close(usockp->usock_fd); if (!usockp->usock_mbuf_pool && usockp->usock_rx_buf) { vr_free(usockp->usock_rx_buf, VR_USOCK_BUF_OBJECT); usockp->usock_rx_buf = NULL; } if (usockp->usock_iovec) { vr_free(usockp->usock_iovec, VR_USOCK_IOVEC_OBJECT); usockp->usock_iovec = NULL; } if (usockp->usock_mbuf_pool) { /* no api to destroy a pool */ } if (usockp->usock_proto == PACKET) { RTE_LOG(DEBUG, USOCK, "%s[%lx]: unlinking %s\n", __func__, pthread_self(), VR_PACKET_UNIX_FILE); unlink(VR_PACKET_UNIX_FILE); } usockp->usock_io_in_progress = 0; vr_free(usockp, VR_USOCK_OBJECT); return; }
void vr_usocket_close(void *sock) { struct vr_usocket *usockp = (struct vr_usocket *)sock; if (usockp == NULL) return; RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(), usockp->usock_fd); if (usockp->usock_io_in_progress) { usockp->usock_should_close = 1; return; } usock_close(usockp); return; }
static int vr_usocket_read(struct vr_usocket *usockp) { int ret; if (!usockp || usockp->usock_fd < 0) return -1; switch (usockp->usock_state) { case LISTENING: case LIMITED: ret = vr_usocket_accept(usockp); if (ret < 0) return ret; break; case READING_HEADER: case READING_DATA: case READING_FAULTY_DATA: ret = __usock_read(usockp); if (ret < 0) { RTE_LOG(DEBUG, USOCK, "%s[%lx]: read error FD %d\n", __func__, pthread_self(), usockp->usock_fd); usock_close(usockp); return ret; } if (usockp->usock_read_offset == usockp->usock_read_len) { usock_read_done(usockp); /* we have the complete message */ usock_read_init(usockp); } break; default: return -1; } return ret; }
static int usock_write(struct vr_usocket *usockp) { int ret; if (!usockp || usockp->usock_fd < 0) return 0; ret = __usock_write(usockp); if (ret < 0) { usock_close(usockp); return ret; } if (usockp->usock_proto == NETLINK) { if (usockp->usock_write_offset == usockp->usock_write_len) { usock_netlink_write_responses(usockp); } } return 0; }
static struct vr_usocket * usock_alloc(unsigned short proto, unsigned short type) { int sock_fd = -1, domain, ret; /* socket TX buffer size = (hold flow table entries * size of jumbo frame) */ int setsocksndbuff = vr_flow_hold_limit * VR_DPDK_MAX_PACKET_SZ; int getsocksndbuff; socklen_t getsocksndbufflen = sizeof(getsocksndbuff); int error = 0, flags; unsigned int buf_len; struct vr_usocket *usockp = NULL, *child; bool is_socket = true; unsigned short sock_type; RTE_SET_USED(child); RTE_LOG(DEBUG, USOCK, "%s[%lx]: proto %u type %u\n", __func__, pthread_self(), proto, type); switch (type) { case TCP: domain = AF_INET; sock_type = SOCK_STREAM; break; case UNIX: case RAW: domain = AF_UNIX; sock_type = SOCK_DGRAM; break; default: return NULL; } if (proto == EVENT) { is_socket = false; sock_fd = eventfd(0, 0); RTE_LOG(DEBUG, USOCK, "%s[%lx]: new event FD %d\n", __func__, pthread_self(), sock_fd); if (sock_fd < 0) return NULL; } if (is_socket) { sock_fd = socket(domain, sock_type, 0); RTE_LOG(INFO, USOCK, "%s[%lx]: new socket FD %d\n", __func__, pthread_self(), sock_fd); if (sock_fd < 0) return NULL; /* set socket send buffer size */ ret = setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &setsocksndbuff, sizeof(setsocksndbuff)); if (ret == 0) { /* check if setting buffer succeeded */ ret = getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &getsocksndbuff, &getsocksndbufflen); if (ret == 0) { if (getsocksndbuff >= setsocksndbuff) { RTE_LOG(INFO, USOCK, "%s[%lx]: setting socket FD %d send buff size.\n" "Buffer size set to %d (requested %d)\n", __func__, pthread_self(), sock_fd, getsocksndbuff, setsocksndbuff); } else { /* set other than requested */ RTE_LOG(ERR, USOCK, "%s[%lx]: setting socket FD %d send buff size failed.\n" "Buffer size set to %d (requested %d)\n", __func__, pthread_self(), sock_fd, getsocksndbuff, setsocksndbuff); } } else { /* requesting buffer size failed */ RTE_LOG(ERR, USOCK, "%s[%lx]: getting socket FD %d send buff size failed (%d)\n", __func__, pthread_self(), sock_fd, errno); } } else { /* setting buffer size failed */ RTE_LOG(ERR, USOCK, "%s[%lx]: setting socket FD %d send buff size %d failed (%d)\n", __func__, pthread_self(), sock_fd, setsocksndbuff, errno); } } usockp = vr_zalloc(sizeof(*usockp), VR_USOCK_OBJECT); if (!usockp) goto error_exit; usockp->usock_type = type; usockp->usock_proto = proto; usockp->usock_fd = sock_fd; usockp->usock_state = INITED; if (is_socket) { error = vr_usocket_bind(usockp); if (error < 0) goto error_exit; if (usockp->usock_proto == PACKET) { error = vr_usocket_connect(usockp); if (error < 0) goto error_exit; } } switch (proto) { case NETLINK: usockp->usock_max_cfds = USOCK_MAX_CHILD_FDS; buf_len = 0; break; case PACKET: usockp->usock_max_cfds = USOCK_MAX_CHILD_FDS; buf_len = 0; break; case EVENT: /* TODO: we don't need the buf since we use stack to send an event */ buf_len = USOCK_EVENT_BUF_LEN; break; default: buf_len = 0; break; } if (buf_len) { usockp->usock_rx_buf = vr_zalloc(buf_len, VR_USOCK_BUF_OBJECT); if (!usockp->usock_rx_buf) goto error_exit; usockp->usock_buf_len = buf_len; usock_read_init(usockp); } if (proto == PACKET) { usockp->usock_mbuf_pool = rte_mempool_lookup("packet_mbuf_pool"); if (!usockp->usock_mbuf_pool) { usockp->usock_mbuf_pool = rte_mempool_create("packet_mbuf_pool", PKT0_MBUF_POOL_SIZE, PKT0_MBUF_PACKET_SIZE, PKT0_MBUF_POOL_CACHE_SZ, sizeof(struct rte_pktmbuf_pool_private), vr_dpdk_pktmbuf_pool_init, NULL, vr_dpdk_pktmbuf_init, NULL, rte_socket_id(), 0); if (!usockp->usock_mbuf_pool) goto error_exit; } usockp->usock_iovec = vr_zalloc(sizeof(struct iovec) * PKT0_MAX_IOV_LEN, VR_USOCK_IOVEC_OBJECT); if (!usockp->usock_iovec) goto error_exit; usock_read_init(usockp); } RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d F_GETFL\n", __func__, pthread_self(), usockp->usock_fd); flags = fcntl(usockp->usock_fd, F_GETFL); if (flags == -1) goto error_exit; RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d F_SETFL\n", __func__, pthread_self(), usockp->usock_fd); error = fcntl(usockp->usock_fd, F_SETFL, flags | O_NONBLOCK); if (error == -1) goto error_exit; usockp->usock_poll_block = 1; return usockp; error_exit: error = errno; if (sock_fd >= 0) { close(sock_fd); sock_fd = -1; } usock_close(usockp); usockp = NULL; errno = error; return usockp; }
/* * start io on socket */ int vr_usocket_io(void *transport) { int ret, i, processed; int timeout; struct pollfd *pfd; struct vr_usocket *usockp = (struct vr_usocket *)transport; unsigned lcore_id = rte_lcore_id(); struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id]; if (!usockp) return -1; RTE_LOG(DEBUG, USOCK, "%s[%lx]: FD %d\n", __func__, pthread_self(), usockp->usock_fd); if ((ret = usock_init_poll(usockp))) goto return_from_io; pfd = &usockp->usock_pfds[0]; pfd->fd = usockp->usock_fd; pfd->events = POLLIN; usockp->usock_io_in_progress = 1; timeout = usockp->usock_poll_block ? INFINITE_TIMEOUT : 0; while (1) { if (usockp->usock_should_close) { usock_close(usockp); return -1; } /* * Handle an IPC commands for IO_LCORE_ID up * and just check the stop flag for the rest. */ if (lcore_id >= VR_DPDK_IO_LCORE_ID) { if (unlikely(vr_dpdk_lcore_cmd_handle(lcore))) break; } else { if (unlikely(vr_dpdk_is_stop_flag_set())) break; } rcu_thread_offline(); ret = poll(usockp->usock_pfds, usockp->usock_max_cfds, timeout); if (ret < 0) { usock_set_error(usockp, ret); /* all other errors are fatal */ if (errno != EINTR) goto return_from_io; } rcu_thread_online(); processed = 0; pfd = usockp->usock_pfds; for (i = 0; (i < usockp->usock_max_cfds) && (processed < ret); i++, pfd++) { if ((pfd->fd >= 0)) { if (pfd->revents & POLLIN) { if (i == 0) { ret = vr_usocket_read(usockp); if (ret < 0) return ret; } else { vr_usocket_read(usockp->usock_children[i]); } } if (pfd->revents & POLLOUT) { usock_write(usockp->usock_children[i]); } if (pfd->revents & POLLHUP) { if (i) { usock_close(usockp->usock_children[i]); } else { break; } } if (pfd->revents) processed++; } } if (!timeout) return 0; } return_from_io: usockp->usock_io_in_progress = 0; usock_deinit_poll(usockp); return ret; }