f-stack/adapter/ff_socket_ops.c

469 lines
11 KiB
C

#include <rte_memcpy.h>
#include <rte_spinlock.h>
#include "ff_socket_ops.h"
#include "ff_sysproto.h"
#include "ff_api.h"
#include "ff_epoll.h"
#undef FF_SYSCALL_DECL
#define FF_SYSCALL_DECL(ret, fn, none) \
static ret ff_sys_##fn(struct ff_##fn##_args *args);
#include <ff_declare_syscalls.h>
static int ff_sys_kqueue(struct ff_kqueue_args *args);
static int ff_sys_kevent(struct ff_kevent_args *args);
#define FF_MAX_BOUND_NUM 8
struct ff_bound_info {
int fd;
struct sockaddr addr;
};
static struct ff_bound_info ff_bound_fds[FF_MAX_BOUND_NUM];
static int
sockaddr_cmp(struct sockaddr *a, struct sockaddr *b)
{
struct sockaddr_in *sina, *sinb;
sina = (struct sockaddr_in *)a;
sinb = (struct sockaddr_in *)b;
if (sina->sin_family != sinb->sin_family) {
return 1;
}
if (sina->sin_port != sinb->sin_port) {
return 1;
}
if (sina->sin_addr.s_addr != sinb->sin_addr.s_addr) {
return 1;
}
return 0;
}
static int
sockaddr_is_bound(struct sockaddr *addr)
{
int i;
for (i = 0; i < FF_MAX_BOUND_NUM; i++) {
struct ff_bound_info *info = &ff_bound_fds[i];
if (info->fd == 0) {
continue;
}
if (sockaddr_cmp(&info->addr, addr) == 0) {
return info->fd;
}
}
return 0;
}
static int
sockaddr_bind(int fd, struct sockaddr *addr)
{
int i;
for (i = 0; i < FF_MAX_BOUND_NUM; i++) {
struct ff_bound_info *info = &ff_bound_fds[i];
if (info->fd != 0) {
continue;
}
info->fd = fd;
rte_memcpy(&info->addr, addr, sizeof(struct sockaddr));
return 0;
}
return -1;
}
static int
sockaddr_unbind(int fd)
{
int i;
for (i = 0; i < FF_MAX_BOUND_NUM; i++) {
struct ff_bound_info *info = &ff_bound_fds[i];
if (info->fd != fd) {
continue;
}
info->fd = 0;
return 0;
}
return -1;
}
static int
ff_sys_socket(struct ff_socket_args *args)
{
return ff_socket(args->domain, args->type, args->protocol);
}
static int
ff_sys_bind(struct ff_bind_args *args)
{
int bound_fd;
int ret;
bound_fd = sockaddr_is_bound(args->addr);
if (bound_fd != 0 && bound_fd != args->fd) {
return ff_dup2(bound_fd, args->fd);
}
ret = ff_bind(args->fd, args->addr, args->addrlen);
if (ret == 0) {
sockaddr_bind(args->fd, args->addr);
}
return ret;
}
static int
ff_sys_listen(struct ff_listen_args *args)
{
return ff_listen(args->fd, args->backlog);
}
static int
ff_sys_shutdown(struct ff_shutdown_args *args)
{
return ff_shutdown(args->fd, args->how);
}
static int
ff_sys_getsockname(struct ff_getsockname_args *args)
{
return ff_getsockname(args->fd, args->name, args->namelen);
}
static int
ff_sys_getpeername(struct ff_getpeername_args *args)
{
return ff_getpeername(args->fd, args->name, args->namelen);
}
static int
ff_sys_getsockopt(struct ff_getsockopt_args *args)
{
return ff_getsockopt(args->fd, args->level, args->name,
args->optval, args->optlen);
}
static int
ff_sys_setsockopt(struct ff_setsockopt_args *args)
{
return ff_setsockopt(args->fd, args->level, args->name,
args->optval, args->optlen);
}
static int
ff_sys_accept(struct ff_accept_args *args)
{
return ff_accept(args->fd, args->addr, args->addrlen);
}
static int
ff_sys_accept4(struct ff_accept4_args *args)
{
errno = ENOSYS;
return -1;
}
static int
ff_sys_connect(struct ff_connect_args *args)
{
return ff_connect(args->fd, args->addr, args->addrlen);
}
static ssize_t
ff_sys_recv(struct ff_recv_args *args)
{
return ff_recv(args->fd, args->buf, args->len, args->flags);
}
static ssize_t
ff_sys_recvfrom(struct ff_recvfrom_args *args)
{
return ff_recvfrom(args->fd, args->buf, args->len, args->flags,
args->from, args->fromlen);
}
static ssize_t
ff_sys_recvmsg(struct ff_recvmsg_args *args)
{
return ff_recvmsg(args->fd, args->msg, args->flags);
}
static ssize_t
ff_sys_read(struct ff_read_args *args)
{
return ff_read(args->fd, args->buf, args->len);
}
static ssize_t
ff_sys_readv(struct ff_readv_args *args)
{
return ff_readv(args->fd, args->iov, args->iovcnt);
}
static ssize_t
ff_sys_send(struct ff_send_args *args)
{
return ff_send(args->fd, args->buf, args->len, args->flags);
}
static ssize_t
ff_sys_sendto(struct ff_sendto_args *args)
{
return ff_sendto(args->fd, args->buf, args->len, args->flags,
args->to, args->tolen);
}
static ssize_t
ff_sys_sendmsg(struct ff_sendmsg_args *args)
{
return ff_sendmsg(args->fd, args->msg, args->flags);
}
static ssize_t
ff_sys_write(struct ff_write_args *args)
{
return ff_write(args->fd, args->buf, args->len);
}
static ssize_t
ff_sys_writev(struct ff_writev_args *args)
{
return ff_writev(args->fd, args->iov, args->iovcnt);
}
static int
ff_sys_close(struct ff_close_args *args)
{
sockaddr_unbind(args->fd);
return ff_close(args->fd);
}
static int
ff_sys_ioctl(struct ff_ioctl_args *args)
{
return ff_ioctl(args->fd, args->com, args->data);
}
static int
ff_sys_fcntl(struct ff_fcntl_args *args)
{
return ff_fcntl(args->fd, args->cmd, args->data);
}
static int
ff_sys_epoll_create(struct ff_epoll_create_args *args)
{
DEBUG_LOG("to run ff_epoll_create, size:%d\n", args->size);
return ff_epoll_create(args->size);
}
static int
ff_sys_epoll_ctl(struct ff_epoll_ctl_args *args)
{
DEBUG_LOG("to run ff_epoll_ctl, epfd:%d, op:%d, fd:%d\n",
args->epfd, args->op, args->fd);
return ff_epoll_ctl(args->epfd, args->op, args->fd,
args->event);
}
static int
ff_sys_epoll_wait(struct ff_epoll_wait_args *args)
{
DEBUG_LOG("to run ff_epoll_wait, epfd:%d, maxevents:%d, timeout:%d\n",
args->epfd, args->maxevents, args->timeout);
return ff_epoll_wait(args->epfd, args->events,
args->maxevents, args->timeout);
}
static int
ff_sys_kqueue(struct ff_kqueue_args *args)
{
return ff_kqueue();
}
static int
ff_sys_kevent(struct ff_kevent_args *args)
{
return ff_kevent(args->kq, args->changelist, args->nchanges,
args->eventlist, args->nevents, args->timeout);
}
static pid_t
ff_sys_fork(struct ff_fork_args *args)
{
errno = ENOSYS;
return -1;
}
static int
ff_so_handler(int ops, void *args)
{
DEBUG_LOG("ff_so_handler ops:%d, epoll create ops:%d\n", ops, FF_SO_EPOLL_CREATE);
switch(ops) {
case FF_SO_SOCKET:
return ff_sys_socket((struct ff_socket_args *)args);
case FF_SO_BIND:
return ff_sys_bind((struct ff_bind_args *)args);
case FF_SO_LISTEN:
return ff_sys_listen((struct ff_listen_args *)args);
case FF_SO_CONNECT:
return ff_sys_connect((struct ff_connect_args *)args);
case FF_SO_SHUTDOWN:
return ff_sys_shutdown((struct ff_shutdown_args *)args);
case FF_SO_GETSOCKNAME:
return ff_sys_getsockname((struct ff_getsockname_args *)args);
case FF_SO_GETPEERNAME:
return ff_sys_getpeername((struct ff_getpeername_args *)args);
case FF_SO_GETSOCKOPT:
return ff_sys_getsockopt((struct ff_getsockopt_args *)args);
case FF_SO_SETSOCKOPT:
return ff_sys_setsockopt((struct ff_setsockopt_args *)args);
case FF_SO_ACCEPT:
return ff_sys_accept((struct ff_accept_args *)args);
case FF_SO_ACCEPT4:
return ff_sys_accept4((struct ff_accept4_args *)args);
case FF_SO_RECV:
return ff_sys_recv((struct ff_recv_args *)args);
case FF_SO_RECVFROM:
return ff_sys_recvfrom((struct ff_recvfrom_args *)args);
case FF_SO_RECVMSG:
return ff_sys_recvmsg((struct ff_recvmsg_args *)args);
case FF_SO_READ:
return ff_sys_read((struct ff_read_args *)args);
case FF_SO_READV:
return ff_sys_readv((struct ff_readv_args *)args);
case FF_SO_SEND:
return ff_sys_send((struct ff_send_args *)args);
case FF_SO_SENDTO:
return ff_sys_sendto((struct ff_sendto_args *)args);
case FF_SO_SENDMSG:
return ff_sys_sendmsg((struct ff_sendmsg_args *)args);
case FF_SO_WRITE:
return ff_sys_write((struct ff_write_args *)args);
case FF_SO_WRITEV:
return ff_sys_writev((struct ff_writev_args *)args);
case FF_SO_CLOSE:
return ff_sys_close((struct ff_close_args *)args);
case FF_SO_IOCTL:
return ff_sys_ioctl((struct ff_ioctl_args *)args);
case FF_SO_FCNTL:
return ff_sys_fcntl((struct ff_fcntl_args *)args);
case FF_SO_EPOLL_CREATE:
return ff_sys_epoll_create((struct ff_epoll_create_args *)args);
case FF_SO_EPOLL_CTL:
return ff_sys_epoll_ctl((struct ff_epoll_ctl_args *)args);
case FF_SO_EPOLL_WAIT:
return ff_sys_epoll_wait((struct ff_epoll_wait_args *)args);
case FF_SO_KQUEUE:
return ff_sys_kqueue((struct ff_kqueue_args *)args);
case FF_SO_KEVENT:
return ff_sys_kevent((struct ff_kevent_args *)args);
case FF_SO_FORK:
return ff_sys_fork((struct ff_fork_args *)args);
default:
break;
}
errno = EINVAL;
return (-1);
}
static void
ff_handle_kevent(struct ff_so_context *sc)
{
struct ff_kevent_args *ka = sc->args;
errno = 0;
sc->result = ff_sys_kevent(ka);
sc->error = errno;
if (ka->nchanges) {
ka->nchanges = 0;
}
if (sc->result == 0 && ka->nevents != 0) {
return;
}
sc->status = FF_SC_REP;
sem_post(&sc->wait_sem);
}
static inline void
ff_handle_socket_ops(struct ff_so_context *sc)
{
if (!rte_spinlock_trylock(&sc->lock)) {
return;
}
if (sc->status != FF_SC_REQ) {
rte_spinlock_unlock(&sc->lock);
return;
}
DEBUG_LOG("ff_handle_socket_ops sc:%p, status:%d, ops:%d\n", sc, sc->status, sc->ops);
if (sc->ops == FF_SO_KEVENT) {
ff_handle_kevent(sc);
rte_spinlock_unlock(&sc->lock);
return;
}
errno = 0;
sc->result = ff_so_handler(sc->ops, sc->args);
sc->error = errno;
sc->status = FF_SC_REP;
if (sc->ops == FF_SO_EPOLL_WAIT) {
sem_post(&sc->wait_sem);
}
rte_spinlock_unlock(&sc->lock);
}
void
ff_handle_each_context()
{
uint16_t i, nb_handled;
rte_spinlock_lock(&ff_so_zone->lock);
assert(ff_so_zone->count >= ff_so_zone->free);
nb_handled = ff_so_zone->count - ff_so_zone->free;
if (nb_handled) {
for (i = 0; i < ff_so_zone->count; i++) {
struct ff_so_context *sc = &ff_so_zone->sc[i];
if (sc->inuse == 0) {
continue;
}
ff_handle_socket_ops(sc);
nb_handled--;
if (!nb_handled) {
break;
}
}
}
rte_spinlock_unlock(&ff_so_zone->lock);
}