static struct snobj *handle_list_ports(struct snobj *q) { struct snobj *r; int cnt = 1; int offset; r = snobj_list(); for (offset = 0; cnt != 0; offset += cnt) { const int arr_size = 16; const struct port *ports[arr_size]; int i; cnt = list_ports(ports, arr_size, offset); for (i = 0; i < cnt; i++) { struct snobj *port = snobj_map(); snobj_map_set(port, "name", snobj_str(ports[i]->name)); snobj_map_set(port, "driver", snobj_str(ports[i]->driver->name)); snobj_list_add(r, port); } }; return r; }
static struct snobj *handle_get_module_info(struct snobj *arg) { const char *m_name; struct module *m; struct snobj *r; struct snobj *gates; m_name = snobj_str_get(arg); if (!m_name) return snobj_err(EINVAL, "Argument must be a name in str"); if ((m = find_module(m_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m_name); r = snobj_map(); gates = snobj_list(); snobj_map_set(r, "name", snobj_str(m->name)); snobj_map_set(r, "mclass", snobj_str(m->mclass->name)); if (m->mclass->get_desc) snobj_map_set(r, "desc", m->mclass->get_desc(m)); if (m->mclass->get_dump) snobj_map_set(r, "dump", m->mclass->get_dump(m)); for (int i = 0; i < m->allocated_gates; i++) { if (m->gates[i].m) { struct snobj *gate = snobj_map(); snobj_map_set(gate, "gate", snobj_uint(i)); #if TRACK_GATES snobj_map_set(gate, "cnt", snobj_uint(m->gates[i].cnt)); snobj_map_set(gate, "pkts", snobj_uint(m->gates[i].pkts)); snobj_map_set(gate, "timestamp", snobj_double(get_epoch_time())); #endif snobj_map_set(gate, "name", snobj_str(m->gates[i].m->name)); snobj_list_add(gates, gate); } } snobj_map_set(r, "gates", gates); return r; }
static struct snobj *handle_create_module(struct snobj *arg) { const char *mclass_name; const struct mclass *mclass; struct module *module; struct snobj *r; mclass_name = snobj_eval_str(arg, "mclass"); if (!mclass_name) return snobj_err(EINVAL, "Missing 'mclass' field in arg"); mclass = find_mclass(mclass_name); if (!mclass) return snobj_err(ENOENT, "No mclass '%s' found", mclass_name); module = create_module(snobj_eval_str(arg, "name"), mclass, snobj_eval(arg, "arg"), &r); if (!module) return r; printf("Module %s created at %p\n", module->name, module); r = snobj_map(); snobj_map_set(r, "name", snobj_str(module->name)); return r; }
static struct snobj *handle_create_port(struct snobj *arg) { const char *driver_name; const struct driver *driver; struct port *port; struct snobj *r; struct snobj *err; driver_name = snobj_eval_str(arg, "driver"); if (!driver_name) return snobj_err(EINVAL, "Missing 'driver' field in arg"); driver = find_driver(driver_name); if (!driver) return snobj_err(ENOENT, "No port driver '%s' found", driver_name); port = create_port(snobj_eval_str(arg, "name"), driver, snobj_eval(arg, "arg"), &err); if (!port) return err; printf("Port %s created at %p\n", port->name, port); r = snobj_map(); snobj_map_set(r, "name", snobj_str(port->name)); return r; }
static struct snobj *handle_list_modules(struct snobj *q) { struct snobj *r; int cnt = 1; int offset; r = snobj_list(); for (offset = 0; cnt != 0; offset += cnt) { const int arr_size = 16; const struct module *modules[arr_size]; int i; cnt = list_modules(modules, arr_size, offset); for (i = 0; i < cnt; i++) { const struct module *m = modules[i]; const struct mclass *mclass = m->mclass; struct snobj *module = snobj_map(); snobj_map_set(module, "name", snobj_str(m->name)); snobj_map_set(module, "mclass", snobj_str(mclass->name)); if (mclass->get_desc) { snobj_map_set(module, "desc", mclass->get_desc(m)); } snobj_list_add(r, module); } }; return r; }
static struct snobj *docker_container_pid(char *cid, int *container_pid) { char buf[1024]; FILE *fp; int ret; int exit_code; if (!cid) return snobj_err(EINVAL, "field 'docker' should be " \ "a containder ID or name in string"); ret = snprintf(buf, sizeof(buf), "docker inspect --format '{{.State.Pid}}' " \ "%s 2>&1", cid); if (ret >= sizeof(buf)) return snobj_err(EINVAL, "The specified Docker " \ "container ID or name is too long"); fp = popen(buf, "r"); if (!fp) return snobj_err_details(ESRCH, snobj_str_fmt("popen() errno=%d (%s)", errno, strerror(errno)), "Command 'docker' is not available. " \ "(not installed?)"); ret = fread(buf, 1, sizeof(buf) - 1, fp); if (ret == 0) return snobj_err(ENOENT, "Cannot find the PID of " \ "container %s", cid); buf[ret] = '\0'; ret = pclose(fp); exit_code = WEXITSTATUS(ret); if (exit_code != 0 || sscanf(buf, "%d", container_pid) == 0) { struct snobj *details = snobj_map(); snobj_map_set(details, "exit_code", snobj_int(exit_code)); snobj_map_set(details, "docker_err", snobj_str(buf)); return snobj_err_details(ESRCH, details, "Cannot find the PID of container %s", cid); } return NULL; }
struct snobj *handle_request(struct client *c, struct snobj *q) { struct snobj *r = NULL; const char *s; #if 0 printf("Request:\n"); snobj_dump(q); #endif if (q->type != TYPE_MAP) { r = snobj_err(EINVAL, "The message must be a map"); goto reply; } s = snobj_eval_str(q, "to"); if (!s) { r = snobj_str("There is no 'to' field"); goto reply; } if (strcmp(s, "softnic") == 0) { r = handle_snobj_softnic(q); } else if (strcmp(s, "module") == 0) { r = handle_snobj_module(q); } else r = snobj_err(EINVAL, "Unknown destination in 'to': %s", s); reply: /* No response was made? (normally means "success") */ if (!r) r = snobj_nil(); #if 0 printf("Response:\n"); snobj_dump(r); #endif return r; }
static struct snobj *handle_list_drivers(struct snobj *q) { struct snobj *r; int cnt = 1; int offset; r = snobj_list(); for (offset = 0; cnt != 0; offset += cnt) { const int arr_size = 16; const struct driver *drivers[arr_size]; int i; cnt = list_drivers(drivers, arr_size, offset); for (i = 0; i < cnt; i++) snobj_list_add(r, snobj_str(drivers[i]->name)); }; return r; }
static struct snobj *init_port(struct port *p, struct snobj *conf) { struct vport_priv *priv = get_port_priv(p); int container_pid = 0; int cpu; int rxq; int ret; if (strlen(p->name) >= IFNAMSIZ) return snobj_err(EINVAL, "Linux interface name should be " \ "shorter than %d characters", IFNAMSIZ); if (snobj_eval_exists(conf, "docker")) { struct snobj *err = docker_container_pid( snobj_eval_str(conf, "docker"), &container_pid); if (err) return err; } priv->fd = open("/dev/softnic", O_RDONLY); if (priv->fd == -1) return snobj_err(ENODEV, "the kernel module is not loaded"); priv->bar = alloc_bar(p, container_pid); ret = ioctl(priv->fd, SN_IOC_CREATE_HOSTNIC, rte_malloc_virt2phy(priv->bar)); if (ret < 0) { close(priv->fd); return snobj_errno_details(-ret, snobj_str("SN_IOC_CREATE_HOSTNIC failure")); } if (snobj_eval_exists(conf, "ip_addr")) { struct snobj *err = set_ip_addr(p, container_pid, snobj_eval(conf, "ip_addr")); if (err) { deinit_port(p); return err; } } for (cpu = 0; cpu < SN_MAX_CPU; cpu++) priv->map.cpu_to_txq[cpu] = cpu % p->num_queues[PACKET_DIR_INC]; cpu = 0; for (rxq = 0; rxq < p->num_queues[PACKET_DIR_OUT]; rxq++) { while (is_worker_core(cpu)) cpu = (cpu + 1) % sysconf(_SC_NPROCESSORS_ONLN); priv->map.rxq_to_cpu[rxq] = cpu; cpu = (cpu + 1) % sysconf(_SC_NPROCESSORS_ONLN); } ret = ioctl(priv->fd, SN_IOC_SET_QUEUE_MAPPING, &priv->map); if (ret < 0) perror("SN_IOC_SET_QUEUE_MAPPING"); return NULL; }
static struct snobj *handle_list_tcs(struct snobj *q) { struct snobj *r; struct snobj *t; unsigned int wid_filter = MAX_WORKERS; struct ns_iter iter; struct tc *c; t = snobj_eval(q, "wid"); if (t) { wid_filter = snobj_uint_get(t); if (wid_filter >= MAX_WORKERS) return snobj_err(EINVAL, "'wid' must be between 0 and %d", MAX_WORKERS - 1); if (!is_worker_active(wid_filter)) return snobj_err(EINVAL, "worker:%d does not exist", wid_filter); } r = snobj_list(); ns_init_iterator(&iter, NS_TYPE_TC); while ((c = (struct tc *)ns_next(&iter)) != NULL) { int wid; if (wid_filter < MAX_WORKERS) { if (workers[wid_filter]->s != c->s) continue; wid = wid_filter; } else { for (wid = 0; wid < MAX_WORKERS; wid++) if (is_worker_active(wid) && workers[wid]->s == c->s) break; } struct snobj *elem = snobj_map(); snobj_map_set(elem, "name", snobj_str(c->name)); snobj_map_set(elem, "tasks", snobj_int(c->num_tasks)); snobj_map_set(elem, "parent", snobj_str(c->parent->name)); snobj_map_set(elem, "priority", snobj_int(c->priority)); if (wid < MAX_WORKERS) snobj_map_set(elem, "wid", snobj_uint(wid)); else snobj_map_set(elem, "wid", snobj_int(-1)); snobj_list_add(r, elem); } ns_release_iterator(&iter); return r; }