int hyper_setup_netlink_listener(struct hyper_event *e) { int fd; struct sockaddr_nl sa; memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; sa.nl_groups = 0xffffffff; fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT); if (fd < 0) { perror("failed to create netlink socket"); return -1; } if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { perror("failed to bind netlink socket"); close(fd); return -1; } e->fd = fd; if (hyper_init_event(e, &hyper_devfd_ops, NULL) < 0) { hyper_reset_event(e); return -1; } return 0; }
int hyper_add_event(int efd, struct hyper_event *de) { struct epoll_event event = { .events = EPOLLIN, .data.ptr = de, }; if (hyper_setfd_nonblock(de->fd) < 0) { perror("set fd nonblock failed"); return -1; } fprintf(stdout, "%s add event fd %d, %p\n", __func__, de->fd, de->ops); if (epoll_ctl(efd, EPOLL_CTL_ADD, de->fd, &event) < 0) { perror("epoll_ctl fd failed"); return -1; } return 0; } void hyper_event_hup(struct hyper_event *de, int efd) { if (epoll_ctl(efd, EPOLL_CTL_DEL, de->fd, NULL) < 0) perror("epoll_ctl del epoll event failed"); close(de->fd); hyper_reset_event(de); } int hyper_handle_event(int efd, struct epoll_event *event) { struct hyper_event *de = event->data.ptr; if (event->events & EPOLLHUP) { fprintf(stdout, "%s event EPOLLHUP, de %p, fd %d, %p\n", __func__, de, de->fd, de->ops); if (de->ops->hup) de->ops->hup(de, efd); return 0; } else if (event->events & EPOLLIN) { return de->ops->read(de); } else if (event->events & EPOLLERR) { fprintf(stderr, "get epoll err of not epool in event\n"); return -1; } fprintf(stdout, "%s get unknown event %d\n", __func__, event->events); return -1; }
int hyper_start_container(struct hyper_container *container, int utsns, int ipcns, struct hyper_pod *pod) { int stacksize = getpagesize() * 4; struct hyper_container_arg arg = { .c = container, .utsns = utsns, .ipcns = ipcns, .pipe = {-1, -1}, }; int flags = CLONE_NEWNS | SIGCHLD; char path[128]; uint32_t type; void *stack; int pid; if (container->image == NULL || container->exec.argv == NULL) { fprintf(stdout, "container root image %s, argv %p\n", container->image, container->exec.argv); goto fail; } if (hyper_setup_pty(container) < 0) { fprintf(stderr, "setup pty device for container failed\n"); goto fail; } if (pipe2(arg.pipe, O_CLOEXEC) < 0) { perror("create pipe between pod init execcmd failed"); goto fail; } if (hyper_watch_exec_pty(&container->exec, pod) < 0) { fprintf(stderr, "faile to watch container pty\n"); goto fail; } stack = malloc(stacksize); if (stack == NULL) { perror("fail to allocate stack for container init"); goto fail; } pid = clone(hyper_container_init, stack + stacksize, flags, &arg); free(stack); if (pid < 0) { perror("create child process failed"); goto fail; } sprintf(path, "/proc/%d/ns/mnt", pid); container->ns = open(path, O_RDONLY | O_CLOEXEC); if (container->ns < 0) { perror("open container mount ns failed"); goto fail; } /* wait for ready message */ if (hyper_get_type(arg.pipe[0], &type) < 0 || type != READY) { fprintf(stderr, "wait for container started failed\n"); goto fail; } container->exec.pid = pid; list_add_tail(&container->exec.list, &pod->exec_head); container->exec.ref++; close(arg.pipe[0]); close(arg.pipe[1]); fprintf(stdout, "container %s,init pid %d,ref %d\n", container->id, pid, container->exec.ref); return 0; fail: close(arg.pipe[0]); close(arg.pipe[1]); close(container->ns); hyper_reset_event(&container->exec.e); hyper_reset_event(&container->exec.errev); container->ns = -1; fprintf(stdout, "container %s init exit code %d\n", container->id, -1); container->exec.code = -1; container->exec.seq = 0; container->exec.ref = 0; return -1; }
int hyper_add_event(int efd, struct hyper_event *de, int flag) { struct epoll_event event = { .events = flag, .data.ptr = de, }; de->flag = flag; if (hyper_setfd_nonblock(de->fd) < 0) { perror("set fd nonblock failed"); return -1; } fprintf(stdout, "%s add event fd %d, %p\n", __func__, de->fd, de->ops); if (epoll_ctl(efd, EPOLL_CTL_ADD, de->fd, &event) < 0) { perror("epoll_ctl fd failed"); return -1; } return 0; } int hyper_modify_event(int efd, struct hyper_event *de, int flag) { struct epoll_event event = { .events = flag, .data.ptr = de, }; if (de->flag == flag) return 0; de->flag = flag; fprintf(stdout, "%s modify event fd %d, %p, event %d\n", __func__, de->fd, de, flag); if (epoll_ctl(efd, EPOLL_CTL_MOD, de->fd, &event) < 0) { perror("epoll_ctl fd failed"); return -1; } return 0; } static int hyper_getmsg_len(struct hyper_event *de, uint32_t *len) { struct hyper_buf *buf = &de->rbuf; if (buf->get < de->ops->len_offset + 4) return -1; *len = hyper_get_be32(buf->data + de->ops->len_offset); return 0; } int hyper_event_read(struct hyper_event *de, int efd) { struct hyper_buf *buf = &de->rbuf; uint32_t len = 4; uint8_t data[4]; int offset = de->ops->len_offset; int end = offset + 4; int size; fprintf(stdout, "%s\n", __func__); while (hyper_getmsg_len(de, &len) < 0) { size = read(de->fd, buf->data + buf->get, end - buf->get); if (size > 0) { buf->get += size; fprintf(stdout, "already read %" PRIu32 " bytes data\n", buf->get); if (de->ops->ack) { /* control channel, need ack */ hyper_set_be32(data, size); hyper_send_msg(de->fd, NEXT, 4, data); } continue; } if (errno == EINTR) continue; if (errno != EAGAIN && size != 0) { perror("fail to read"); return -1; } return 0; } fprintf(stdout, "get length %" PRIu32"\n", len); if (len > buf->size) { fprintf(stderr, "get length %" PRIu32", too long\n", len); return -1; } while (buf->get < len) { size = read(de->fd, buf->data + buf->get, len - buf->get); if (size > 0) { buf->get += size; fprintf(stdout, "read %d bytes data, total data %" PRIu32 "\n", size, buf->get); if (de->ops->ack) { /* control channel, need ack */ hyper_set_be32(data, size); hyper_send_msg(de->fd, NEXT, 4, data); } continue; } if (errno == EINTR) continue; if (errno != EAGAIN && size != 0) { perror("fail to read"); return -1; } /* size == 0 : No one connect to qemu socket */ return 0; } /* get the whole data */ if (de->ops->handle(de, len) != 0) return -1; /* len: length of the already get new data */ buf->get -= len; memmove(buf->data, buf->data + len, buf->get); return 0; } int hyper_event_write(struct hyper_event *de) { struct hyper_buf *buf = &de->wbuf; uint32_t len = 0; int size = 0; while (len < buf->get) { size = write(de->fd, buf->data + len, buf->get - len); if (size <= 0) { if (errno == EINTR) continue; if (errno == EAGAIN || size == 0) break; return -1; } len += size; } buf->get -= len; memmove(buf->data, buf->data + len, buf->get); if (buf->get == 0) { hyper_modify_event(ctl.efd, de, EPOLLIN); } return 0; } void hyper_event_hup(struct hyper_event *de, int efd) { if (epoll_ctl(efd, EPOLL_CTL_DEL, de->fd, NULL) < 0) perror("epoll_ctl del epoll event failed"); hyper_reset_event(de); } int hyper_handle_event(int efd, struct epoll_event *event) { struct hyper_event *de = event->data.ptr; fprintf(stdout, "%s get event %d, de %p, fd %d. ops %p\n", __func__, event->events, de, de->fd, de->ops); /* do not handle hup event if have in event */ if ((event->events & EPOLLIN) && de->ops->read) { fprintf(stdout, "%s event EPOLLIN, de %p, fd %d, %p\n", __func__, de, de->fd, de->ops); if (de->ops->read && de->ops->read(de, efd) < 0) return -1; } else if (event->events & EPOLLHUP) { fprintf(stdout, "%s event EPOLLHUP, de %p, fd %d, %p\n", __func__, de, de->fd, de->ops); if (de->ops->hup) de->ops->hup(de, efd); return 0; } if (event->events & EPOLLOUT) { fprintf(stdout, "%s event EPOLLOUT, de %p, fd %d, %p\n", __func__, de, de->fd, de->ops); if (de->ops->write && de->ops->write(de) < 0) return -1; } if (event->events & EPOLLERR) { fprintf(stderr, "get epoll err of not epool in event\n"); if (de->ops->hup) de->ops->hup(de, efd); return 0; } return 0; }