/* * Wait for a DCCP event. * * Note that we don't need to lock the socket, as the upper poll layers * take care of normal races (between the test and the event) and we don't * go look at any of the socket buffers directly. */ static unsigned int dccp_poll(struct file *file, struct socket *sock, poll_table *wait) { unsigned int mask; struct sock *sk = sock->sk; poll_wait(file, sk->sk_sleep, wait); if (sk->sk_state == DCCP_LISTEN) return inet_csk_listen_poll(sk); /* Socket is not locked. We are protected from async events by poll logic and correct handling of state changes made by another threads is impossible in any case. */ mask = 0; if (sk->sk_err) mask = POLLERR; if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED) mask |= POLLHUP; if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLIN | POLLRDNORM; /* Connected? */ if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) { if (atomic_read(&sk->sk_rmem_alloc) > 0) mask |= POLLIN | POLLRDNORM; if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { mask |= POLLOUT | POLLWRNORM; } else { /* send SIGIO later */ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); /* Race breaker. If space is freed after * wspace test but before the flags are set, * IO signal will be lost. */ if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) mask |= POLLOUT | POLLWRNORM; } } } return mask; }
unsigned int dccp_poll(struct file *file, struct socket *sock, poll_table *wait) { unsigned int mask; struct sock *sk = sock->sk; sock_poll_wait(file, sk->sk_sleep, wait); if (sk->sk_state == DCCP_LISTEN) return inet_csk_listen_poll(sk); mask = 0; if (sk->sk_err) mask = POLLERR; if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED) mask |= POLLHUP; if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLIN | POLLRDNORM | POLLRDHUP; if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) { if (atomic_read(&sk->sk_rmem_alloc) > 0) mask |= POLLIN | POLLRDNORM; if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { mask |= POLLOUT | POLLWRNORM; } else { set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) mask |= POLLOUT | POLLWRNORM; } } } return mask; }
/* * Any space to write? */ static inline unsigned long svc_sock_wspace(struct svc_sock *svsk) { int wspace; if (svsk->sk_sock->type == SOCK_STREAM) wspace = sk_stream_wspace(svsk->sk_sk); else wspace = sock_wspace(svsk->sk_sk); return wspace; }
/** * sk_stream_write_space - stream socket write_space callback. * @sk: socket * * FIXME: write proper description */ void sk_stream_write_space(struct sock *sk) { struct socket *sock = sk->sk_socket; if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) { clear_bit(SOCK_NOSPACE, &sock->flags); if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); } }
static void ksocknal_write_space(struct sock *sk) { struct ksock_conn *conn; int wspace; int min_wpace; /* interleave correctly with closing sockets... */ LASSERT(!in_irq()); read_lock(&ksocknal_data.ksnd_global_lock); conn = sk->sk_user_data; wspace = sk_stream_wspace(sk); min_wpace = sk_stream_min_wspace(sk); CDEBUG(D_NET, "sk %p wspace %d low water %d conn %p%s%s%s\n", sk, wspace, min_wpace, conn, !conn ? "" : (conn->ksnc_tx_ready ? " ready" : " blocked"), !conn ? "" : (conn->ksnc_tx_scheduled ? " scheduled" : " idle"), !conn ? "" : (list_empty(&conn->ksnc_tx_queue) ? " empty" : " queued")); if (!conn) { /* raced with ksocknal_terminate_conn */ LASSERT(sk->sk_write_space != &ksocknal_write_space); sk->sk_write_space(sk); read_unlock(&ksocknal_data.ksnd_global_lock); return; } if (wspace >= min_wpace) { /* got enough space */ ksocknal_write_callback(conn); /* * Clear SOCK_NOSPACE _after_ ksocknal_write_callback so the * ENOMEM check in ksocknal_transmit is race-free (think about * it). */ clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags); } read_unlock(&ksocknal_data.ksnd_global_lock); }
void sk_stream_write_space(struct sock *sk) { struct socket *sock = sk->sk_socket; struct socket_wq *wq; if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) { clear_bit(SOCK_NOSPACE, &sock->flags); rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); if (wq_has_sleeper(wq)) wake_up_interruptible_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT); rcu_read_unlock(); } }
/** * xs_tcp_write_space - callback invoked when socket buffer space * becomes available * @sk: socket whose state has changed * * Called when more output buffer space is available for this socket. * We try not to wake our writers until they can make "significant" * progress, otherwise we'll waste resources thrashing kernel_sendmsg * with a bunch of small requests. */ static void xs_tcp_write_space(struct sock *sk) { read_lock(&sk->sk_callback_lock); /* from net/core/stream.c:sk_stream_write_space */ if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) { struct socket *sock; struct rpc_xprt *xprt; if (unlikely(!(sock = sk->sk_socket))) goto out; if (unlikely(!(xprt = xprt_from_sock(sk)))) goto out; if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))) goto out; xprt_write_space(xprt); } out: read_unlock(&sk->sk_callback_lock); }
/* * This function may be called to estimate amount of data can be sent . * Paramters: a pointer to socket structure * Returns: number of bytes the application can send * */ int app_glue_calc_size_of_data_to_send(void *sock) { int bufs_count1,bufs_count2,bufs_count3,stream_space,bufs_min; struct sock *sk = ((struct socket *)sock)->sk; if(!sk_stream_is_writeable(sk)) { return 0; } bufs_count1 = kmem_cache_get_free(get_fclone_cache()); bufs_count2 = kmem_cache_get_free(get_header_cache()); bufs_count3 = get_buffer_count(); if(bufs_count1 > 2) { bufs_count1 -= 2; } if(bufs_count2 > 2) { bufs_count2 -= 2; } bufs_min = min(bufs_count1,bufs_count2); bufs_min = min(bufs_min,bufs_count3); if(bufs_min <= 0) { return 0; } stream_space = sk_stream_wspace(((struct socket *)sock)->sk); return min(bufs_min << 10,stream_space); }
void ipaugenblick_main_loop() { struct rte_mbuf *mbuf; uint8_t ports_to_poll[1] = { 0 }; int drv_poll_interval = get_max_drv_poll_interval_in_micros(0); app_glue_init_poll_intervals(drv_poll_interval/(2*MAX_PKT_BURST), 100 /*timer_poll_interval*/, drv_poll_interval/(10*MAX_PKT_BURST), drv_poll_interval/(60*MAX_PKT_BURST)); ipaugenblick_service_api_init(COMMAND_POOL_SIZE,DATA_RINGS_SIZE,DATA_RINGS_SIZE); TAILQ_INIT(&buffers_available_notification_socket_list_head); TAILQ_INIT(&ipaugenblick_clients_list_head); init_systick(rte_lcore_id()); ipaugenblick_log(IPAUGENBLICK_LOG_INFO,"IPAugenblick service initialized\n"); while(1) { process_commands(); app_glue_periodic(1,ports_to_poll,1); while(!TAILQ_EMPTY(&buffers_available_notification_socket_list_head)) { if(get_buffer_count() > 0) { struct socket *sock = TAILQ_FIRST(&buffers_available_notification_socket_list_head); socket_satelite_data_t *socket_data = get_user_data(sock); if(socket_data->socket->type == SOCK_DGRAM) user_set_socket_tx_space(&g_ipaugenblick_sockets[socket_data->ringset_idx].tx_space,sk_stream_wspace(socket_data->socket->sk)); //printf("%s %d %d %d %d\n",__FILE__,__LINE__,socket_data->ringset_idx,g_ipaugenblick_sockets[socket_data->ringset_idx].tx_space,sk_stream_wspace(socket_data->socket->sk)); if(!ipaugenblick_mark_writable(socket_data)) { sock->buffers_available_notification_queue_present = 0; TAILQ_REMOVE(&buffers_available_notification_socket_list_head,sock,buffers_available_notification_queue_entry); } else { break; } } else { break; } } } }
static inline void process_commands() { int ringset_idx; ipaugenblick_cmd_t *cmd; struct rte_mbuf *mbuf; struct socket *sock; char *p; struct sockaddr_in addr; struct sockaddr_in *p_sockaddr; struct rtentry rtentry; int len; cmd = ipaugenblick_dequeue_command_buf(); if(!cmd) return; switch(cmd->cmd) { case IPAUGENBLICK_OPEN_SOCKET_COMMAND: ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"open_sock %x %x %x %x\n",cmd->u.open_sock.family,cmd->u.open_sock.type); sock = app_glue_create_socket(cmd->u.open_sock.family,cmd->u.open_sock.type); if(sock) { ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"setting user data %p\n",sock); socket_satelite_data[cmd->ringset_idx].ringset_idx = cmd->ringset_idx; socket_satelite_data[cmd->ringset_idx].parent_idx = cmd->parent_idx; socket_satelite_data[cmd->ringset_idx].apppid = cmd->u.open_sock.pid; app_glue_set_user_data(sock,(void *)&socket_satelite_data[cmd->ringset_idx]); socket_satelite_data[cmd->ringset_idx].socket = sock; ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"%d setting tx_space %d\n",__LINE__,sk_stream_wspace(sock->sk)); user_set_socket_tx_space(&g_ipaugenblick_sockets[socket_satelite_data[cmd->ringset_idx].ringset_idx].tx_space,sk_stream_wspace(sock->sk)); } ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"Done\n"); break; case IPAUGENBLICK_SOCKET_CONNECT_BIND_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { if(cmd->u.socket_connect_bind.is_connect) { ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"connect %x\n",cmd->ringset_idx); if(app_glue_v4_connect(socket_satelite_data[cmd->ringset_idx].socket, cmd->u.socket_connect_bind.ipaddr, cmd->u.socket_connect_bind.port)) { ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"failed to connect socket\n"); } else { ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"socket connected\n"); len = sizeof(addr); inet_getname(socket_satelite_data[cmd->ringset_idx].socket,&addr,&len,0); g_ipaugenblick_sockets[cmd->ringset_idx].local_ipaddr = addr.sin_addr.s_addr; g_ipaugenblick_sockets[cmd->ringset_idx].local_port = addr.sin_port; } } else { ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"bind %x\n",cmd->ringset_idx); if(app_glue_v4_bind(socket_satelite_data[cmd->ringset_idx].socket, cmd->u.socket_connect_bind.ipaddr, cmd->u.socket_connect_bind.port)) { ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"cannot bind %x %x\n",cmd->u.socket_connect_bind.ipaddr,cmd->u.socket_connect_bind.port); } } } else { ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"no socket to invoke command!!!\n"); } break; case IPAUGENBLICK_LISTEN_SOCKET_COMMAND: ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"listen %x\n",cmd->ringset_idx); if(app_glue_v4_listen(socket_satelite_data[cmd->ringset_idx].socket)) { ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"failed listening\n"); } break; case IPAUGENBLICK_SOCKET_CLOSE_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { // ipaugenblick_log(IPAUGENBLICK_LOG_INFO,"closing socket %d %p\n",cmd->ringset_idx,socket_satelite_data[cmd->ringset_idx].socket); // printf("%s %d %p\n",__FILE__,__LINE__,socket_satelite_data[cmd->ringset_idx].socket); // user_on_transmission_opportunity(socket_satelite_data[cmd->ringset_idx].socket); user_flush_rx_tx((struct socket *)socket_satelite_data[cmd->ringset_idx].socket); app_glue_close_socket((struct socket *)socket_satelite_data[cmd->ringset_idx].socket); socket_satelite_data[cmd->ringset_idx].socket = NULL; socket_satelite_data[cmd->ringset_idx].ringset_idx = -1; socket_satelite_data[cmd->ringset_idx].parent_idx = -1; ipaugenblick_free_socket(cmd->ringset_idx); user_sockets_closed++; } break; case IPAUGENBLICK_SOCKET_TX_KICK_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { user_kick_tx++; // user_data_available_cbk(socket_satelite_data[cmd->ringset_idx].socket); user_on_transmission_opportunity(socket_satelite_data[cmd->ringset_idx].socket); } break; case IPAUGENBLICK_SOCKET_RX_KICK_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { user_kick_rx++; user_data_available_cbk(socket_satelite_data[cmd->ringset_idx].socket); // user_on_transmission_opportunity(socket_satelite_data[cmd->ringset_idx].socket); } break; case IPAUGENBLICK_SET_SOCKET_RING_COMMAND: //ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"%s %d %d %d %p\n",__FILE__,__LINE__,cmd->ringset_idx,cmd->parent_idx,cmd->u.set_socket_ring.socket_descr); socket_satelite_data[cmd->ringset_idx].ringset_idx = cmd->ringset_idx; if(cmd->parent_idx != -1) socket_satelite_data[cmd->ringset_idx].parent_idx = cmd->parent_idx; socket_satelite_data[cmd->ringset_idx].apppid = cmd->u.set_socket_ring.pid; app_glue_set_user_data(cmd->u.set_socket_ring.socket_descr,&socket_satelite_data[cmd->ringset_idx]); socket_satelite_data[cmd->ringset_idx].socket = cmd->u.set_socket_ring.socket_descr; //ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"setting tx space: %d connidx %d\n",sk_stream_wspace(socket_satelite_data[cmd->ringset_idx].socket->sk),g_ipaugenblick_sockets[socket_satelite_data[cmd->ringset_idx].ringset_idx].connection_idx); user_set_socket_tx_space(&g_ipaugenblick_sockets[socket_satelite_data[cmd->ringset_idx].ringset_idx].tx_space,sk_stream_wspace(socket_satelite_data[cmd->ringset_idx].socket->sk)); // user_on_transmission_opportunity(socket_satelite_data[cmd->ringset_idx].socket); user_data_available_cbk(socket_satelite_data[cmd->ringset_idx].socket); ipaugenblick_mark_writable(&socket_satelite_data[cmd->ringset_idx]); ipaugenblick_mark_readable(&socket_satelite_data[cmd->ringset_idx]); user_client_app_accepted++; break; case IPAUGENBLICK_SET_SOCKET_SELECT_COMMAND: // ipaugenblick_log(IPAUGENBLICK_LOG_DEBUG,"setting selector %d for socket %d\n",cmd->u.set_socket_select.socket_select,cmd->ringset_idx); socket_satelite_data[cmd->ringset_idx].parent_idx = cmd->u.set_socket_select.socket_select; socket_satelite_data[cmd->ringset_idx].apppid = cmd->u.set_socket_select.pid; user_data_available_cbk(socket_satelite_data[cmd->ringset_idx].socket); ipaugenblick_mark_writable(&socket_satelite_data[cmd->ringset_idx]); ipaugenblick_mark_readable(&socket_satelite_data[cmd->ringset_idx]); break; case IPAUGENBLICK_SOCKET_TX_POOL_EMPTY_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { if(!socket_satelite_data[cmd->ringset_idx].socket->buffers_available_notification_queue_present) { TAILQ_INSERT_TAIL(&buffers_available_notification_socket_list_head,socket_satelite_data[cmd->ringset_idx].socket,buffers_available_notification_queue_entry); socket_satelite_data[cmd->ringset_idx].socket->buffers_available_notification_queue_present = 1; if(socket_satelite_data[cmd->ringset_idx].socket->type == SOCK_DGRAM) user_set_socket_tx_space(&g_ipaugenblick_sockets[socket_satelite_data[cmd->ringset_idx].ringset_idx].tx_space,sk_stream_wspace(socket_satelite_data[cmd->ringset_idx].socket->sk)); } } break; case IPAUGENBLICK_ROUTE_ADD_COMMAND: memset((void *)&rtentry,0,sizeof(rtentry)); rtentry.rt_metric = cmd->u.route.metric; rtentry.rt_flags = RTF_UP|RTF_GATEWAY; p_sockaddr = (struct sockaddr_in *)&rtentry.rt_dst; p_sockaddr->sin_family = AF_INET; p_sockaddr->sin_addr.s_addr = cmd->u.route.dest_ipaddr; p_sockaddr = (struct sockaddr_in *)&rtentry.rt_gateway; p_sockaddr->sin_family = AF_INET; p_sockaddr->sin_addr.s_addr = cmd->u.route.next_hop; p_sockaddr = (struct sockaddr_in *)&rtentry.rt_genmask; p_sockaddr->sin_family = AF_INET; p_sockaddr->sin_addr.s_addr = cmd->u.route.dest_mask; if(ip_rt_ioctl(&init_net,SIOCADDRT,&rtentry)) { ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"CANNOT ADD ROUTE ENTRY %x %x %x\n", ((struct sockaddr_in *)&rtentry.rt_dst)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_addr.s_addr); } else { ipaugenblick_log(IPAUGENBLICK_LOG_INFO,"ROUTE ENTRY %x %x %x is added\n", ((struct sockaddr_in *)&rtentry.rt_dst)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_addr.s_addr); } break; case IPAUGENBLICK_ROUTE_DEL_COMMAND: memset((void *)&rtentry,0,sizeof(rtentry)); p_sockaddr = (struct sockaddr_in *)&rtentry.rt_dst; p_sockaddr->sin_family = AF_INET; p_sockaddr->sin_addr.s_addr = cmd->u.route.dest_ipaddr; p_sockaddr = (struct sockaddr_in *)&rtentry.rt_gateway; p_sockaddr->sin_family = AF_INET; p_sockaddr->sin_addr.s_addr = cmd->u.route.next_hop; p_sockaddr = (struct sockaddr_in *)&rtentry.rt_genmask; p_sockaddr->sin_family = AF_INET; p_sockaddr->sin_addr.s_addr = cmd->u.route.dest_mask; if(ip_rt_ioctl(&init_net,SIOCDELRT,&rtentry)) { ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"CANNOT DELETE ROUTE ENTRY %x %x %x\n", ((struct sockaddr_in *)&rtentry.rt_dst)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_addr.s_addr); } else { ipaugenblick_log(IPAUGENBLICK_LOG_INFO,"ROUTE ENTRY %x %x %x is deleted\n", ((struct sockaddr_in *)&rtentry.rt_dst)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_addr.s_addr, ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_addr.s_addr); } break; case IPAUGENBLICK_CONNECT_CLIENT: if(cmd->ringset_idx >= IPAUGENBLICK_CLIENTS_POOL_SIZE) { break; } if(!ipaugenblick_clients[cmd->ringset_idx].is_busy) { TAILQ_INSERT_TAIL(&ipaugenblick_clients_list_head,&ipaugenblick_clients[cmd->ringset_idx],queue_entry); ipaugenblick_clients[cmd->ringset_idx].is_busy = 1; on_client_connect(cmd->ringset_idx); } break; case IPAUGENBLICK_DISCONNECT_CLIENT: if(cmd->ringset_idx >= IPAUGENBLICK_CLIENTS_POOL_SIZE) { break; } if(ipaugenblick_clients[cmd->ringset_idx].is_busy) { TAILQ_REMOVE(&ipaugenblick_clients_list_head,&ipaugenblick_clients[cmd->ringset_idx],queue_entry); ipaugenblick_clients[cmd->ringset_idx].is_busy = 0; } break; case IPAUGENBLICK_SETSOCKOPT_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { sock_setsockopt(socket_satelite_data[cmd->ringset_idx].socket, cmd->u.setsockopt.level, cmd->u.setsockopt.optname, cmd->u.setsockopt.optval, cmd->u.setsockopt.optlen); } break; case IPAUGENBLICK_SOCKET_SHUTDOWN_COMMAND: if(socket_satelite_data[cmd->ringset_idx].socket) { inet_shutdown(socket_satelite_data[cmd->ringset_idx].socket, cmd->u.socket_shutdown.how); user_sockets_shutdown++; } break; case IPAUGENBLICK_SOCKET_DECLINE_COMMAND: user_flush_rx_tx((struct socket *)cmd->u.socket_decline.socket_descr); app_glue_close_socket((struct socket *)cmd->u.socket_decline.socket_descr); user_sockets_closed++; break; default: ipaugenblick_log(IPAUGENBLICK_LOG_ERR,"unknown cmd %d\n",cmd->cmd); break; } ipaugenblick_free_command_buf(cmd); }