void citp_waitable_wakeup(ci_netif* ni, citp_waitable* w) { oo_waitable_wake_t op; op.sock_id = w->bufid; oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_WAITABLE_WAKE, &op); }
int oo_os_sock_recvmsg(ci_netif* ni, oo_sp sock_p, struct msghdr* msg, int flags) { oo_os_sock_recvmsg_t op; int rc; op.sock_id = OO_SP_TO_INT(sock_p); op.sizeof_ptr = sizeof(void*); op.flags = flags; CI_USER_PTR_SET(op.msg_iov, msg->msg_iov); op.msg_iovlen = msg->msg_iovlen; CI_USER_PTR_SET(op.msg_name, msg->msg_name); op.msg_namelen = msg->msg_namelen; CI_USER_PTR_SET(op.msg_control, msg->msg_control); op.msg_controllen = msg->msg_controllen; rc = oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OS_SOCK_RECVMSG, &op); ci_assert(op.rc >= 0 || rc < 0); if( rc == 0 ) { msg->msg_flags = op.flags; msg->msg_namelen = op.msg_namelen; if( msg->msg_controllen ) msg->msg_controllen = op.msg_controllen; return op.rc; } return rc; }
int oo_os_sock_get(ci_netif* ni, oo_sp sock_p, oo_os_file* os_sock_out) { oo_os_sock_fd_get_t op; int rc; oo_rwlock_lock_read(&citp_dup2_lock); op.sock_id = OO_SP_TO_INT(sock_p); rc = oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OS_SOCK_FD_GET, &op); if( rc == 0 ) *os_sock_out = op.fd_out; else oo_rwlock_unlock_read (&citp_dup2_lock); return rc; }
static void do_ofe_command(ci_netif *ni) { char command[200]; char *str = command; int rc; oo_ofe_config_t op; int i; if( ni->ofe == NULL ) return; for( i = 0; i < cfg_argc; i++ ) str += snprintf(str, sizeof(command) - (str - command), "%s ", cfg_argv[i]); op.len = str - command; CI_USER_PTR_SET(op.str, command); rc = oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OFE_CONFIG, &op); oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OFE_CONFIG_DONE, NULL); if( rc == 0 ) { ci_log("[%s] %s: OK", ni->state->pretty_name, command); return; } ci_log("[%s] Onload Filter Engine fails to process command\n\t%s", ni->state->pretty_name, command); if( ofe_engine_get_last_error(ni->ofe) != NULL ) ci_log("OFE ERROR: %s", ofe_engine_get_last_error(ni->ofe)); else { char err[CI_LOG_MAX_LINE]; oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OFE_GET_LAST_ERROR, err); err[CI_LOG_MAX_LINE-1] = '\0'; ci_log("OFE ERROR: %s", err); } }
int oo_os_sock_accept(ci_netif* ni, oo_sp sock_p, struct sockaddr *addr, socklen_t *addrlen, int flags) { oo_os_sock_accept_t op; int rc; op.sock_id = OO_SP_TO_INT(sock_p); CI_USER_PTR_SET(op.addr, addr); CI_USER_PTR_SET(op.addrlen, addrlen); op.flags = flags; rc = oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OS_SOCK_ACCEPT, &op); return rc == 0 ? op.rc : rc; }
/* SIG_DFL simulator for signals like SIGINT, SIGTERM: it is postponed * properly to safe shared stacks. */ static void citp_signal_terminate(int signum, siginfo_t *info, void *context) { int fd; int rc; /* get any Onload fd to call ioctl */ rc = ef_onload_driver_open(&fd, OO_STACK_DEV, 1); /* Die now: * _exit sets incorrect status in waitpid(), so we should try to exit via * signal. Use _exit() if there is no other way. */ if( rc == 0 ) oo_resource_op(fd, OO_IOC_DIE_SIGNAL, &signum); else _exit(128 + signum); }
int oo_os_sock_sendmsg_raw(ci_netif* ni, oo_sp sock_p, const struct msghdr* msg, int flags) { unsigned long socketcall_args[8]; oo_os_sock_sendmsg_raw_t op; int rc; op.sock_id = OO_SP_TO_INT(sock_p); op.sizeof_ptr = sizeof(void*); op.flags = flags; CI_USER_PTR_SET(op.msg, msg); CI_USER_PTR_SET(op.socketcall_args, socketcall_args); oo_rwlock_lock_read(&citp_dup2_lock); rc = oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OS_SOCK_SENDMSG_RAW, &op); oo_rwlock_unlock_read (&citp_dup2_lock); return rc; }
static int fdtable_fd_move(ci_fd_t sock_fd, int op) { ci_uint32 io_fd = sock_fd; int rc; oo_rwlock_lock_read(&citp_dup2_lock); rc = oo_resource_op(sock_fd, op, &io_fd); if( rc != 0 || io_fd == sock_fd ) { oo_rwlock_unlock_read(&citp_dup2_lock); return rc; } /* Kernel failed to hand over, but there is no epoll here - let's dup */ rc = ci_sys_dup2(io_fd, sock_fd); ci_tcp_helper_close_no_trampoline(io_fd); oo_rwlock_unlock_read(&citp_dup2_lock); if( rc == sock_fd ) return 0; else if( rc >= 0 ) return -EINVAL; return rc; }
int oo_os_sock_sendmsg(ci_netif* ni, oo_sp sock_p, const struct msghdr* msg, int flags) { oo_os_sock_sendmsg_t op; op.sock_id = OO_SP_TO_INT(sock_p); op.sizeof_ptr = sizeof(void*); op.flags = flags; CI_USER_PTR_SET(op.msg_iov, msg->msg_iov); op.msg_iovlen = msg->msg_iovlen; CI_USER_PTR_SET(op.msg_name, msg->msg_name); op.msg_namelen = msg->msg_namelen; #ifdef __i386__ /* compat cmsg is not handled in this function */ ci_assert_equal(msg->msg_controllen, 0); op.msg_controllen = 0; CI_USER_PTR_SET(op.msg_control, NULL); #else CI_USER_PTR_SET(op.msg_control, msg->msg_control); op.msg_controllen = msg->msg_controllen; #endif return oo_resource_op(ci_netif_get_driver_handle(ni), OO_IOC_OS_SOCK_SENDMSG, &op); }
/* Returns: * 0 on success * * CI_SOCKET_ERROR (and errno set) * this is a normal error that is returned to the * the application * * CI_SOCKET_HANDOVER we tell the upper layers to handover, no need * to set errno since it isn't a real error */ int ci_tcp_connect(citp_socket* ep, const struct sockaddr* serv_addr, socklen_t addrlen, ci_fd_t fd, int *p_moved) { /* Address family is validated earlier. */ struct sockaddr_in* inaddr = (struct sockaddr_in*) serv_addr; ci_sock_cmn* s = ep->s; ci_tcp_state* ts = &SOCK_TO_WAITABLE_OBJ(s)->tcp; int rc = 0, crc; ci_uint32 dst_be32; if( NI_OPTS(ep->netif).tcp_connect_handover ) return CI_SOCKET_HANDOVER; /* Make sure we're up-to-date. */ ci_netif_lock(ep->netif); CHECK_TEP(ep); ci_netif_poll(ep->netif); /* * 1. Check if state of the socket is OK for connect operation. */ start_again: if( (rc = ci_tcp_connect_handle_so_error(s)) != 0) { CI_SET_ERROR(rc, rc); goto unlock_out; } if( s->b.state != CI_TCP_CLOSED ) { /* see if progress can be made on this socket before ** determining status (e.g. non-blocking connect and connect poll)*/ if( s->b.state & CI_TCP_STATE_SYNCHRONISED ) { if( ts->tcpflags & CI_TCPT_FLAG_NONBLOCK_CONNECT ) { ts->tcpflags &= ~CI_TCPT_FLAG_NONBLOCK_CONNECT; rc = 0; goto unlock_out; } if( serv_addr->sa_family == AF_UNSPEC ) LOG_E(ci_log("Onload does not support TCP disconnect via " "connect(addr->sa_family==AF_UNSPEC)")); CI_SET_ERROR(rc, EISCONN); } else if( s->b.state == CI_TCP_LISTEN ) { #if CI_CFG_POSIX_CONNECT_AFTER_LISTEN CI_SET_ERROR(rc, EOPNOTSUPP); #else if( ci_tcp_validate_sa(s->domain, serv_addr, addrlen) ) { /* Request should be forwarded to OS */ rc = CI_SOCKET_HANDOVER; goto unlock_out; } if( serv_addr->sa_family == AF_UNSPEC ) { /* Linux does listen shutdown on disconnect (AF_UNSPEC) */ ci_netif_unlock(ep->netif); rc = ci_tcp_shutdown(ep, SHUT_RD, fd); goto out; } else { /* Linux has curious error reporting in this case */ CI_SET_ERROR(rc, EISCONN); } #endif } else { /* Socket is in SYN-SENT state. Let's block for receiving SYN-ACK */ ci_assert_equal(s->b.state, CI_TCP_SYN_SENT); if( s->b.sb_aflags & (CI_SB_AFLAG_O_NONBLOCK | CI_SB_AFLAG_O_NDELAY) ) CI_SET_ERROR(rc, EALREADY); else goto syn_sent; } goto unlock_out; } /* Check if we've ever been connected. */ if( ts->tcpflags & CI_TCPT_FLAG_WAS_ESTAB ) { CI_SET_ERROR(rc, EISCONN); goto unlock_out; } /* * 2. Check address parameter, if it's inappropriate for handover * decision or handover should be done, try to to call OS and * do handover on success. */ if ( /* Af first, check that address family and length is OK. */ ci_tcp_validate_sa(s->domain, serv_addr, addrlen) /* rfc793 p54 if the foreign socket is unspecified return */ /* "error: foreign socket unspecified" (EINVAL), but keep it to OS */ || (dst_be32 = ci_get_ip4_addr(inaddr->sin_family, serv_addr)) == 0 /* Zero destination port is tricky as well, keep it to OS */ || inaddr->sin_port == 0 ) { rc = CI_SOCKET_HANDOVER; goto unlock_out; } /* is this a socket that we can handle? */ rc = ci_tcp_connect_check_dest(ep, dst_be32, inaddr->sin_port); if( rc ) goto unlock_out; if( (ts->s.pkt.flags & CI_IP_CACHE_IS_LOCALROUTE) && OO_SP_IS_NULL(ts->local_peer) ) { /* Try to connect to another stack; handover if can't */ struct oo_op_loopback_connect op; op.dst_port = inaddr->sin_port; op.dst_addr = dst_be32; /* this operation unlocks netif */ rc = oo_resource_op(fd, OO_IOC_TCP_LOOPBACK_CONNECT, &op); if( rc < 0) return CI_SOCKET_HANDOVER; if( op.out_moved ) *p_moved = 1; if( op.out_rc == -EINPROGRESS ) RET_WITH_ERRNO( EINPROGRESS ); else if( op.out_rc == -EAGAIN ) return -EAGAIN; else if( op.out_rc != 0 ) return CI_SOCKET_HANDOVER; return 0; } /* filters can't handle alien source address */ if( (s->s_flags & CI_SOCK_FLAG_BOUND_ALIEN) && ! (ts->s.pkt.flags & CI_IP_CACHE_IS_LOCALROUTE) ) { rc = CI_SOCKET_HANDOVER; goto unlock_out; } crc = ci_tcp_connect_ul_start(ep->netif, ts, dst_be32, inaddr->sin_port, &rc); if( crc != CI_CONNECT_UL_OK ) { switch( crc ) { case CI_CONNECT_UL_FAIL: goto unlock_out; case CI_CONNECT_UL_LOCK_DROPPED: goto out; case CI_CONNECT_UL_START_AGAIN: goto start_again; } } CI_TCP_STATS_INC_ACTIVE_OPENS( ep->netif ); syn_sent: rc = ci_tcp_connect_ul_syn_sent(ep->netif, ts); unlock_out: ci_netif_unlock(ep->netif); out: return rc; }