static struct snobj *queue_out_init(struct module *m, struct snobj *arg) { struct queue_out_priv *priv = get_priv(m); struct snobj *t; const char *port_name; int ret; if (!arg || snobj_type(arg) != TYPE_MAP) return snobj_err(EINVAL, "Argument must be a map"); t = snobj_eval(arg, "port"); if (!t || !(port_name = snobj_str_get(t))) return snobj_err(EINVAL, "Field 'port' must be specified"); t = snobj_eval(arg, "qid"); if (!t || snobj_type(t) != TYPE_INT) return snobj_err(EINVAL, "Field 'qid' must be specified"); priv->qid = snobj_uint_get(t); priv->port = find_port(port_name); if (!priv->port) return snobj_err(ENODEV, "Port %s not found", port_name); ret = acquire_queues(priv->port, m, PACKET_DIR_OUT, &priv->qid, 1); if (ret < 0) return snobj_errno(-ret); priv->send_pkts = priv->port->driver->send_pkts; return NULL; }
static struct snobj *set_ip_addr(struct port *p, int container_pid, struct snobj *arg) { int child_pid; int ret = 0; if (snobj_type(arg) == TYPE_STR || snobj_type(arg) == TYPE_LIST) { if (snobj_type(arg) == TYPE_LIST) { if (arg->size == 0) goto invalid_type; for (int i = 0; i < arg->size; i++) { struct snobj *addr = snobj_list_get(arg, i); if (snobj_type(addr) != TYPE_STR) goto invalid_type; } } } else goto invalid_type; /* change network namespace if necessary */ if (container_pid) { child_pid = fork(); if (child_pid < 0) return snobj_errno(-child_pid); if (child_pid == 0) { char buf[1024]; int fd; sprintf(buf, "/proc/%d/ns/net", container_pid); fd = open(buf, O_RDONLY); if (fd < 0) { perror("open(/proc/pid/ns/net)"); exit(errno <= 255 ? errno: ENOMSG); } ret = setns(fd, 0); if (ret < 0) { perror("setns()"); exit(errno <= 255 ? errno: ENOMSG); } } else goto wait_child; } switch (snobj_type(arg)) { case TYPE_STR: ret = set_ip_addr_single(p, snobj_str_get(arg)); if (ret < 0) { if (container_pid) { /* it must be the child */ assert(child_pid == 0); exit(errno <= 255 ? errno: ENOMSG); } } break; case TYPE_LIST: if (!arg->size) goto invalid_type; for (int i = 0; i < arg->size; i++) { struct snobj *addr = snobj_list_get(arg, i); ret = set_ip_addr_single(p, snobj_str_get(addr)); if (ret < 0) { if (container_pid) { /* it must be the child */ assert(child_pid == 0); exit(errno <= 255 ? errno: ENOMSG); } else break; } } break; default: assert(0); } if (container_pid) { if (child_pid == 0) { if (ret < 0) { ret = -ret; exit(ret <= 255 ? ret: ENOMSG); } else exit(0); } else { int exit_status; wait_child: ret = waitpid(child_pid, &exit_status, 0); if (ret >= 0) { assert(ret == child_pid); ret = -WEXITSTATUS(exit_status); } else perror("waitpid()"); } } if (ret < 0) return snobj_err_details(-ret, arg, "Failed to set IP addresses " \ "(incorrect IP address format?)"); return NULL; invalid_type: return snobj_err(EINVAL, "'ip_addr' must be a string or list " \ "of IPv4/v6 addresses (e.g., '10.0.20.1/24')"); }