summaryrefslogtreecommitdiff
path: root/accel-dp/ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-dp/ctrl.c')
-rw-r--r--accel-dp/ctrl.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/accel-dp/ctrl.c b/accel-dp/ctrl.c
new file mode 100644
index 0000000..b816d82
--- /dev/null
+++ b/accel-dp/ctrl.c
@@ -0,0 +1,347 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <rte_malloc.h>
+
+#include "init.h"
+#include "common.h"
+#include "conf_file.h"
+#include "event.h"
+#include "sock.h"
+
+#include "if_dp.h"
+
+struct protosw {
+ struct list_head entry;
+ int domain;
+ int type;
+ int proto;
+ const struct proto_ops *ops;
+};
+
+static struct event_handler ctrl_hnd;
+
+static LIST_HEAD(proto_list);
+
+void sock_register_proto(int domain, int type, int proto, const struct proto_ops *ops)
+{
+ struct list_head *pos = proto_list.next;
+ struct protosw *p;
+
+ while (pos != &proto_list) {
+ p = list_entry(pos, typeof(*p), entry);
+ if (p->domain == domain && type && !p->type)
+ break;
+ pos = pos->next;
+ }
+
+ p = malloc(sizeof(*p));
+ p->domain = domain;
+ p->type = type;
+ p->proto = proto;
+
+ list_add_tail(&p->entry, pos);
+}
+
+static int sock_send_errno(int fd, int err)
+{
+ struct msg_result msg = {
+ .err = err,
+ .len = 0,
+ .addrlen = 0,
+ };
+
+ return write(fd, &msg, sizeof(msg)) != sizeof(msg);
+}
+
+int sock_errno(struct sock *sk, int err)
+{
+ sk->res->err = 0;
+ sk->res->len = 0;
+ sk->res->addrlen = 0;
+ return sizeof(*sk->res);
+}
+
+static int msg_socket(struct sock *sk, void *buf, int size)
+{
+ struct msg_socket *msg = (struct msg_socket *)buf;
+ struct protosw *p;
+ int dom = 0;
+
+ list_for_each_entry(p, &proto_list, entry) {
+ if (p->domain != msg->domain)
+ continue;
+
+ dom = 1;
+
+ if (p->type && p->type != msg->type)
+ continue;
+
+ if (p->proto && p->proto != msg->proto)
+ continue;
+
+ sk->ops = p->ops;
+
+ break;
+ }
+
+ if (!sk->ops) {
+ sock_send_errno(sk->hnd.fd, dom ? EPROTONOSUPPORT : EAFNOSUPPORT);
+ return -1;
+ }
+
+ return sk->ops->socket(sk, msg->type, msg->proto);
+}
+
+static int msg_connect(struct sock *sk, void *buf, int size)
+{
+ struct msg_connect *msg = (struct msg_connect *)buf;
+
+ assert(sk->ops);
+ /*if (unlikely(!sk->ops)) {
+ sock_send_errno(sk->hnd.fd, ENOTSOCK);
+ return -1;
+ }*/
+
+ return sk->ops->connect(sk, (struct sockaddr *)msg->addr, msg->addrlen);
+}
+
+static int msg_bind(struct sock *sk, void *buf, int size)
+{
+ struct msg_bind *msg = (struct msg_bind *)buf;
+
+ assert(sk->ops);
+ /*if (unlikely(!sk->ops)) {
+ sock_send_errno(sk->hnd.fd, ENOTSOCK);
+ return -1;
+ }*/
+
+ return sk->ops->bind(sk, (struct sockaddr *)msg->addr, msg->addrlen);
+}
+
+static int msg_listen(struct sock *sk, void *buf, int size)
+{
+ struct msg_listen *msg = (struct msg_listen *)buf;
+
+ assert(sk->ops);
+ /*if (unlikely(!sk->ops)) {
+ sock_send_errno(sk->hnd.fd, ENOTSOCK);
+ return -1;
+ }*/
+
+ return sk->ops->listen(sk, msg->backlog);
+}
+
+static int msg_recv(struct sock *sk, void *buf, int size)
+{
+ struct msg_recv *msg = (struct msg_recv *)buf;
+
+ assert(sk->ops);
+ /*if (unlikely(!sk->ops)) {
+ sock_send_errno(sk->hnd.fd, ENOTSOCK);
+ return -1;
+ }*/
+
+ return sk->ops->recv(sk, msg->len, msg->flags, msg->addrlen);
+}
+
+static int msg_send(struct sock *sk, void *buf, int size)
+{
+ struct msg_send *msg = (struct msg_send *)buf;
+ struct sockaddr *addr = (struct sockaddr *)(msg + 1);
+
+ assert(sk->ops);
+ /*if (unlikely(!sk->ops)) {
+ sock_send_errno(sk->hnd.fd, ENOTSOCK);
+ return -1;
+ }*/
+
+ return sk->ops->send(sk, (char *)(msg + 1) + msg->addrlen, msg->len, msg->flags, addr, msg->addrlen);
+}
+
+static int msg_ioctl(struct sock *sk, void *buf, int size)
+{
+ struct msg_ioctl *msg = (struct msg_ioctl *)buf;
+
+ assert(sk->ops);
+
+ return sk->ops->ioctl(sk, msg->request, msg->arg);
+}
+
+static int msg_ppp_open(struct sock *sk, void *buf, int size)
+{
+ struct msg_socket *msg = (struct msg_socket *)buf;
+ msg->domain = PF_PPP;
+ msg->type = SOCK_DGRAM;
+ msg->proto = 0;
+
+ return msg_socket(sk, buf, size);
+}
+
+static int msg_sock_ioctl(struct sock *sk, void *buf, int size)
+{
+ //struct msg_ioctl *msg = (struct msg_ioctl *)buf;
+
+ return 0;
+}
+
+typedef int (*handler)(struct sock *sk, void *buf, int size);
+static handler msg_hnd[__MSG_MAX_ID] = {
+ [MSG_SOCKET] = msg_socket,
+ [MSG_CONNECT] = msg_connect,
+ [MSG_BIND] = msg_bind,
+ [MSG_LISTEN] = msg_listen,
+ [MSG_RECV] = msg_recv,
+ [MSG_SEND] = msg_send,
+ [MSG_IOCTL] = msg_ioctl,
+ [MSG_PPP_OPEN] = msg_ppp_open,
+ [MSG_SOCK_IOCTL] = msg_sock_ioctl,
+};
+
+int sock_no_listen(struct sock *sk, int backlog)
+{
+ return sock_send_errno(sk->hnd.fd, ENOSYS);
+}
+
+int sock_no_connect(struct sock *sk, const struct sockaddr *addr, socklen_t addrlen)
+{
+ return sock_send_errno(sk->hnd.fd, ENOSYS);
+}
+
+int sock_no_ioctl(struct sock *sk, unsigned long request, void *arg)
+{
+ return sock_send_errno(sk->hnd.fd, ENOSYS);
+}
+
+static int sock_read(struct event_handler *h)
+{
+ struct sock *sk = container_of(h, typeof(*sk), hnd);
+ char *buf = rte_malloc(NULL, SOCK_BUF_SIZE, 0);
+ int r;
+ struct msg_hdr *hdr = (struct msg_hdr *)buf;
+
+ if (!buf)
+ goto close;
+
+ r = read(h->fd, buf, SOCK_BUF_SIZE);
+
+ if (r < sizeof(*hdr))
+ goto close;
+
+ if (hdr->id >= __MSG_MAX_ID) {
+ if (sock_send_errno(h->fd, ENOSYS))
+ goto close;
+ }
+
+ sk->res = (struct msg_result *)buf;
+ r = msg_hnd[hdr->id](sk, buf, r);
+
+ if (likely(r > 0)) {
+ if (unlikely(write(h->fd, buf, r) != r))
+ goto close;
+ }
+
+ rte_free(buf);
+
+ if (likely(r == 0))
+ return 0;
+
+close:
+ if (sk->ops)
+ sk->ops->close(sk);
+
+ event_del_handler(h, 1);
+
+ if (buf)
+ rte_free(buf);
+
+ return 1;
+}
+
+static int ctrl_accept(struct event_handler *h)
+{
+ int sock;
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ struct sock *sk;
+
+ while (1) {
+ addrlen = sizeof(addr);
+ sock = accept(h->fd, (struct sockaddr *)&addr, &addrlen);
+ if (sock < 0)
+ break;
+
+ sk = rte_malloc(NULL, sizeof(*sk), 0);
+ if (sk) {
+ sk->hnd.fd = sock;
+ sk->hnd.read = sock_read;
+ sk->ops = NULL;
+
+ fcntl(sock, F_SETFL, O_NONBLOCK);
+
+ event_add_handler(&sk->hnd, EVENT_READ);
+ } else
+ close(h->fd);
+ }
+
+ return 0;
+}
+
+int ctrl_init()
+{
+ const char *opt = conf_get_opt("core", "ctrl-socket");
+ int sock;
+ struct sockaddr_un addr;
+
+ if (event_init())
+ return -1;
+
+ if (!opt) {
+ fprintf(stderr, "ctrl-socket not specified\n");
+ return -1;
+ }
+
+ if (strlen(opt) >= sizeof(addr.sun_path)) {
+ fprintf(stderr, "ctrl-socket path is too large\n");
+ return -1;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, opt);
+
+ unlink(opt);
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
+ fprintf(stderr, "ctrl-socket: %s\n", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ if (listen(sock, 1024)) {
+ perror("listen");
+ close(sock);
+ return -1;
+ }
+
+ fcntl(sock, F_SETFL, O_NONBLOCK);
+
+ ctrl_hnd.fd = sock;
+ ctrl_hnd.read = ctrl_accept;
+ event_add_handler(&ctrl_hnd, EVENT_READ);
+
+ return 0;
+}
+