static struct snobj *handle_enable_tcpdump(struct snobj *arg) { const char *m_name; const char *fifo; uint16_t gate; struct module *m; int ret; m_name = snobj_eval_str(arg, "name"); gate = snobj_eval_uint(arg, "gate"); fifo = snobj_eval_str(arg, "fifo"); if (!m_name) return snobj_err(EINVAL, "Missing 'name' field in arg"); if ((m = find_module(m_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m_name); if (gate >= m->allocated_gates) return snobj_err(EINVAL, "Gate '%hu' does not exist", gate); ret = enable_tcpdump(fifo, m, gate); if (ret < 0) { return snobj_err(-ret, "Enabling tcpdump %s[%d] failed", m_name, gate); } return NULL; }
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_connect_modules(struct snobj *arg) { const char *m1_name; const char *m2_name; uint16_t gate; struct module *m1; struct module *m2; int ret; m1_name = snobj_eval_str(arg, "m1"); m2_name = snobj_eval_str(arg, "m2"); gate = snobj_eval_uint(arg, "gate"); if (!m1_name || !m2_name) return snobj_err(EINVAL, "Missing 'm1' or 'm2' field in arg"); if ((m1 = find_module(m1_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m1_name); if ((m2 = find_module(m2_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m2_name); ret = connect_modules(m1, gate, m2); if (ret < 0) return snobj_err(-ret, "Connection '%s'[%d]->'%s' failed", m1_name, gate, m2_name); printf("%s[%d] -> %s\n", m1_name, gate, m2_name); return NULL; }
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_attach_task(struct snobj *q) { const char *m_name; const char *tc_name; task_id_t tid; struct module *m; struct task *t; m_name = snobj_eval_str(q, "name"); if (!m_name) return snobj_err(EINVAL, "Missing 'name' field"); if ((m = find_module(m_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m_name); tid = snobj_eval_uint(q, "taskid"); if (tid >= MAX_TASKS_PER_MODULE) return snobj_err(EINVAL, "'taskid' must be between 0 and %d", MAX_TASKS_PER_MODULE - 1); if ((t = m->tasks[tid]) == NULL) return snobj_err(ENOENT, "Task %s:%hu does not exist", m_name, tid); tc_name = snobj_eval_str(q, "tc"); if (tc_name) { struct tc *c; c = ns_lookup(NS_TYPE_TC, tc_name); if (!c) return snobj_err(ENOENT, "No TC '%s' found", tc_name); task_attach(t, c); } else { int wid; /* TODO: worker_id_t */ if (task_is_attached(t)) return snobj_err(EBUSY, "Task %s:%hu is already " "attached to a TC", m_name, tid); wid = snobj_eval_uint(q, "wid"); if (wid >= MAX_WORKERS) return snobj_err(EINVAL, "'wid' must be between 0 and %d", MAX_WORKERS - 1); if (!is_worker_active(wid)) return snobj_err(EINVAL, "Worker %d does not exist", wid); assign_default_tc(wid, t); } return NULL; }
static struct snobj *handle_disconnect_modules(struct snobj *arg) { const char *m_name; uint16_t gate; struct module *m; int ret; m_name = snobj_eval_str(arg, "name"); gate = snobj_eval_uint(arg, "gate"); if (!m_name) return snobj_err(EINVAL, "Missing 'name' field in arg"); if ((m = find_module(m_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m_name); ret = disconnect_modules(m, gate); if (ret < 0) return snobj_err(-ret, "Disconnection '%s'[%d] failed", m_name, gate); printf("%s[%d] -> <dead end>\n", m_name, gate); return NULL; }
static struct snobj *handle_disable_tcpdump(struct snobj *q) { const char *m_name; gate_t gate; struct module *m; int ret; m_name = snobj_eval_str(q, "name"); gate = snobj_eval_uint(q, "gate"); if (!m_name) return snobj_err(EINVAL, "Missing 'name' field"); if ((m = find_module(m_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m_name); if (gate >= m->allocated_gates) return snobj_err(EINVAL, "Gate '%hu' does not exist", gate); ret = disable_tcpdump(m, gate); if (ret < 0) { return snobj_err(-ret, "Disabling tcpdump %s[%d] failed", m_name, gate); } return NULL; }
static struct snobj *handle_snobj_module(struct snobj *q) { const char *m_name; const char *cmd; struct module *m; m_name = snobj_eval_str(q, "name"); if (!m_name) return snobj_err(EINVAL, "Missing module name field 'name'"); if ((m = find_module(m_name)) == NULL) return snobj_err(ENOENT, "No module '%s' found", m_name); cmd = snobj_eval_str(q, "cmd"); if (strcmp(cmd, "query") == 0) { struct snobj *arg; if (!m->mclass->query) return snobj_err(ENOTSUP, "Module '%s' does not support queries", m_name); arg = snobj_eval(q, "arg"); if (!arg) { struct snobj *ret; arg = snobj_nil(); ret = m->mclass->query(m, arg); snobj_free(arg); return ret; } return m->mclass->query(m, arg); } else return snobj_err(ENOTSUP, "Not supported command '%s'", cmd); }
static struct snobj *handle_add_tc(struct snobj *q) { const char *tc_name; int wid; struct tc_params params; struct tc *c; tc_name = snobj_eval_str(q, "name"); if (!tc_name) return snobj_err(EINVAL, "Missing 'name' field"); if (!ns_is_valid_name(tc_name)) return snobj_err(EINVAL, "'%s' is an invalid name", tc_name); if (ns_name_exists(tc_name)) return snobj_err(EINVAL, "Name '%s' already exists", tc_name); wid = snobj_eval_uint(q, "wid"); if (wid >= MAX_WORKERS) return snobj_err(EINVAL, "'wid' must be between 0 and %d", MAX_WORKERS - 1); if (!is_worker_active(wid)) return snobj_err(EINVAL, "worker:%d does not exist", wid); memset(¶ms, 0, sizeof(params)); strcpy(params.name, tc_name); params.priority = snobj_eval_int(q, "priority"); if (params.priority == DEFAULT_PRIORITY) return snobj_err(EINVAL, "Priority %d is reserved", DEFAULT_PRIORITY); /* TODO */ params.share = 1; params.share_resource = RESOURCE_CNT; c = tc_init(workers[wid]->s, ¶ms); if (is_err(c)) return snobj_err(-ptr_to_err(c), "tc_init() failed"); tc_join(c); 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_snobj_softnic(struct snobj *q) { struct snobj *arg; const char *s; s = snobj_eval_str(q, "cmd"); if (!s) return snobj_err(EINVAL, "Missing 'cmd' field"); arg = snobj_map_get(q, "arg"); for (int i = 0; sn_handlers[i].cmd != NULL; i++) { if (strcmp(s, sn_handlers[i].cmd) != 0) continue; if (sn_handlers[i].pause_needed && is_any_worker_running()) return snobj_err(EBUSY, "There is a running worker"); return sn_handlers[i].func(arg); } return snobj_err(ENOTSUP, "Unknown command in 'cmd': '%s'", s); }
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; }