diff options
Diffstat (limited to 'accel-dp')
-rw-r--r-- | accel-dp/CMakeLists.txt | 49 | ||||
-rw-r--r-- | accel-dp/af_packet.c | 82 | ||||
-rw-r--r-- | accel-dp/common.h | 25 | ||||
-rw-r--r-- | accel-dp/conf_file.c | 364 | ||||
-rw-r--r-- | accel-dp/conf_file.h | 24 | ||||
-rw-r--r-- | accel-dp/ctrl.c | 347 | ||||
-rw-r--r-- | accel-dp/dev.c | 94 | ||||
-rw-r--r-- | accel-dp/dev.h | 33 | ||||
-rw-r--r-- | accel-dp/distributor.c | 156 | ||||
-rw-r--r-- | accel-dp/eth_dev.c | 118 | ||||
-rw-r--r-- | accel-dp/event.c | 284 | ||||
-rw-r--r-- | accel-dp/event.h | 44 | ||||
-rw-r--r-- | accel-dp/if_dp.h | 77 | ||||
-rw-r--r-- | accel-dp/init.h | 18 | ||||
l--------- | accel-dp/iputils.c | 1 | ||||
l--------- | accel-dp/iputils.h | 1 | ||||
-rw-r--r-- | accel-dp/kni_dev.c | 213 | ||||
-rw-r--r-- | accel-dp/kni_dev.h | 9 | ||||
l--------- | accel-dp/libnetlink.c | 1 | ||||
l--------- | accel-dp/libnetlink.h | 1 | ||||
-rw-r--r-- | accel-dp/list.h | 251 | ||||
-rw-r--r-- | accel-dp/log.c | 350 | ||||
-rw-r--r-- | accel-dp/log.h | 61 | ||||
-rw-r--r-- | accel-dp/log_file.c | 246 | ||||
-rw-r--r-- | accel-dp/main.c | 378 | ||||
-rw-r--r-- | accel-dp/sock.h | 40 |
26 files changed, 3267 insertions, 0 deletions
diff --git a/accel-dp/CMakeLists.txt b/accel-dp/CMakeLists.txt new file mode 100644 index 00000000..0506615f --- /dev/null +++ b/accel-dp/CMakeLists.txt @@ -0,0 +1,49 @@ +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mssse3") + +add_definitions("-DACCEL_DP") + +include_directories(${DPDK}/build/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +find_library(rte_eal NAMES librte_eal.a PATHS ${DPDK}/build/lib) +find_library(rte_malloc NAMES librte_malloc.a PATHS ${DPDK}/build/lib) +find_library(rte_mbuf NAMES librte_mbuf.a PATHS ${DPDK}/build/lib) +find_library(rte_mempool NAMES librte_mempool.a PATHS ${DPDK}/build/lib) +find_library(rte_ring NAMES librte_ring.a PATHS ${DPDK}/build/lib) +find_library(ethdev NAMES libethdev.a PATHS ${DPDK}/build/lib) +find_library(rte_kni NAMES librte_kni.a PATHS ${DPDK}/build/lib) +find_library(rte_distributor NAMES librte_distributor.a PATHS ${DPDK}/build/lib) +find_library(rte_pmd_virtio NAMES librte_pmd_virtio.a PATHS ${DPDK}/build/lib) + +add_executable(accel-dp + main.c + conf_file.c + event.c + ctrl.c + af_packet.c + dev.c + eth_dev.c + kni_dev.c + distributor.c + + log.c + log_file.c + + libnetlink.c + iputils.c +) + +target_link_libraries(accel-dp dl pthread + -Wl,-whole-archive + ${rte_eal} + ${rte_mbuf} + ${rte_mempool} + ${rte_ring} + ${rte_malloc} + ${ethdev} + ${rte_kni} + ${rte_distributor} + ${rte_pmd_virtio} + -Wl,-no-whole-archive +) + diff --git a/accel-dp/af_packet.c b/accel-dp/af_packet.c new file mode 100644 index 00000000..89a3c09b --- /dev/null +++ b/accel-dp/af_packet.c @@ -0,0 +1,82 @@ +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <assert.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <linux/if_packet.h> + +#include <rte_malloc.h> + +#include "sock.h" +#include "common.h" +#include "dev.h" + +struct packet_priv { + int type; +}; + +static int packet_socket(struct sock *sk, int type, int proto) +{ + struct packet_priv *priv = rte_malloc(NULL, sizeof(*sk->priv), 0); + + if (!priv) + return sock_errno(sk, ENOMEM); + + priv->type = type; + + sk->priv = priv; + + return sock_errno(sk, 0); +} + +static int packet_bind(struct sock *sk, const struct sockaddr *a, socklen_t addrlen) +{ + struct sockaddr_ll *addr = (struct sockaddr_ll *)a; + struct net_device *dev = NULL; + + if (addrlen != sizeof(*addr)) + return sock_errno(sk, EINVAL); + + if (addr->sll_ifindex) { + dev = netdev_get_by_index(addr->sll_ifindex); + if (!dev) + return sock_errno(sk, ENODEV); + } + + return sock_errno(sk, 0); +} + +static int packet_recv(struct sock *sk, size_t len, int flags, socklen_t addrlen) +{ + + return sock_errno(sk, EAGAIN); +} + +static int packet_send(struct sock *sk, void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) +{ + + return sock_errno(sk, 0); +} + +static void packet_close(struct sock *sk) +{ + rte_free(sk->priv); +} + +static const struct proto_ops proto = { + .socket = packet_socket, + .bind = packet_bind, + .listen = sock_no_listen, + .connect = sock_no_connect, + .recv = packet_recv, + .send = packet_send, + .ioctl = sock_no_ioctl, + .close = packet_close, +}; + +static void __init init() +{ + sock_register_proto(PF_PACKET, SOCK_RAW, 0, &proto); +} + diff --git a/accel-dp/common.h b/accel-dp/common.h new file mode 100644 index 00000000..62b47e32 --- /dev/null +++ b/accel-dp/common.h @@ -0,0 +1,25 @@ +#ifndef __COMMON_H +#define __COMMON_H + +#define __init __attribute__((constructor)) +#define __exit __attribute__((destructor)) +#define __export __attribute__((visibility("default"))) + +#undef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +extern int sock_fd; + +#endif + diff --git a/accel-dp/conf_file.c b/accel-dp/conf_file.c new file mode 100644 index 00000000..c22cfd5d --- /dev/null +++ b/accel-dp/conf_file.c @@ -0,0 +1,364 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#include "conf_file.h" + +struct conf_ctx { + const char *fname; + FILE *file; + int line; + struct conf_opt **list; + int options:1; +}; + +static struct conf_sect *sect_head; +static struct conf_sect *sect_tail; + +static char* skip_space(char *str); +static char* skip_word(char *str); + +static struct conf_sect *find_sect(const char *name); +static struct conf_sect *create_sect(const char *name); +static int sect_add_item(struct conf_ctx *ctx, const char *name, char *val, char *raw); +static struct conf_opt *find_item(struct conf_opt *list, const char *name); +static int load_file(struct conf_ctx *ctx); + +static char *buf; +static struct conf_sect *cur_sect; + +static int open_ctx(struct conf_ctx *ctx, const char *fname, struct conf_opt **list) +{ + ctx->file = fopen(fname, "r"); + if (!ctx->file) + return -1; + + ctx->fname = fname; + ctx->line = 0; + ctx->list = ctx->list; + ctx->options = 0; + + return 0; +} + +static void close_ctx(struct conf_ctx *ctx) +{ + fclose(ctx->file); +} + +static int load_file(struct conf_ctx *ctx) +{ + char *str, *str2, *raw; + int len; + + while(1) { + if (!fgets(buf, 1024, ctx->file)) + break; + ctx->line++; + + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[--len] = 0; + + while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) + buf[--len] = 0; + + str = skip_space(buf); + if (*str == '#' || *str == 0) + continue; + + if (strncmp(str, "$include", 8) == 0) { + struct conf_ctx ctx1; + int r; + str = skip_word(str); + str = skip_space(str); + + if (open_ctx(&ctx1, str, ctx->list)) + break; + + r = load_file(&ctx1); + + close_ctx(&ctx1); + + if (r) + break; + + ctx->list = ctx1.list; + + continue; + } + + if (*str == '[') { + for (str2 = ++str; *str2 && *str2 != ']'; str2++); + if (*str2 != ']') { + fprintf(stderr, "conf_file:%s:%i: sintax error\n", ctx->fname, ctx->line); + return -1; + } + + if (ctx->options) { + fprintf(stderr, "conf_file:%s:%i: cann't open section inside option\n", ctx->fname, ctx->line); + return -1; + } + + *str2 = 0; + cur_sect = find_sect(str); + if (!cur_sect) + cur_sect = create_sect(str); + ctx->list = (struct conf_opt **)&cur_sect->opt; + continue; + } + + if (!cur_sect) { + fprintf(stderr, "conf_file:%s:%i: no section opened\n", ctx->fname, ctx->line); + return -1; + } + + if (*str == '}') { + if (ctx->options) + return 0; + + fprintf(stderr, "conf_file:%s:%i: sintax error\n", ctx->fname, ctx->line); + return -1; + } + + raw = strdup(str); + str2 = skip_word(str); + if (*str2 == ' ') { + *str2 = 0; + ++str2; + } + + str2 = skip_space(str2); + if (*str2 == '=' || *str2 == ',') { + *str2 = 0; + str2 = skip_space(str2 + 1); + if (*str2 && *(str2 + 1) && *str2 == '$' && *(str2 + 1) == '{') { + char *s; + struct conf_opt *opt; + for (s = str2 + 2; *s && *s != '}'; s++); + if (*s == '}') { + *s = 0; + str2 += 2; + } + opt = find_item(cur_sect->opt, str2); + if (!opt) { + fprintf(stderr, "conf_file:%s:%i: parent option not found\n", ctx->fname, ctx->line); + return -1; + } + str2 = (char *)opt->val; + } + } else + str2 = NULL; + + if (sect_add_item(ctx, str, str2, raw)) + return -1; + } + + return 0; +} + +/*static void print_items(struct list_head *items, int dep) +{ + struct conf_option_t *opt; + int i; + + list_for_each_entry(opt, items, entry) { + for (i = 0; i < dep; i++) + printf("\t"); + printf("%s=%s\n", opt->name, opt->val); + print_items(&opt->items, dep + 1); + } +} + +static void print_conf() +{ + struct sect_t *s; + + list_for_each_entry(s, §ions, entry) { + printf("[%s]\n", s->sect->name); + print_items(&s->sect->items, 0); + } +}*/ + +static void free_items(struct conf_opt *opt) +{ + struct conf_opt *next; + + for (next = opt->next; opt; opt = next) { + if (opt->child) + free_items(opt->child); + free(opt->name); + free(opt->raw); + if (opt->val) + free(opt->val); + free((void *)opt); + } +} + +static void conf_clear(struct conf_sect *s) +{ + struct conf_sect *next; + + for (next = s->next; s; s = next) { + if (s->opt) + free_items(s->opt); + free(s->name); + free((void *)s); + } +} + +int conf_load(const char *fname) +{ + struct conf_sect *head = sect_head; + struct conf_ctx ctx; + int r; + + if (open_ctx(&ctx, fname, NULL)) + return -1; + + cur_sect = NULL; + sect_head = NULL; + + buf = malloc(1024); + + r = load_file(&ctx); + + free(buf); + + close_ctx(&ctx); + + if (r) + sect_head = head; + else if (head) + conf_clear(head); + + return r; +} + +static char* skip_space(char *str) +{ + for (; *str && (*str == ' ' || *str == '\t'); str++); + return str; +} + +static char* skip_word(char *str) +{ + for (; *str && (*str != ' ' && *str != '\t' && *str != '='); str++); + return str; +} + +static struct conf_sect *find_sect(const char *name) +{ + struct conf_sect *s; + + for (s = sect_head; s; s = s->next) { + if (strcmp(s->name, name) == 0) + return s; + } + + return NULL; +} + +static struct conf_sect *create_sect(const char *name) +{ + struct conf_sect *s = malloc(sizeof(struct conf_sect)); + + s->name = strdup(name); + s->next = NULL; + s->opt = NULL; + + if (!sect_head) + sect_head = s; + else + sect_tail->next = s; + + sect_tail = s; + + return s; +} + +static int sect_add_item(struct conf_ctx *ctx, const char *name, char *val, char *raw) +{ + struct conf_opt *opt = malloc(sizeof(struct conf_opt)); + int r = 0; + int chld = 0; + + if (val) { + int len = strlen(val); + if (val[len - 1] == '{') { + chld = 1; + val[--len] = 0; + + while (--len >= 0 && (val[len] == ' ' || val[len] == '\t')); + + if (len >= 0) + val[len + 1] = 0; + else + val = NULL; + } + } + + opt->name = strdup(name); + opt->val = val ? strdup(val) : NULL; + opt->raw = raw; + opt->next = NULL; + opt->child = NULL; + + *ctx->list = opt; + ctx->list = &opt->next; + + if (chld) { + struct conf_opt **list = ctx->list; + ctx->list = &opt->child; + ctx->options = 1; + r = load_file(ctx); + ctx->options = 0; + ctx->list = list; + } + + return r; +} + +static struct conf_opt *find_item(struct conf_opt *list, const char *name) +{ + struct conf_opt *opt; + + for (opt = list; opt; opt = opt->next) { + if (strcmp(opt->name, name) == 0) + return opt; + } + + return NULL; +} + +struct conf_sect* conf_get_sect(const char *name) +{ + return find_sect(name); +} + +const char *conf_get_opt(const char *sect, const char *name) +{ + struct conf_opt *opt; + struct conf_sect *s = conf_get_sect(sect); + + if (!s) + return NULL; + + opt = find_item(s->opt, name); + if (!opt) + return NULL; + + return opt->val; +} + +const char *conf_get_subopt(const struct conf_opt *opt, const char *name) +{ + if (!opt->child) + return NULL; + + opt = find_item(opt->child, name); + + return opt ? opt->val : NULL; +} + diff --git a/accel-dp/conf_file.h b/accel-dp/conf_file.h new file mode 100644 index 00000000..7110303f --- /dev/null +++ b/accel-dp/conf_file.h @@ -0,0 +1,24 @@ +#ifndef __CONF_FILE_H +#define __CONF_FILE_H + +struct conf_opt { + struct conf_opt *next; + char *name; + char *val; + char *raw; + struct conf_opt *child; +}; + +struct conf_sect { + struct conf_sect *next; + char *name; + struct conf_opt *opt; +}; + +struct conf_sect *conf_get_sect(const char *name); +const char *conf_get_opt(const char *sect, const char *name); +const char *conf_get_subopt(const struct conf_opt *opt, const char *name); + +int conf_load(const char *fname); + +#endif diff --git a/accel-dp/ctrl.c b/accel-dp/ctrl.c new file mode 100644 index 00000000..b816d82c --- /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; +} + diff --git a/accel-dp/dev.c b/accel-dp/dev.c new file mode 100644 index 00000000..d31773db --- /dev/null +++ b/accel-dp/dev.c @@ -0,0 +1,94 @@ +#include <string.h> + +#include <rte_malloc.h> + +#include "init.h" +#include "dev.h" + +#define DEV_MAX 65536 + +static struct net_device **dev_list; +static int next_idx = 1; + +struct net_device *netdev_get_by_index(int id) +{ + struct net_device *dev; + + if (id <= 0 || id >= DEV_MAX) + return NULL; + + dev = dev_list[id]; + + if (dev) + ++dev->refs; + + return dev; +} + +struct net_device *netdev_alloc(const char *name, int priv_size, void (*setup)(struct net_device *dev)) +{ + struct net_device *dev; + int i; + + for (i = 0; i < DEV_MAX; i++) { + if (dev_list[i] && !strcmp(dev_list[i]->name, name)) + return NULL; + } + + for (; next_idx < DEV_MAX; next_idx++) { + if (!dev_list[next_idx]) + break; + } + + if (next_idx == DEV_MAX) { + for (next_idx = 1; next_idx < DEV_MAX; next_idx++) { + if (!dev_list[next_idx]) + break; + } + + if (next_idx == DEV_MAX) + return NULL; + } + + dev = rte_malloc(NULL, sizeof(*dev) + priv_size, 0); + strcpy(dev->name, name); + dev->index = next_idx; + + dev->refs = 1; + dev->destructor = netdev_free; + + if (setup) + setup(dev); + + dev_list[next_idx] = dev; + + if (++next_idx == DEV_MAX) + next_idx = 1; + + return dev; +} + +void netdev_unregister(struct net_device *dev) +{ + dev_list[dev->index] = NULL; + + netdev_put(dev); +} + +void netdev_free(struct net_device *dev) +{ + rte_free(dev); +} + +void netdev_put(struct net_device *dev) +{ + if (--dev->refs == 0) + dev->destructor(dev); +} + +static void init() +{ + dev_list = rte_zmalloc(0, DEV_MAX * sizeof(void *), 0); +} + +DEFINE_INIT(1, init); diff --git a/accel-dp/dev.h b/accel-dp/dev.h new file mode 100644 index 00000000..1039a17b --- /dev/null +++ b/accel-dp/dev.h @@ -0,0 +1,33 @@ +#ifndef __NET_DEVICE_H +#define __NET_DEVICE_H + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +struct rte_mbuf; + +struct net_device { + char name[IFNAMSIZ]; + int index; + + unsigned char hwaddr[6]; + + int refs; + + void (*xmit)(struct rte_mbuf *mbuf, struct net_device *dev); + void (*destructor)(struct net_device *dev); +}; + +struct net_device *netdev_get_by_index(int id); +void netdev_put(struct net_device *dev); +void netdev_free(struct net_device *dev); +struct net_device *netdev_alloc(const char *name, int priv_size, void (*setup)(struct net_device *dev)); +void netdev_unregister(struct net_device *dev); + +static inline void *netdev_priv(struct net_device *dev) +{ + return dev + 1; +} + +#endif diff --git a/accel-dp/distributor.c b/accel-dp/distributor.c new file mode 100644 index 00000000..970f322f --- /dev/null +++ b/accel-dp/distributor.c @@ -0,0 +1,156 @@ +#include <rte_config.h> +#include <rte_memory.h> +#include <rte_malloc.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_ethdev.h> +#include <rte_log.h> +#include <rte_errno.h> +#include <rte_distributor.h> +#include <rte_debug.h> + +#include "init.h" +#include "kni_dev.h" +#include "event.h" +#include "log.h" + +#define BURST_SIZE 32 + +#define MBUF_DROP 255 + +static struct rte_distributor *d; +static int term; +static int port_cnt; + +struct xmit_buf { + struct rte_mbuf *bufs[BURST_SIZE]; + int cnt; +}; + +int distributor_init(int ded) +{ + d = rte_distributor_create("distributor", rte_socket_id(), rte_lcore_count() - ded); + return d == NULL; +} + +static void flush_port(int port, struct xmit_buf *xb) +{ + int nb; + + if (likely(port < port_cnt)) + nb = rte_eth_tx_burst(port, 0, xb->bufs, xb->cnt); + else + nb = kni_dev_tx_burst(port - port_cnt, 0, xb->bufs, xb->cnt); + + if (unlikely(nb < xb->cnt)) { + do { + rte_pktmbuf_free(xb->bufs[nb]); + } while (++nb < xb->cnt); + } +} + +static void distributor_tx(struct rte_mbuf **bufs, int nb, struct xmit_buf *xmit_bufs) +{ + struct rte_mbuf *mb; + int i, p; + + _mm_prefetch(bufs[0], 0); + _mm_prefetch(bufs[1], 0); + _mm_prefetch(bufs[2], 0); + for (i = 0; i < nb; i++) { + _mm_prefetch(bufs[i + 3], 0); + + mb = bufs[i]; + + p = mb->port; + + if (likely(p != MBUF_DROP)) { + struct xmit_buf *xb = &xmit_bufs[p]; + xb->bufs[xb->cnt++] = mb; + if (xb->cnt == BURST_SIZE) + flush_port(p, xb); + } else + rte_pktmbuf_free(mb); + } +} + +void distributor_loop(int chk_event) +{ + int kni_port_cnt = kni_dev_count(); + struct rte_mbuf *bufs[BURST_SIZE*2]; + int port, nb, i; + struct xmit_buf *xmit_bufs; + int tot_port_cnt; + struct xmit_buf *xb; + + port_cnt = rte_eth_dev_count(); + tot_port_cnt = port_cnt + kni_port_cnt; + + xmit_bufs = rte_malloc(NULL, (tot_port_cnt * sizeof(struct xmit_buf)), 0); + + for (i = 0; i < tot_port_cnt; i++) + xmit_bufs[i].cnt = 0; + + while (!term) { + for (port = 0; port < port_cnt; port++) { + nb = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE); + + if (likely(nb)) + rte_distributor_process(d, bufs, nb); + + nb = rte_distributor_returned_pkts(d, bufs, BURST_SIZE*2); + + if (likely(nb)) + distributor_tx(bufs, nb, xmit_bufs); + } + + for (port = 0; port < kni_port_cnt; port++) { + nb = kni_dev_rx_burst(port, 0, bufs, BURST_SIZE); + + if (likely(nb)) + rte_distributor_process(d, bufs, nb); + + nb = rte_distributor_returned_pkts(d, bufs, BURST_SIZE*2); + + if (likely(nb)) + distributor_tx(bufs, nb, xmit_bufs); + } + + _mm_prefetch(&xmit_bufs[0], 0); + _mm_prefetch(&xmit_bufs[1], 0); + _mm_prefetch(&xmit_bufs[2], 0); + for (i = 0; i < tot_port_cnt; i++) { + _mm_prefetch(&xmit_bufs[i + 3], 0); + + xb = &xmit_bufs[i]; + + if (likely(xb->cnt)) + flush_port(i, xb); + } + + if (chk_event) + event_process(0); + } +} + +int lcore_worker(void *a) +{ + struct rte_mbuf *mb = NULL; + + while (!term) { + mb = rte_distributor_get_pkt(d, 0, mb); + mb->port = MBUF_DROP; + } + + return 0; +} + +int lcore_distributor(void *a) +{ + distributor_loop(0); + + return 0; +} diff --git a/accel-dp/eth_dev.c b/accel-dp/eth_dev.c new file mode 100644 index 00000000..c99edba4 --- /dev/null +++ b/accel-dp/eth_dev.c @@ -0,0 +1,118 @@ +#include <unistd.h> + +#include <rte_config.h> +#include <rte_mbuf.h> +#include <rte_ethdev.h> +#include <rte_malloc.h> +#include <rte_errno.h> + +#include "init.h" +#include "conf_file.h" +#include "dev.h" + +#define TX_RING_SIZE 512 +#define RX_RING_SIZE 512 + +struct ethdev { + int port; +}; + +static struct ethdev **dev_list; + +static void ethdev_xmit(struct rte_mbuf *mbuf, struct net_device *dev) +{ + struct ethdev *eth_dev = netdev_priv(dev); + + mbuf->port = eth_dev->port; +} + +int eth_dev_init(struct rte_mempool *mbuf_pool) +{ + struct conf_sect *s = conf_get_sect("interface"); + struct conf_opt *opt; + int i, cnt = rte_eth_dev_count(); + struct rte_eth_dev_info info; + char busid[64]; + const char *opt1; + int rxd, txd; + struct net_device *dev; + struct ethdev *eth_dev; + struct ether_addr addr; + struct rte_eth_link link; + struct rte_eth_conf conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_NONE, + .max_rx_pkt_len = ETHER_MAX_LEN + 8, + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + }; + + dev_list = rte_malloc(NULL, cnt * sizeof(void *), 0); + + for (i = 0; i < cnt; i++) { + rte_eth_dev_info_get(i, &info); + + sprintf(busid, "%04x:%02x:%02x.%i", info.pci_dev->addr.domain, info.pci_dev->addr.bus, info.pci_dev->addr.devid, info.pci_dev->addr.function); + + for (opt = s->opt; opt; opt = opt->next) { + const char *opt_busid = conf_get_subopt(opt, "busid"); + if (!strcmp(opt_busid, busid) || !strcmp(opt_busid, busid + 5)) + break; + } + + opt1 = conf_get_subopt(opt, "txd"); + if (opt1) + txd = atoi(opt1); + else + txd = TX_RING_SIZE; + + opt1 = conf_get_subopt(opt, "rxd"); + if (opt1) + rxd = atoi(opt1); + else + rxd = RX_RING_SIZE; + + if (rte_eth_dev_configure(i, 1, 1, &conf)) { + fprintf(stderr, "%s: %s\n", busid, rte_strerror(rte_errno)); + return -1; + } + + if (rte_eth_rx_queue_setup(i, 0, rxd, rte_eth_dev_socket_id(i), NULL, mbuf_pool)) { + fprintf(stderr, "%s: %s\n", busid, rte_strerror(rte_errno)); + return -1; + } + + if (rte_eth_tx_queue_setup(i, 0, txd, rte_eth_dev_socket_id(i), NULL)) { + fprintf(stderr, "%s: %s\n", busid, rte_strerror(rte_errno)); + return -1; + } + + if (rte_eth_dev_start(i)) { + fprintf(stderr, "%s: %s\n", busid, rte_strerror(rte_errno)); + return -1; + } + + rte_eth_link_get_nowait(i, &link); + if (!link.link_status) { + sleep(1); + rte_eth_link_get_nowait(i, &link); + } + + if (!link.link_status) + printf("%s: link down\n", opt->name); + + rte_eth_macaddr_get(i, &addr); + + dev = netdev_alloc(opt->name, sizeof(*eth_dev), NULL); + dev->xmit = ethdev_xmit; + memcpy(dev->hwaddr, addr.addr_bytes, ETHER_ADDR_LEN); + eth_dev = netdev_priv(dev); + eth_dev->port = i; + + dev_list[i] = eth_dev; + } + + return 0; +} diff --git a/accel-dp/event.c b/accel-dp/event.c new file mode 100644 index 00000000..c313df81 --- /dev/null +++ b/accel-dp/event.c @@ -0,0 +1,284 @@ +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> + +#include "event.h" + +#define MAX_EVENT 128 + +static int epoll_fd; +static struct epoll_event *epoll_events; +static struct event_deferred *deferred_list; +static LIST_HEAD(timers); +static LIST_HEAD(handlers); +static int term; + +int event_init(void) +{ + epoll_fd = epoll_create(1); + if (epoll_fd < 0) { + perror("epoll_create"); + return -1; + } + + if (!epoll_events) + epoll_events = malloc(MAX_EVENT * sizeof(struct epoll_event)); + + term = 0; + + INIT_LIST_HEAD(&timers); + INIT_LIST_HEAD(&handlers); + + return 0; +} + +static int get_timeout() +{ + struct event_handler *h; + struct timespec ts; + + if (list_empty(&timers)) + return -1; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + h = list_entry(timers.next, typeof(*h), entry2); + + if (ts.tv_sec > h->timeout_ts.tv_sec || (ts.tv_sec == h->timeout_ts.tv_sec && ts.tv_nsec >= h->timeout_ts.tv_nsec)) + return 0; + + return (h->timeout_ts.tv_sec - ts.tv_sec)*1000 + (h->timeout_ts.tv_nsec - ts.tv_nsec)/1000000; +} + +static void check_timeout() +{ + struct event_handler *h; + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + while (!list_empty(&timers)) { + h = list_entry(timers.next, typeof(*h), entry2); + + if (ts.tv_sec > h->timeout_ts.tv_sec || (ts.tv_sec == h->timeout_ts.tv_sec && ts.tv_nsec >= h->timeout_ts.tv_nsec)) { + list_del(&h->entry2); + h->entry2.next = NULL; + h->timeout(h); + } else + break; + } +} + +void event_process(int timeout) +{ + int i, n; + struct event_handler *h; + struct event_deferred *d; + uint32_t events; + struct list_head *pos, *t; + + if (timeout == -1) + timeout = get_timeout(); + else if (timeout > 0) { + int t = get_timeout(); + if (t >= 0 && t < timeout) + timeout = t; + } + + n = epoll_wait(epoll_fd, epoll_events, MAX_EVENT, timeout); + if (n <= 0) + return; + + for(i = 0; i < n && !term; i++) { + h = (struct event_handler *)epoll_events[i].data.ptr; + + if (h->fd == -1) + continue; + + if (!h->epoll_event.events) + continue; + + events = epoll_events[i].events & h->epoll_event.events; + + if ((events & (EPOLLIN|EPOLLHUP)) && h->read) { + if (h->read(h)) + continue; + } + + if ((events & (EPOLLOUT|EPOLLHUP)) && h->write) { + if (h->write(h)) + continue; + } + } + + check_timeout(); + + while (deferred_list) { + d = deferred_list; + deferred_list = deferred_list->next; + d->fn(d); + } + + if (term) { + list_for_each_safe(pos, t, &handlers) { + h = list_entry(pos, typeof(*h), entry); + if (h->close) + h->close(h); + } + + while (deferred_list) { + d = deferred_list; + deferred_list = deferred_list->next; + d->fn(d); + } + + close(epoll_fd); + } +} + +void event_loop() +{ + while (!term) + event_process(-1); +} + +void event_terminate(void) +{ + term = 1; +} + +int event_add_handler(struct event_handler *h, int mode) +{ + list_add_tail(&h->entry, &handlers); + + h->epoll_event.data.ptr = h; + h->epoll_event.events = EPOLLET; + + if (mode & EVENT_READ) + h->epoll_event.events |= EPOLLIN; + + if (mode & EVENT_WRITE) + h->epoll_event.events |= EPOLLOUT; + + return epoll_ctl(epoll_fd, EPOLL_CTL_ADD, h->fd, &h->epoll_event); +} + +int event_mod_handler(struct event_handler *h, int mode) +{ + h->epoll_event.data.ptr = h; + h->epoll_event.events = EPOLLET; + + if (mode & EVENT_READ) + h->epoll_event.events |= EPOLLIN; + + if (mode & EVENT_WRITE) + h->epoll_event.events |= EPOLLOUT; + + return epoll_ctl(epoll_fd, EPOLL_CTL_MOD, h->fd, &h->epoll_event); +} + +int event_enable_handler(struct event_handler *h, int mode) +{ + uint32_t events = h->epoll_event.events; + + if (mode & EVENT_READ) + h->epoll_event.events |= EPOLLIN; + + if (mode & EVENT_WRITE) + h->epoll_event.events |= EPOLLOUT; + + if (events == h->epoll_event.events) + return 0; + + return epoll_ctl(epoll_fd, EPOLL_CTL_MOD, h->fd, &h->epoll_event); +} + +int event_disable_handler(struct event_handler *h, int mode) +{ + uint32_t events = h->epoll_event.events; + + if (mode & EVENT_READ) + h->epoll_event.events &= ~EPOLLIN; + + if (mode & EVENT_WRITE) + h->epoll_event.events &= ~EPOLLOUT; + + if (events == h->epoll_event.events) + return 0; + + return epoll_ctl(epoll_fd, EPOLL_CTL_MOD, h->fd, &h->epoll_event); +} + +int event_del_handler(struct event_handler *h, int c) +{ + if (!h->entry.next) + return 0; + + if (h->entry2.next) { + list_del(&h->entry2); + h->entry2.next = NULL; + } + + list_del(&h->entry); + + if (c) { + close(h->fd); + h->fd = -1; + return 0; + } + + h->epoll_event.events = 0; + + return epoll_ctl(epoll_fd, EPOLL_CTL_DEL, h->fd, NULL); +} + +void event_set_timeout(struct event_handler *h, int msec) +{ + struct event_handler *h1; + struct list_head *pos; + struct timespec ts; + + if (h->entry2.next) + list_del(&h->entry2); + + if (msec == -1) { + h->entry2.next = NULL; + return; + } + + clock_gettime(CLOCK_MONOTONIC, &ts); + + ts.tv_sec += msec / 1000; + ts.tv_nsec += (msec % 1000) * 1000000; + + if (ts.tv_nsec >= 1000000000) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000; + } + + h->timeout_ts = ts; + + pos = timers.prev; + + while (pos != &timers) { + h1 = list_entry(pos, typeof(*h1), entry2); + + if (ts.tv_sec > h1->timeout_ts.tv_sec || (ts.tv_sec == h1->timeout_ts.tv_sec && ts.tv_nsec >= h1->timeout_ts.tv_nsec)) + break; + + pos = pos->prev; + } + + list_add(&h->entry2, pos); +} + +void event_add_deferred(struct event_deferred *d) +{ + d->next = deferred_list; + deferred_list = d; +} + diff --git a/accel-dp/event.h b/accel-dp/event.h new file mode 100644 index 00000000..fefb0991 --- /dev/null +++ b/accel-dp/event.h @@ -0,0 +1,44 @@ +#ifndef __EVENT_H__ +#define __EVENT_H__ + +#include <sys/epoll.h> +#include "list.h" + +#define EVENT_READ 1 +#define EVENT_WRITE 2 + +struct event_handler { + struct list_head entry; + struct list_head entry2; + struct timespec timeout_ts; + int fd; + struct epoll_event epoll_event; + int (*read)(struct event_handler *); + int (*write)(struct event_handler *); + void (*timeout)(struct event_handler *); + void (*close)(struct event_handler *); +}; + +struct event_deferred { + struct event_deferred *next; + void (*fn)(struct event_deferred *); +}; + +int event_init(void); +void event_loop(); +void event_process(int timeout); +void event_terminate(void); +int event_add_handler(struct event_handler *h, int mode); +int event_enable_handler(struct event_handler *h, int mode); +int event_disable_handler(struct event_handler *h, int mode); +int event_mod_handler(struct event_handler *h, int mode); +int event_del_handler(struct event_handler *h, int close); +void event_set_timeout(struct event_handler *h, int msec); +void event_add_deferred(struct event_deferred *d); + +static inline void event_init_handler(struct event_handler *h) +{ + h->entry.next = NULL; +} + +#endif diff --git a/accel-dp/if_dp.h b/accel-dp/if_dp.h new file mode 100644 index 00000000..5c209a79 --- /dev/null +++ b/accel-dp/if_dp.h @@ -0,0 +1,77 @@ +#ifndef __IF_DP_H +#define __IF_DP_H + +#include <stdint.h> + +enum { + MSG_SOCKET, + MSG_CONNECT, + MSG_BIND, + MSG_LISTEN, + MSG_RECV, + MSG_SEND, + MSG_IOCTL, + MSG_PPP_OPEN, + MSG_SOCK_IOCTL, + __MSG_MAX_ID +}; + +#define MSG_MAX_ID (__MSG_MAX_ID - 1) + +struct msg_hdr { + uint8_t id; +}; + +struct msg_socket { + uint8_t id; + int domain; + int type; + int proto; +}; + +struct msg_connect { + uint8_t id; + socklen_t addrlen; + char addr[0]; +}; + +struct msg_bind { + uint8_t id; + socklen_t addrlen; + char addr[0]; +}; + +struct msg_listen { + uint8_t id; + int backlog; +}; + +struct msg_recv { + uint8_t id; + size_t len; + int flags; + socklen_t addrlen; +}; + +struct msg_send { + uint8_t id; + size_t len; + int flags; + socklen_t addrlen; +}; + +struct msg_ioctl { + uint8_t id; + unsigned long request; + char arg[0]; +}; + +struct msg_result { + int err; + ssize_t len; + socklen_t addrlen; + struct sockaddr_storage ss; +}; + +#endif + diff --git a/accel-dp/init.h b/accel-dp/init.h new file mode 100644 index 00000000..28c87810 --- /dev/null +++ b/accel-dp/init.h @@ -0,0 +1,18 @@ +#ifndef __INIT_H +#define __INIT_H + +struct rte_mempool; + +int ctrl_init(); +int kni_dev_init(struct rte_mempool *mbuf_pool); +int eth_dev_init(struct rte_mempool *mbuf_pool); + +int distributor_init(int ded); +void distributor_loop(int chk_event); +int lcore_worker(void *a); +int lcore_distributor(void *a); + +void register_init(int order, void (*func)(void)); +#define DEFINE_INIT(o, func) static void __attribute__((constructor)) __init__(void){register_init(o,func);} + +#endif diff --git a/accel-dp/iputils.c b/accel-dp/iputils.c new file mode 120000 index 00000000..ca75da2f --- /dev/null +++ b/accel-dp/iputils.c @@ -0,0 +1 @@ +../accel-pppd/libnetlink/iputils.c
\ No newline at end of file diff --git a/accel-dp/iputils.h b/accel-dp/iputils.h new file mode 120000 index 00000000..a36b2246 --- /dev/null +++ b/accel-dp/iputils.h @@ -0,0 +1 @@ +../accel-pppd/libnetlink/iputils.h
\ No newline at end of file diff --git a/accel-dp/kni_dev.c b/accel-dp/kni_dev.c new file mode 100644 index 00000000..bafe9767 --- /dev/null +++ b/accel-dp/kni_dev.c @@ -0,0 +1,213 @@ +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <linux/if.h> + +#include <rte_config.h> +#include <rte_mbuf.h> +#include <rte_ethdev.h> +#include <rte_kni.h> +#include <rte_malloc.h> +#include <rte_errno.h> + +#include "init.h" +#include "conf_file.h" +#include "common.h" +#include "dev.h" +#include "kni_dev.h" + +#include "iputils.h" + +struct knidev { + int port; + int xport; + struct net_device *dev; + struct rte_kni *kni; + int ifindex; +}; + +static int kni_cnt; +static struct knidev **dev_list; + +int kni_dev_count() +{ + return kni_cnt; +} + +uint16_t kni_dev_rx_burst(uint8_t port_id, uint16_t queue_id, struct rte_mbuf **rx_pkts, const uint16_t nb_pkts) +{ + return rte_kni_rx_burst(dev_list[port_id]->kni, rx_pkts, nb_pkts); +} + +uint16_t kni_dev_tx_burst(uint8_t port_id, uint16_t queue_id, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) +{ + return rte_kni_tx_burst(dev_list[port_id]->kni, tx_pkts, nb_pkts); +} + +static void knidev_xmit(struct rte_mbuf *mbuf, struct net_device *dev) +{ + struct knidev *kni_dev = netdev_priv(dev); + + mbuf->port = kni_dev->xport; +} + +static int kni_change_mtu(uint8_t port, unsigned mtu) +{ + return 0; +} + +static int kni_config_network_if(uint8_t port, uint8_t if_up) +{ + return 0; +} + +static int parse_ip_addr(const char *str, in_addr_t *addr, int *mask) +{ + char *ptr = strchr(str, '/'); + char tmp[32]; + + if (ptr) { + memcpy(tmp, str, ptr - str); + tmp[ptr - str] = 0; + *addr = inet_addr(tmp); + *mask = atoi(ptr + 1); + if (*mask <= 0 || *mask > 32) + return -1; + } else { + *addr = inet_addr(str); + *mask = 32; + } + + return *addr == INADDR_NONE; +} + +struct ifconfig_arg { + struct knidev *dev; + struct conf_opt *opt; + int err; +}; + +static void *kni_ifconfig(void *a) +{ + struct ifconfig_arg *arg = a; + struct knidev *dev = arg->dev; + struct conf_opt *opt = arg->opt; + struct ifreq ifr; + const char *opt1; + in_addr_t addr; + int mask; + + strcpy(ifr.ifr_name, opt->name); + + if (ioctl(sock_fd, SIOCGIFINDEX, &ifr, sizeof(ifr))) { + fprintf(stderr, "%s: SIOCGIFINDEX: %s\n", opt->name, strerror(errno)); + arg->err = errno; + return NULL; + } + + dev->ifindex = ifr.ifr_ifindex; + + ioctl(sock_fd, SIOCGIFFLAGS, &ifr, sizeof(ifr)); + + ifr.ifr_flags |= IFF_UP | IFF_NOARP; + + while (ioctl(sock_fd, SIOCSIFFLAGS, &ifr, sizeof(ifr))) + sleep(1); + + opt1 = conf_get_subopt(opt, "ip-addr"); + if (opt1) { + if (parse_ip_addr(opt1, &addr, &mask)) { + arg->err = EINVAL; + return NULL; + } + + ipaddr_add(dev->ifindex, addr, mask); + } + + arg->err = 0; + + return NULL; +} + +int kni_dev_init(struct rte_mempool *mbuf_pool) +{ + struct conf_sect *s = conf_get_sect("interface"); + struct conf_opt *opt; + struct rte_kni_conf conf; + struct rte_kni_ops ops; + struct rte_kni *kni; + struct net_device *dev; + struct knidev *knidev; + pthread_t tid; + struct ifconfig_arg arg; + int i = 0, x = rte_eth_dev_count(); + + for (opt = s->opt; opt; opt = opt->next) { + const char *busid = conf_get_subopt(opt, "busid"); + if (!strcmp(busid, "kni")) + kni_cnt++; + } + + if (!kni_cnt) + return 0; + + rte_kni_init(kni_cnt); + + dev_list = rte_malloc(NULL, kni_cnt * sizeof(void *), 0); + + memset(&conf, 0, sizeof(conf)); + memset(&ops, 0, sizeof(ops)); + + ops.change_mtu = kni_change_mtu; + ops.config_network_if = kni_config_network_if; + + for (opt = s->opt; opt; opt = opt->next) { + const char *busid = conf_get_subopt(opt, "busid"); + if (strcmp(busid, "kni")) + continue; + + strcpy(conf.name, opt->name); + conf.group_id = i; + conf.mbuf_size = ETHER_MAX_LEN + 8; + + ops.port_id = i; + + kni = rte_kni_alloc(mbuf_pool, &conf, &ops); + + if (!kni) { + fprintf(stderr, "failed to create %s\n", opt->name); + return -1; + } + + dev = netdev_alloc(opt->name, sizeof(*knidev), NULL); + dev->xmit = knidev_xmit; + knidev = netdev_priv(dev); + knidev->port = i; + knidev->xport = i + x; + knidev->dev = dev; + knidev->kni = kni; + + dev_list[i] = knidev; + + arg.dev = knidev; + arg.opt = opt; + arg.err = -1; + + pthread_create(&tid, NULL, kni_ifconfig, &arg); + + while (arg.err == -1) + rte_kni_handle_request(kni); + + pthread_join(tid, NULL); + + if (arg.err != 0) + return -1; + } + + return 0; +} + diff --git a/accel-dp/kni_dev.h b/accel-dp/kni_dev.h new file mode 100644 index 00000000..78fa448b --- /dev/null +++ b/accel-dp/kni_dev.h @@ -0,0 +1,9 @@ +#ifndef __KNI_DEV_H +#define __KNI_DEV_H + +int kni_dev_count(); +uint16_t kni_dev_rx_burst(uint8_t port_id, uint16_t queue_id, struct rte_mbuf **rx_pkts, const uint16_t nb_pkts); +uint16_t kni_dev_tx_burst(uint8_t port_id, uint16_t queue_id, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); + +#endif + diff --git a/accel-dp/libnetlink.c b/accel-dp/libnetlink.c new file mode 120000 index 00000000..98931f9b --- /dev/null +++ b/accel-dp/libnetlink.c @@ -0,0 +1 @@ +../accel-pppd/libnetlink/libnetlink.c
\ No newline at end of file diff --git a/accel-dp/libnetlink.h b/accel-dp/libnetlink.h new file mode 120000 index 00000000..86c87981 --- /dev/null +++ b/accel-dp/libnetlink.h @@ -0,0 +1 @@ +../accel-pppd/libnetlink/libnetlink.h
\ No newline at end of file diff --git a/accel-dp/list.h b/accel-dp/list.h new file mode 100644 index 00000000..2ffa7f0a --- /dev/null +++ b/accel-dp/list.h @@ -0,0 +1,251 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#undef LIST_HEAD + +//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE) + +//#include <linux/prefetch.h> + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +typedef struct list_head { + struct list_head *next, *prev; +} list_t; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ + +static void inline prefetch(void *p){} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = (void *) 0; + entry->prev = (void *) 0; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +//#endif /* __KERNEL__ || _LVM_H_INCLUDE */ + +#endif diff --git a/accel-dp/log.c b/accel-dp/log.c new file mode 100644 index 00000000..bd0d6bbd --- /dev/null +++ b/accel-dp/log.c @@ -0,0 +1,350 @@ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> +#include <signal.h> +#include <pthread.h> +#include <sys/time.h> + +#include <rte_malloc.h> + +#include "init.h" +#include "common.h" +#include "conf_file.h" + +#include "log.h" + +#define LOG_MSG 0 +#define LOG_ERROR 1 +#define LOG_WARN 2 +#define LOG_INFO1 3 +#define LOG_INFO2 4 +#define LOG_DEBUG 5 + +struct _log_msg { + struct list_head entry; + int level; + struct timeval timestamp; + struct list_head chunks; + unsigned int refs; +}; + +static int log_level; + +static LIST_HEAD(targets); + +static pthread_key_t pth_key; +static __thread struct _log_msg *cur_msg; +static __thread char *stat_buf; + +static FILE *emerg_file; +static FILE *debug_file; + +static void _log_free_msg(struct _log_msg *msg); +static struct log_msg *clone_msg(struct _log_msg *msg); +static int add_msg(struct _log_msg *msg, const char *buf, int len); +static void write_msg(FILE *f, struct _log_msg *msg); + +static void stat_buf_free(void *ptr) +{ + rte_free(ptr); +} + +void log_append(const char *str, int len) +{ + struct log_target *t; + struct log_msg *m; + + if (!cur_msg) + return; + + if (add_msg(cur_msg, str, len)) + goto out; + + if (str[len - 1] != '\n') + return; + + if (debug_file) + write_msg(debug_file, cur_msg); + + list_for_each_entry(t, &targets, entry) { + m = clone_msg(cur_msg); + if (!m) + break; + t->log(m); + } + +out: + _log_free_msg(cur_msg); + cur_msg = NULL; +} + +static void do_log(int level, const char *fmt, va_list ap) +{ + if (!cur_msg) { + cur_msg = rte_malloc(NULL, sizeof(*cur_msg), 0); + if (!cur_msg) + return; + INIT_LIST_HEAD(&cur_msg->chunks); + cur_msg->refs = 1; + cur_msg->level = level; + gettimeofday(&cur_msg->timestamp, NULL); + } + + if (!stat_buf) { + stat_buf = rte_malloc(NULL, LOG_MAX_SIZE + 1, 0); + pthread_setspecific(pth_key, stat_buf); + } + + vsnprintf(stat_buf, LOG_MAX_SIZE, fmt, ap); + log_append(stat_buf, strlen(stat_buf)); +} + +void log_error(const char *fmt,...) +{ + if (log_level >= LOG_ERROR) { + va_list ap; + va_start(ap,fmt); + do_log(LOG_ERROR, fmt, ap); + va_end(ap); + } +} + +void log_warn(const char *fmt,...) +{ + if (log_level >= LOG_WARN) { + va_list ap; + va_start(ap,fmt); + do_log(LOG_WARN, fmt, ap); + va_end(ap); + } +} + +void log_info1(const char *fmt,...) +{ + if (log_level >= LOG_INFO1) { + va_list ap; + va_start(ap, fmt); + do_log(LOG_INFO1, fmt, ap); + va_end(ap); + } +} + +void log_info2(const char *fmt,...) +{ + if (log_level >= LOG_INFO2) { + va_list ap; + va_start(ap, fmt); + do_log(LOG_INFO2, fmt, ap); + va_end(ap); + } +} + +void log_debug(const char *fmt,...) +{ + if (log_level >= LOG_DEBUG) { + va_list ap; + va_start(ap, fmt); + do_log(LOG_DEBUG, fmt, ap); + va_end(ap); + } +} + +void log_debug2(const char *fmt,...) +{ + va_list ap; + if (!debug_file) + return; + va_start(ap, fmt); + vfprintf(debug_file, fmt, ap); + va_end(ap); + fflush(debug_file); +} +void log_msg(const char *fmt,...) +{ + va_list ap; + va_start(ap, fmt); + do_log(LOG_MSG, fmt, ap); + va_end(ap); +} + +void log_emerg(const char *fmt, ...) +{ + if (emerg_file) { + va_list ap; + va_start(ap, fmt); + vfprintf(emerg_file, fmt, ap); + va_end(ap); + fflush(emerg_file); + } +} + +void log_free_msg(struct log_msg *m) +{ + struct _log_msg *msg = (struct _log_msg *)m->lpd; + + //printf("free msg %p\n", m); + + rte_free(m->hdr); + _log_free_msg(msg); + + rte_free(m); +} + + +static void _log_free_msg(struct _log_msg *msg) +{ + struct log_chunk *chunk; + + if (__sync_sub_and_fetch(&msg->refs, 1)) + return; + + while(!list_empty(&msg->chunks)) { + chunk = list_entry(msg->chunks.next, typeof(*chunk), entry); + list_del(&chunk->entry); + rte_free(chunk); + } + + rte_free(msg); +} + +static struct log_msg *clone_msg(struct _log_msg *msg) +{ + struct log_msg *m = rte_malloc(NULL, sizeof(*m), 0); + if (!m) { + log_emerg("log: out of memory\n"); + return NULL; + } + + m->hdr = rte_malloc(NULL, sizeof(*m->hdr), 0); + if (!m->hdr) { + log_emerg("log: out of memory\n"); + rte_free(m); + return NULL; + } + + m->hdr->len = 0; + m->lpd = msg; + m->chunks = &msg->chunks; + m->timestamp = msg->timestamp; + m->level = msg->level; + + __sync_add_and_fetch(&msg->refs, 1); + + //printf("clone msg %p\n", m); + return m; +} + +static int add_msg(struct _log_msg *msg, const char *buf, int len) +{ + struct log_chunk *chunk; + int i, chunk_cnt, n; + + if (!list_empty(&msg->chunks)) { + chunk = list_entry(msg->chunks.prev, typeof(*chunk), entry); + if (chunk->len != LOG_CHUNK_SIZE) { + n = LOG_CHUNK_SIZE - chunk->len; + if (n > len) + n = len; + memcpy(chunk->msg + chunk->len, buf, n); + chunk->len += n; + chunk->msg[chunk->len] = 0; + buf += n; + len -= n; + if (len == 0) + return 0; + } + } + + chunk_cnt = (len - 1)/LOG_CHUNK_SIZE + 1; + + for (i = 0; i < chunk_cnt; i++) { + chunk = rte_malloc(NULL, sizeof(*chunk), 0); + if (!chunk) + return -1; + + chunk->len = i == chunk_cnt -1 ? len - i * LOG_CHUNK_SIZE : LOG_CHUNK_SIZE; + memcpy(chunk->msg, buf + i * LOG_CHUNK_SIZE, chunk->len); + chunk->msg[chunk->len] = 0; + + list_add_tail(&chunk->entry, &msg->chunks); + } + + return 0; +} + +static void write_msg(FILE *f, struct _log_msg *msg) +{ + struct log_chunk *chunk; + + fprintf(f, "[%u.%03u] ", (unsigned)msg->timestamp.tv_sec, (unsigned)msg->timestamp.tv_usec/1000); + + list_for_each_entry(chunk, &msg->chunks, entry) + fwrite(chunk->msg, chunk->len, 1, f); + + fflush(f); +} + +void log_register_target(struct log_target *t) +{ + list_add_tail(&t->entry, &targets); +} + +static void sighup(int n) +{ + struct log_target *t; + + list_for_each_entry(t, &targets, entry) + if (t->reopen) + t->reopen(); +} + +static void config_load(void) +{ + const char *opt; + + opt = conf_get_opt("log", "level"); + if (opt && atoi(opt) >= 0) + log_level = atoi(opt); + + opt = conf_get_opt("log", "log-emerg"); + if (opt) { + if (emerg_file) + emerg_file = freopen(opt, "a", emerg_file); + else + emerg_file = fopen(opt, "a"); + if (!emerg_file) + fprintf(stderr, "log:open: %s\n", strerror(errno)); + } else if (emerg_file) { + fclose(emerg_file); + emerg_file = NULL; + } + + opt = conf_get_opt("log", "log-debug"); + if (opt) { + if (debug_file) + debug_file = freopen(opt, "a", debug_file); + else + debug_file = fopen(opt, "a"); + if (!debug_file) + fprintf(stderr, "log:open: %s\n", strerror(errno)); + } else if (debug_file) { + fclose(debug_file); + debug_file = NULL; + } +} + +static void log_init(void) +{ + pthread_key_create(&pth_key, stat_buf_free); + + config_load(); + + signal(SIGHUP, sighup); +} + +DEFINE_INIT(0, log_init); + diff --git a/accel-dp/log.h b/accel-dp/log.h new file mode 100644 index 00000000..2f4d1b86 --- /dev/null +++ b/accel-dp/log.h @@ -0,0 +1,61 @@ +#ifndef __LOG_H__ +#define __LOG_H__ + +#ifdef MINIMAL +#define log_error(...) fprintf(stderr, __VA_ARGS__) +#define log_warn(...) fprintf(stderr, __VA_ARGS__) +#define log_info1(...) fprintf(stderr, __VA_ARGS__) +#define log_info2(...) fprintf(stderr, __VA_ARGS__) +#define log_debug(...) fprintf(stderr, __VA_ARGS__) +#define log_msg(...) fprintf(stderr, __VA_ARGS__) +#define log_append(...) fprintf(stderr, __VA_ARGS__) +#define log_emerg(...) fprintf(stderr, __VA_ARGS__) +#else + +#include <stdarg.h> +#include <sys/time.h> +#include "list.h" + +#define LOG_MAX_SIZE 4096 +#define LOG_CHUNK_SIZE 128 + +struct log_msg { + struct list_head entry; + struct timeval timestamp; + void *lpd; + int level; + struct log_chunk *hdr; + struct list_head *chunks; +}; + +struct log_chunk { + struct list_head entry; + int len; + char msg[0]; +}; + +struct log_target { + struct list_head entry; + + void (*log)(struct log_msg *); + void (*reopen)(void); +}; + +void log_free_msg(struct log_msg *msg); + +void log_emerg(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); + +void log_error(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); +void log_warn(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); +void log_info1(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); +void log_info2(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); +void log_debug(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); +void log_msg(const char *fmt, ...) __attribute__((format(gnu_printf, 1, 2))); +void log_append(const char *str, int len); + +#define log_ppp_error(...) log_error(__VA_ARGS__) + +void log_register_target(struct log_target *t); +#endif + +#endif diff --git a/accel-dp/log_file.c b/accel-dp/log_file.c new file mode 100644 index 00000000..395e24c0 --- /dev/null +++ b/accel-dp/log_file.c @@ -0,0 +1,246 @@ +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <aio.h> +#include <signal.h> +#include <pthread.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/uio.h> + +#include "init.h" +#include "common.h" +#include "conf_file.h" + +#include "log.h" + +//static const char* level_name[]={" msg", "error", " warn", " info", " info", "debug"}; +static int log_fd = -1; +static int conf_buf_size; + +#define THREADED_LOG_FILE + +#ifdef THREADED_LOG_FILE +static LIST_HEAD(log_queue); +static LIST_HEAD(log_buf); +static int buf_size; +static int buf_cnt; +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond; +static pthread_t thr; +static int need_reopen; +#endif + +static void make_hdr(struct log_msg *msg) +{ + struct tm tm; + + tm = *localtime(&msg->timestamp.tv_sec); + + msg->hdr->len = sprintf(msg->hdr->msg, "[%i-%02i-%02i %02i:%02i:%02i]: ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec/*, (int)msg->timestamp.tv_usec/100000*/); +} + +/*static void __log(struct log_msg *msg) +{ + struct log_chunk *chunk; + struct iovec iov[IOV_MAX]; + int iov_cnt; + struct list_head *pos = msg->chunks->next; + + make_hdr(msg); + + iov[0].iov_base = msg->hdr->msg; + iov[0].iov_len = msg->hdr->len; + iov_cnt = 1; + + while (pos != msg->chunks) { + chunk = list_entry(pos, typeof(*chunk), entry); + iov[iov_cnt].iov_base = chunk->msg; + iov[iov_cnt].iov_len = chunk->len; + iov_cnt++; + pos = pos->next; + + if (iov_cnt == IOV_MAX || pos == msg->chunks) { + writev(log_fd, iov, iov_cnt); + iov_cnt = 0; + } + } + + log_free_msg(msg); +}*/ + +static void write_buf() +{ + struct log_msg *msg; + struct log_chunk *chunk; + struct iovec iov[IOV_MAX]; + int n = 0; + + list_for_each_entry(msg, &log_buf, entry) { + iov[n].iov_base = msg->hdr->msg; + iov[n].iov_len = msg->hdr->len; + n++; + + list_for_each_entry(chunk, msg->chunks, entry) { + iov[n].iov_base = chunk->msg; + iov[n].iov_len = chunk->len; + n++; + + if (n >= IOV_MAX - 2) { + writev(log_fd, iov, n); + n = 0; + } + } + } + + if (n) + writev(log_fd, iov, n); + + while (!list_empty(&log_buf)) { + msg = list_entry(log_buf.next, typeof(*msg), entry); + list_del(&msg->entry); + log_free_msg(msg); + } + + buf_size = 0; + buf_cnt = 0; +} + +static void do_log(struct log_msg *msg) +{ +#ifndef THREADED_LOG_FILE + struct log_chunk *chunk; +#endif + + if (log_fd < 0 || msg->level == 5) { + log_free_msg(msg); + return; + } + + make_hdr(msg); + +#ifdef THREADED_LOG_FILE + pthread_mutex_lock(&lock); + list_add_tail(&msg->entry, &log_queue); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); +#else + buf_cnt++; + buf_size += msg->hdr->len; + + list_for_each_entry(chunk, msg->chunks, entry) { + buf_size += chunk->len; + buf_cnt++; + } + + if (buf_cnt > IOV_MAX - 16 || buf_size >= conf_buf_size) + write_buf(); +#endif +} + +static void __reopen(void) +{ + const char *fname = conf_get_opt("log", "log-file"); + + if (log_fd >= 0) { + close(log_fd); + log_fd = -1; + } + + if (!fname) + return; + + log_fd = open(fname, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); + if (log_fd < 0) { + log_emerg("log_file: open '%s': %s\n", fname, strerror(errno)); + return; + } + + fcntl(log_fd, F_SETFD, FD_CLOEXEC); +} + +static void reopen(void) +{ +#ifdef THREADED_LOG_FILE + pthread_mutex_lock(&lock); + need_reopen = 1; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); +#else + __reopen(); +#endif +} + +#ifdef THREADED_LOG_FILE +static void *log_thread(void *ignored) +{ + struct log_msg *msg; + struct log_chunk *chunk; + + pthread_mutex_lock(&lock); + while (1) { + if (need_reopen) { + need_reopen = 0; + __reopen(); + } + while (!list_empty(&log_queue)) { + msg = list_entry(log_queue.next, typeof(*msg), entry); + list_move_tail(&msg->entry, &log_buf); + + buf_cnt++; + buf_size += msg->hdr->len; + + list_for_each_entry(chunk, msg->chunks, entry) { + buf_size += chunk->len; + buf_cnt++; + } + + if (buf_cnt > IOV_MAX - 16 || buf_size >= conf_buf_size) { + pthread_mutex_unlock(&lock); + write_buf(); + pthread_mutex_lock(&lock); + } + } + pthread_cond_wait(&cond, &lock); + } + pthread_mutex_unlock(&lock); + + return NULL; +} +#endif + +static struct log_target target = { + .log = do_log, + .reopen = reopen, +}; + +static void load_config() +{ + const char *opt = conf_get_opt("log", "buffer"); + if (opt) + conf_buf_size = atoi(opt); + else + conf_buf_size = 0; +} + +static void init(void) +{ + if (!conf_get_opt("log", "log-file")) + return; + + load_config(); + + log_register_target(&target); + reopen(); + +#ifdef THREADED_LOG_FILE + pthread_cond_init(&cond, NULL); + pthread_create(&thr, NULL, log_thread, NULL); +#endif +} + +DEFINE_INIT(2, init); diff --git a/accel-dp/main.c b/accel-dp/main.c new file mode 100644 index 00000000..bdf81632 --- /dev/null +++ b/accel-dp/main.c @@ -0,0 +1,378 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/resource.h> +#include <sys/socket.h> + +#include <rte_config.h> +#include <rte_memory.h> +#include <rte_memzone.h> +#include <rte_launch.h> +#include <rte_eal.h> +#include <rte_per_lcore.h> +#include <rte_lcore.h> +#include <rte_ethdev.h> +#include <rte_log.h> +#include <rte_errno.h> +#include <rte_debug.h> + +#include "init.h" +#include "conf_file.h" +#include "event.h" + +#define RTE_LOGTYPE_INIT RTE_LOGTYPE_USER1 +#define MBUF_CACHE_SIZE 128 + +int sock_fd; + +static struct rte_mempool *mbuf_pool; + +static LIST_HEAD(init_list); + +struct init { + struct list_head entry; + + int order; + void (*func)(void); +}; + +void register_init(int order, void (*func)(void)) +{ + struct init *i1, *i = malloc(sizeof(*i)); + struct list_head *p = init_list.next; + + i->order = order; + i->func = func; + + while (p != &init_list) { + i1 = list_entry(p, typeof(*i1), entry); + if (order < i1->order) + break; + p = p->next; + } + list_add_tail(&i->entry, p); +} + +static void run_init(void) +{ + struct init *i; + + list_for_each_entry(i, &init_list, entry) + i->func(); +} + +static void change_limits(void) +{ + FILE *f; + struct rlimit lim; + unsigned int nr_open = 1024*1024; + + f = fopen("/proc/sys/fs/nr_open", "r"); + if (f) { + fscanf(f, "%d", &nr_open); + fclose(f); + } + + lim.rlim_cur = nr_open; + lim.rlim_max = nr_open; + setrlimit(RLIMIT_NOFILE, &lim); +} + +static int bind_driver(const char *opt, char **val) +{ + char *ptr = strchr(opt, ':'); + char drv[128]; + int fd, r; + char fname[1024]; + char bus_id[64]; + struct stat st; + char vendor[16], device[16]; + + if (!ptr) + return -1; + + if (strchr(ptr + 1, ':')) { + memcpy(drv, opt, ptr - opt); + drv[ptr - opt] = 0; + opt = ptr + 1; + } else + strcpy(drv, "uio_pci_generic"); + + sprintf(bus_id, "0000:%s", opt); + + sprintf(fname, "/sys/bus/pci/devices/%s", bus_id); + if (stat(fname, &st)) { + fprintf(stderr, "%s: device not found\n", opt); + return -1; + } + + sprintf(fname, "/sys/bus/pci/devices/%s/vendor", bus_id); + fd = open(fname, O_RDONLY); + r = read(fd, vendor, sizeof(vendor)); + if (r <= 0) { + fprintf(stderr, "%s: failed to read vendor\n", opt); + close(fd); + return -1; + } + vendor[r - 1] = 0; + close(fd); + + sprintf(fname, "/sys/bus/pci/devices/%s/device", bus_id); + fd = open(fname, O_RDONLY); + r = read(fd, device, sizeof(device)); + if (r <= 0) { + fprintf(stderr, "%s: failed to read device\n", opt); + close(fd); + return -1; + } + device[r - 1] = 0; + close(fd); + + sprintf(fname, "modprobe -q %s", drv); + system(fname); + + sprintf(fname, "/sys/bus/pci/drivers/%s", drv); + if (stat(fname, &st)) { + fprintf(stderr, "%s: driver '%s' is not loaded\n", opt, drv); + return -1; + } + + sprintf(fname, "/sys/bus/pci/devices/%s/driver", bus_id); + + r = readlink(fname, fname, sizeof(fname)); + if (r > 0) { + fname[r] = 0; + ptr = fname + r - 1; + while (*ptr != '/') + ptr--; + + if (strcmp(ptr + 1, drv)) { + fprintf(stderr, "%s: unbind driver: %s\n", opt, ptr + 1); + + sprintf(fname, "/sys/bus/pci/devices/%s/driver/unbind", bus_id); + + fd = open(fname, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "%s: failed to unbind driver: %s\n", opt, strerror(errno)); + return -1; + } + + if (write(fd, bus_id, strlen(bus_id)) < 0) { + fprintf(stderr, "%s: failed to unbind driver: %s\n", opt, strerror(errno)); + close(fd); + return -1; + } + close(fd); + } else + goto out; + } + + sprintf(fname, "/sys/bus/pci/drivers/%s/new_id", drv); + fd = open(fname, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "%s: failed to bind driver %s: %s\n", opt, drv, strerror(errno)); + return -1; + } + + sprintf(fname, "%s %s", vendor, device); + if (write(fd, fname, strlen(fname)) < 0) { + fprintf(stderr, "%s: failed to bind driver %s: %s\n", opt, drv, strerror(errno)); + close(fd); + return -1; + } + close(fd); + + /*sprintf(fname, "/sys/bus/pci/drivers/%s/bind", drv); + fd = open(fname, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "%s: failed to bind driver %s: %s\n", opt, drv, strerror(errno)); + close(fd); + return -1; + } + + if (write(fd, bus_id, strlen(bus_id)) < 0) { + fprintf(stderr, "%s: failed to bind driver %s: %s\n", opt, drv, strerror(errno)); + close(fd); + return -1; + } + close(fd);*/ + +out: + *val = (char *)opt; + return 0; +} + +static int build_rte_args(char **argv) +{ + int i = 0; + struct conf_sect *s = conf_get_sect("core"); + struct conf_opt *opt; + + if (!s) + return 0; + + for (opt = s->opt; opt; opt = opt->next) { + if (!strcmp(opt->name, "coremask")) { + argv[i++] = "-c"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "corelist")) { + argv[i++] = "-l"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "coremap")) { + argv[i++] = "--lcores"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "master-lcore")) { + argv[i++] = "--master-lcore"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "mem-channels")) { + argv[i++] = "-n"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "mem-ranks")) { + argv[i++] = "-r"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "socket-mem")) { + argv[i++] = "-m"; + argv[i++] = opt->val; + } else if (!strcmp(opt->name, "huge-dir")) { + argv[i++] = "--huge-dir"; + argv[i++] = opt->val; + } + } + + s = conf_get_sect("interface"); + + for (opt = s->opt; opt; opt = opt->next) { + const char *busid = conf_get_subopt(opt, "busid"); + if (!busid) { + fprintf(stderr, "%s: busid not specified\n", opt->name); + return -1; + } + + if (strcmp(busid, "kni")) { + if (bind_driver(busid, &argv[i + 1])) + return -1; + argv[i++] = "-w"; + i++; + } + } + + return i; +} + +static int init_pktmbuf_pool() +{ + int mbuf_cnt = 16*1024; + const char *opt = conf_get_opt("core", "mbuf-count"); + + if (opt) + mbuf_cnt = atoi(opt); + + mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", mbuf_cnt, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + if (!mbuf_pool) { + fprintf(stderr, "%s\n", rte_strerror(rte_errno)); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + unsigned lcore_id; + int i; + char *cf = NULL; + char *pid_file = NULL; + int goto_daemon = 0; + int rte_argc; + char *rte_argv[256]; + const char *opt; + int dist_lcore; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-c") && i + 1 < argc) + cf = argv[++i]; + else if (!strcmp(argv[i], "-p") && i + 1 < argc) + pid_file = argv[++i]; + else if (!strcmp(argv[i], "-d")) + goto_daemon = 1; + } + + if (!cf) { + printf("usage: accel-dpdk [-d] [-p <pid file>] -c <config file>\n"); + return 1; + } + + if (conf_load(cf)) + return 1; + + rte_argv[0] = argv[0]; + rte_argc = build_rte_args(rte_argv + 1) + 1; + if (rte_argc == 0) + return 1; + + if (rte_eal_init(rte_argc, rte_argv) < 0) { + fprintf(stderr, "Cannot init EAL\n"); + return 1; + } + + if (init_pktmbuf_pool()) + return -1; + + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + + run_init(); + + if (ctrl_init()) + return 1; + + if (eth_dev_init(mbuf_pool)) + return -1; + + if (kni_dev_init(mbuf_pool)) + return -1; + + opt = conf_get_opt("core", "distributor-lcore"); + if (opt) + dist_lcore = atoi(opt); + else + dist_lcore = -1; + + if (distributor_init(dist_lcore != -1)) + return -1; + + if (goto_daemon) + daemon(0, 0); + + change_limits(); + + if (pid_file) { + FILE *f = fopen(pid_file, "w"); + if (f) { + fprintf(f, "%i", getpid()); + fclose(f); + } + } + + /* call lcore_hello() on every slave lcore */ + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + printf("%i\n", lcore_id); + if (lcore_id == dist_lcore) + rte_eal_remote_launch(lcore_distributor, NULL, lcore_id); + else + rte_eal_remote_launch(lcore_worker, NULL, lcore_id); + } + + if (dist_lcore == -1) + distributor_loop(1); + else + event_loop(); + + rte_eal_mp_wait_lcore(); + return 0; +} diff --git a/accel-dp/sock.h b/accel-dp/sock.h new file mode 100644 index 00000000..0bff811d --- /dev/null +++ b/accel-dp/sock.h @@ -0,0 +1,40 @@ +#ifndef __SOCK_H +#define __SOCK_H + +#include "event.h" + +#define SOCK_BUF_SIZE 1024 + +#define PF_PPP 255 + +struct sock; + +struct proto_ops { + int (*socket)(struct sock *sk, int type, int proto); + int (*bind)(struct sock *sk, const struct sockaddr *addr, socklen_t addrlen); + int (*listen)(struct sock *sk, int backlog); + int (*connect)(struct sock *sk, const struct sockaddr *addr, socklen_t addrlen); + int (*recv)(struct sock *sk, size_t len, int flags, socklen_t addrlen); + int (*send)(struct sock *sk, void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen); + int (*ioctl)(struct sock *sk, unsigned long request, void *arg); + void (*close)(struct sock *sk); +}; + +struct msg_result; + +struct sock { + struct event_handler hnd; + void *priv; + struct msg_result *res; + const struct proto_ops *ops; +}; + +int sock_errno(struct sock *sk, int err); + +int sock_no_listen(struct sock *sk, int backlog); +int sock_no_connect(struct sock *sk, const struct sockaddr *addr, socklen_t addrlen); +int sock_no_ioctl(struct sock *sk, unsigned long request, void *arg); + +void sock_register_proto(int domain, int type, int proto, const struct proto_ops *ops); + +#endif |