diff --git a/usr.sbin/valectl/valectl.c b/usr.sbin/valectl/valectl.c index 7e219e2df7a3..bf1bc6229fb8 100644 --- a/usr.sbin/valectl/valectl.c +++ b/usr.sbin/valectl/valectl.c @@ -1,445 +1,445 @@ /* * Copyright (C) 2013-2014 Michio Honda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* $FreeBSD$ */ #define LIBNETMAP_NOTHREADSAFE #include #include #include #include /* PRI* macros */ #include /* strcmp */ #include /* open */ #include /* close */ #include /* ioctl */ #include #include /* apple needs sockaddr */ #include /* ifreq */ #include /* basename */ #include /* atoi, free */ int verbose; struct args { const char *name; const char *config; const char *mem_id; uint16_t nr_reqtype; uint32_t nr_mode; }; static void dump_port_info(struct nmreq_port_info_get *v) { printf("memsize: %"PRIu64"\n", v->nr_memsize); printf("tx_slots: %"PRIu32"\n", v->nr_tx_slots); printf("rx_slots: %"PRIu32"\n", v->nr_rx_slots); printf("tx_rings: %"PRIu16"\n", v->nr_tx_rings); printf("rx_rings %"PRIu16"\n", v->nr_rx_rings); printf("mem_id: %"PRIu16"\n", v->nr_mem_id); } static void dump_newif(struct nmreq_vale_newif *v) { printf("tx_slots: %"PRIu32"\n", v->nr_tx_slots); printf("rx_slots: %"PRIu32"\n", v->nr_rx_slots); printf("tx_rings: %"PRIu16"\n", v->nr_tx_rings); printf("rx_ring: %"PRIu16"\n", v->nr_rx_rings); printf("mem_id: %"PRIu16"\n", v->nr_mem_id); } static void dump_vale_list(struct nmreq_vale_list *v) { printf("bridge_idx: %"PRIu16"\n", v->nr_bridge_idx); printf("port_idx: %"PRIu16"\n", v->nr_port_idx); } static void parse_ring_config(const char* conf, uint32_t *nr_tx_slots, uint32_t *nr_rx_slots, uint16_t *nr_tx_rings, uint16_t *nr_rx_rings) { char *w, *tok; int i, v; *nr_tx_rings = *nr_rx_rings = 0; *nr_tx_slots = *nr_rx_slots = 0; if (conf == NULL || ! *conf) return; w = strdup(conf); for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { v = atoi(tok); switch (i) { case 0: *nr_tx_slots = *nr_rx_slots = v; break; case 1: *nr_rx_slots = v; break; case 2: *nr_tx_rings = *nr_rx_rings = v; break; case 3: *nr_rx_rings = v; break; default: fprintf(stderr, "ignored config: %s", tok); break; } } ND("txr %d txd %d rxr %d rxd %d", *nr_tx_rings, *nr_tx_slots, *nr_rx_rings, *nr_rx_slots); free(w); } static int parse_poll_config(const char *conf, struct nmreq_vale_polling *v) { char *w, *tok; int i, p; if (conf == NULL || ! *conf) { fprintf(stderr, "invalid null/empty config\n"); return -1; } w = strdup(conf); for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { p = atoi(tok); switch (i) { case 0: v->nr_mode = p ? NETMAP_POLLING_MODE_MULTI_CPU : NETMAP_POLLING_MODE_SINGLE_CPU; break; case 1: v->nr_first_cpu_id = p; break; case 2: if (v->nr_mode != NETMAP_POLLING_MODE_MULTI_CPU) { fprintf(stderr, "too many numbers in '%s'\n", conf); return -1; } v->nr_num_polling_cpus = p; break; case 3: fprintf(stderr, "too many numbers in '%s'\n", conf); return -1; } } free(w); return 0; } static int32_t parse_mem_id(const char *mem_id) { int32_t id; if (mem_id == NULL) return 0; if (isdigit(*mem_id)) return atoi(mem_id); id = nmreq_get_mem_id(&mem_id, nmctx_get()); if (id == 0) { fprintf(stderr, "invalid format in '-m %s' (missing 'netmap:'?)\n", mem_id); return -1; } return id; } static int list_all(int fd, struct nmreq_header *hdr) { int error; struct nmreq_vale_list *vale_list = - (struct nmreq_vale_list *)hdr->nr_body; + (struct nmreq_vale_list *)(uintptr_t)hdr->nr_body; for (;;) { hdr->nr_name[0] = '\0'; error = ioctl(fd, NIOCCTRL, hdr); if (error < 0) { if (errno == ENOENT) break; fprintf(stderr, "failed to list all: %s\n", strerror(errno)); return 1; } printf("%s bridge_idx %"PRIu16" port_idx %"PRIu32"\n", hdr->nr_name, vale_list->nr_bridge_idx, vale_list->nr_port_idx); vale_list->nr_port_idx++; } return 1; } static int bdg_ctl(struct args *a) { struct nmreq_header hdr; struct nmreq_vale_attach vale_attach; struct nmreq_vale_detach vale_detach; struct nmreq_vale_newif vale_newif; struct nmreq_vale_list vale_list; struct nmreq_vale_polling vale_polling; struct nmreq_port_info_get port_info_get; int error = 0; int fd; int32_t mem_id; const char *action = NULL; fd = open("/dev/netmap", O_RDWR); if (fd == -1) { perror("/dev/netmap"); return 1; } bzero(&hdr, sizeof(hdr)); hdr.nr_version = NETMAP_API; if (a->name != NULL) { /* might be NULL */ strncpy(hdr.nr_name, a->name, NETMAP_REQ_IFNAMSIZ - 1); hdr.nr_name[NETMAP_REQ_IFNAMSIZ - 1] = '\0'; } hdr.nr_reqtype = a->nr_reqtype; switch (a->nr_reqtype) { case NETMAP_REQ_VALE_DELIF: /* no body */ action = "remove"; break; case NETMAP_REQ_VALE_NEWIF: memset(&vale_newif, 0, sizeof(vale_newif)); hdr.nr_body = (uintptr_t)&vale_newif; parse_ring_config(a->config, &vale_newif.nr_tx_slots, &vale_newif.nr_rx_slots, &vale_newif.nr_tx_rings, &vale_newif.nr_rx_rings); mem_id = parse_mem_id(a->mem_id); if (mem_id < 0) return 1; vale_newif.nr_mem_id = mem_id; action = "create"; break; case NETMAP_REQ_VALE_ATTACH: memset(&vale_attach, 0, sizeof(vale_attach)); hdr.nr_body = (uintptr_t)&vale_attach; vale_attach.reg.nr_mode = a->nr_mode; parse_ring_config(a->config, &vale_attach.reg.nr_tx_slots, &vale_attach.reg.nr_rx_slots, &vale_attach.reg.nr_tx_rings, &vale_attach.reg.nr_rx_rings); mem_id = parse_mem_id(a->mem_id); if (mem_id < 0) return 1; vale_attach.reg.nr_mem_id = mem_id; action = "attach"; break; case NETMAP_REQ_VALE_DETACH: memset(&vale_detach, 0, sizeof(vale_detach)); hdr.nr_body = (uintptr_t)&vale_detach; action = "detach"; break; case NETMAP_REQ_VALE_LIST: memset(&vale_list, 0, sizeof(vale_list)); hdr.nr_body = (uintptr_t)&vale_list; if (a->name == NULL) { return list_all(fd, &hdr); } action = "list"; break; case NETMAP_REQ_VALE_POLLING_ENABLE: action = "enable polling on"; /* fall through */ case NETMAP_REQ_VALE_POLLING_DISABLE: memset(&vale_polling, 0, sizeof(vale_polling)); hdr.nr_body = (uintptr_t)&vale_polling; parse_poll_config(a->config, &vale_polling); if (action == NULL) action ="disable polling on"; break; case NETMAP_REQ_PORT_INFO_GET: memset(&port_info_get, 0, sizeof(port_info_get)); hdr.nr_body = (uintptr_t)&port_info_get; action = "obtain info for"; break; } error = ioctl(fd, NIOCCTRL, &hdr); if (error < 0) { fprintf(stderr, "failed to %s %s: %s\n", action, a->name, strerror(errno)); return 1; } switch (hdr.nr_reqtype) { case NETMAP_REQ_VALE_NEWIF: if (verbose) { dump_newif(&vale_newif); } break; case NETMAP_REQ_VALE_ATTACH: if (verbose) { printf("port_index: %"PRIu32"\n", vale_attach.port_index); } break; case NETMAP_REQ_VALE_DETACH: if (verbose) { printf("port_index: %"PRIu32"\n", vale_detach.port_index); } break; case NETMAP_REQ_VALE_LIST: dump_vale_list(&vale_list); break; case NETMAP_REQ_PORT_INFO_GET: dump_port_info(&port_info_get); break; } close(fd); return error; } static void usage(int errcode) { fprintf(stderr, "Usage:\n" "vale-ctl [arguments]\n" "\t-g interface interface name to get info\n" "\t-d interface interface name to be detached\n" "\t-a interface interface name to be attached\n" "\t-h interface interface name to be attached with the host stack\n" "\t-n interface interface name to be created\n" "\t-r interface interface name to be deleted\n" "\t-l vale-port show bridge and port indices\n" "\t-C string ring/slot setting of an interface creating by -n\n" "\t-p interface start polling. Additional -C x,y,z configures\n" "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n" "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n" "\t\t z: (ONE_NIC only) num of total cores/rings\n" "\t-P interface stop polling\n" "\t-m memid to use when creating a new interface\n" "\t-v increase verbosity\n" "with no arguments: list all existing vale ports\n"); exit(errcode); } int main(int argc, char *argv[]) { int ch; struct args a = { .name = NULL, .config = NULL, .mem_id = NULL, .nr_reqtype = 0, .nr_mode = NR_REG_ALL_NIC, }; while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:v")) != -1) { switch (ch) { default: fprintf(stderr, "bad option %c %s", ch, optarg); usage(1); break; case 'd': a.nr_reqtype = NETMAP_REQ_VALE_DETACH; a.name = optarg; break; case 'a': a.nr_reqtype = NETMAP_REQ_VALE_ATTACH; a.nr_mode = NR_REG_ALL_NIC; a.name = optarg; break; case 'h': a.nr_reqtype = NETMAP_REQ_VALE_ATTACH; a.nr_mode = NR_REG_NIC_SW; a.name = optarg; break; case 'n': a.nr_reqtype = NETMAP_REQ_VALE_NEWIF; a.name = optarg; break; case 'r': a.nr_reqtype = NETMAP_REQ_VALE_DELIF; a.name = optarg; break; case 'g': a.nr_reqtype = NETMAP_REQ_PORT_INFO_GET; a.name = optarg; break; case 'l': a.nr_reqtype = NETMAP_REQ_VALE_LIST; a.name = optarg; if (strncmp(a.name, NM_BDG_NAME, strlen(NM_BDG_NAME))) { fprintf(stderr, "invalid vale port name: '%s'\n", a.name); usage(1); } break; case 'C': a.config = optarg; break; case 'p': a.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE; a.name = optarg; break; case 'P': a.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE; a.name = optarg; break; case 'm': a.mem_id = optarg; break; case 'v': verbose++; break; } } if (optind != argc) { usage(1); } if (argc == 1) { a.nr_reqtype = NETMAP_REQ_VALE_LIST; a.name = NULL; } if (!a.nr_reqtype) { usage(1); } return bdg_ctl(&a); }