Index: usr.sbin/valectl/valectl.8 =================================================================== --- usr.sbin/valectl/valectl.8 +++ usr.sbin/valectl/valectl.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 31, 2020 +.Dd August 23, 2020 .Dt VALECTL 8 .Os .Sh NAME @@ -66,25 +66,32 @@ with their internal bridge number and port number. .Bl -tag -width Ds .It Fl g Ar valeSSS:PPP -Print the number of receive rings of +Print parameters of .Ar valeSSS:PPP . .It Fl a Ar valeSSS:interface Attach .Ar interface -(which must be an existing network interface) to +.Pq which must be a network interface on the system +to .Ar valeSSS -and detach it from the host stack. +and detach it from the network stack on the system. .It Fl h Ar valeSSS:interface Attach .Ar interface -(which must be an existing network interface) to +.Pq which must be a network interface on the system +to .Ar valeSSS -while keeping it attached to the host stack. -More precisely, packets coming from -the host stack and directed to the interface will go through the switch, where -they can still reach the interface if the switch rules allow it. -Conversely, packets coming from the interface will go through the switch and, -if appropriate, will reach the host stack. +while keeping it attached to the network stack on the system. +.Pp +More precisely, +packets originated from the network stack and directed to the interface +will go through the specified VALE switch. +The packets can still reach the interface if the switch rules are configured +to allow it. +Conversely, packets received on the interface will go through the VALE +switch and, +if configured properly, +will reach the network stack. .It Fl d Ar valeSSS:interface Detach .Ar interface @@ -93,8 +100,8 @@ .It Fl n Ar interface Create a new persistent VALE port with name .Ar interface . -The name must be different from any other network interface -already present in the system. +The interface name must be different from any other network interface +on the system. .It Fl r Ar interface Destroy the persistent VALE port with name .Ar inteface . @@ -115,10 +122,13 @@ .Ar valeSSS:PPP . .It Fl C Ar x | Ar x,y | Ar x,y,z | Ar x,y,z,w When used in conjunction with -.Fl n -it supplies the number of tx and rx rings and slots. -The full format with four numbers gives, in order, number of tx slots, number -of rx slots, number of tx rings and number of rx rings. +.Fl n , +this supplies the number of tx and rx rings and slots. +The full format with four numbers gives, in order, +the number of tx slots, +the number of rx slots, +the number of tx rings, +and the number of rx rings. The form with three numbers uses .Ar z for both the number of tx and the number of rx rings. @@ -131,7 +141,7 @@ .Pp When used in conjunction with .Fl p -only the first three forms are used. +only the first three forms are valid. The first number may be either 0 or 1. If 0, then all interface rings will be polled by a single thread, running on the core id given by the second number (the third number, if present, Index: usr.sbin/valectl/valectl.c =================================================================== --- usr.sbin/valectl/valectl.c +++ usr.sbin/valectl/valectl.c @@ -25,194 +25,251 @@ /* $FreeBSD$ */ +#include +#include /* ioctl */ +#include /* apple needs sockaddr */ + +#include /* ifreq */ #define NETMAP_WITH_LIBS #include #include +#include #include -#include -#include /* PRI* macros */ -#include /* strcmp */ #include /* open */ -#include /* close */ -#include /* ioctl */ -#include -#include /* apple needs sockaddr */ -#include /* ifreq */ +#include #include /* basename */ +#include +#include /* strcmp */ #include /* atoi, free */ +#include +#include /* close */ +static void parse_nmr_config(const char *, struct nmreq_register *); +static int vale_ctl(const char *, uint16_t, uint32_t, int, char *, int); +static void usage(int); + static void -parse_nmr_config(const char* conf, struct nmreq *nmr) +parse_nmr_config(const char *conf, struct nmreq_register *nrr) { char *w, *tok; int i, v; - nmr->nr_tx_rings = nmr->nr_rx_rings = 0; - nmr->nr_tx_slots = nmr->nr_rx_slots = 0; if (conf == NULL || ! *conf) return; w = strdup(conf); + if (w == NULL) + perror("strdup()"); for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { v = atoi(tok); switch (i) { case 0: - nmr->nr_tx_slots = nmr->nr_rx_slots = v; + nrr->nr_tx_slots = nrr->nr_rx_slots = v; break; case 1: - nmr->nr_rx_slots = v; + nrr->nr_rx_slots = v; break; case 2: - nmr->nr_tx_rings = nmr->nr_rx_rings = v; + nrr->nr_tx_rings = nrr->nr_rx_rings = v; break; case 3: - nmr->nr_rx_rings = v; + nrr->nr_rx_rings = v; break; default: - D("ignored config: %s", tok); + warnx("ignored config: %s", tok); break; } } - D("txr %d txd %d rxr %d rxd %d", - nmr->nr_tx_rings, nmr->nr_tx_slots, - nmr->nr_rx_rings, nmr->nr_rx_slots); free(w); } static int -bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2) +vale_ctl(const char *name, uint16_t nr_reqtype, uint32_t nr_mode, int nr_arg, + char *nmr_config, int nr_mem_id) { - struct nmreq nmr; + struct nmreq_header nrh; + struct nmreq_register nrr; + struct nmreq_port_info_get *nrpig; int error = 0; int fd = open("/dev/netmap", O_RDWR); - if (fd == -1) { - D("Unable to open /dev/netmap"); - return -1; - } + if (fd == -1) + err(EX_IOERR, "Unable to open /dev/netmap"); - bzero(&nmr, sizeof(nmr)); - nmr.nr_version = NETMAP_API; + nrh = (struct nmreq_header){ + .nr_version = NETMAP_API, + .nr_reqtype = nr_reqtype, + }; + nrr = (struct nmreq_register){ + }; if (name != NULL) /* might be NULL */ - strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)-1); - nmr.nr_cmd = nr_cmd; - parse_nmr_config(nmr_config, &nmr); - nmr.nr_arg2 = nr_arg2; + strncpy(nrh.nr_name, name, sizeof(nrh.nr_name) - 1); + parse_nmr_config(nmr_config, &nrr); - switch (nr_cmd) { - case NETMAP_BDG_DELIF: - case NETMAP_BDG_NEWIF: - error = ioctl(fd, NIOCREGIF, &nmr); - if (error == -1) { - ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); - perror(name); - } else { - ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); - } + switch (nr_reqtype) { + case NETMAP_REQ_VALE_DELIF: + error = ioctl(fd, NIOCCTRL, &nrh); + if (error == -1) + err(EX_OSERR, "Unable to delete %s", name); break; - case NETMAP_BDG_ATTACH: - case NETMAP_BDG_DETACH: - nmr.nr_flags = NR_REG_ALL_NIC; - if (nr_arg && nr_arg != NETMAP_BDG_HOST) { - nmr.nr_flags = NR_REG_NIC_SW; - nr_arg = 0; - } - nmr.nr_arg1 = nr_arg; - error = ioctl(fd, NIOCREGIF, &nmr); - if (error == -1) { - ND("Unable to %s %s to the bridge", nr_cmd == - NETMAP_BDG_DETACH?"detach":"attach", name); - perror(name); - } else - ND("Success to %s %s to the bridge", nr_cmd == - NETMAP_BDG_DETACH?"detach":"attach", name); + case NETMAP_REQ_VALE_NEWIF: + nrh.nr_body = (uintptr_t)&(struct nmreq_vale_newif){ + .nr_tx_slots = nrr.nr_tx_slots, + .nr_tx_rings = nrr.nr_tx_rings, + .nr_rx_slots = nrr.nr_rx_slots, + .nr_rx_rings = nrr.nr_rx_rings, + .nr_mem_id = nr_mem_id + }; + error = ioctl(fd, NIOCCTRL, &nrh); + if (error == -1) + err(EX_OSERR, "Unable to create %s", name); + printf("%s: " + "tx_slots=%u tx_rings=%u " + "rx_slots=%u rx_rings=%u " + "mem_id=%u\n", + nrh.nr_name, + nrr.nr_tx_slots, nrr.nr_tx_rings, + nrr.nr_rx_slots, nrr.nr_rx_rings, + nr_mem_id); break; - - case NETMAP_BDG_LIST: - if (strlen(nmr.nr_name)) { /* name to bridge/port info */ - error = ioctl(fd, NIOCGINFO, &nmr); - if (error) { - ND("Unable to obtain info for %s", name); - perror(name); - } else - D("%s at bridge:%d port:%d", name, nmr.nr_arg1, - nmr.nr_arg2); + case NETMAP_REQ_VALE_ATTACH: + nrr.nr_mode = nr_mode; + nrr.nr_mem_id = nr_mem_id; + nrh.nr_body = (uintptr_t)&(struct nmreq_vale_attach){ + .reg = nrr + }; + error = ioctl(fd, NIOCCTRL, &nrh); + if (error == -1) + err(EX_OSERR, "Unable to attach %s to the bridge", + name); + case NETMAP_REQ_VALE_DETACH: + nrh.nr_body = (uintptr_t)&(struct nmreq_vale_detach){ + }; + error = ioctl(fd, NIOCCTRL, &nrh); + if (error == -1) + err(EX_OSERR, "Unable to detach %s to the bridge", + name); + break; + case NETMAP_REQ_VALE_LIST: + nrh.nr_body = (uintptr_t)&(struct nmreq_vale_list){ + }; + if (strlen(nrh.nr_name)) { + /* nrh.nr_name is for bridge/port info. */ + error = ioctl(fd, NIOCCTRL, &nrh); + if (error) + err(EX_OSERR, "Unable to obtain info for %s", + name); + else { + struct nmreq_vale_list *nrvl = + (struct nmreq_vale_list *)nrh.nr_body; + printf("%s bridge:%d port:%d\n", name, + nrvl->nr_bridge_idx, nrvl->nr_port_idx); + } break; + } else { + /* Scan all of the bridges and ports. */ + struct nmreq_vale_list *nrvl = + (struct nmreq_vale_list *)nrh.nr_body; + nrvl->nr_bridge_idx = 0; + nrvl->nr_port_idx = 0; + while (ioctl(fd, NIOCCTRL, &nrh) == 0) { + printf("%s bridge:%d port:%d\n", + nrh.nr_name, + nrvl->nr_bridge_idx, nrvl->nr_port_idx); + nrvl->nr_port_idx++; + nrh.nr_name[0] = '\0'; + } } - - /* scan all the bridges and ports */ - nmr.nr_arg1 = nmr.nr_arg2 = 0; - for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) { - D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2, - nmr.nr_name); - nmr.nr_name[0] = '\0'; - } - break; - - case NETMAP_BDG_POLLING_ON: - case NETMAP_BDG_POLLING_OFF: - /* We reuse nmreq fields as follows: - * nr_tx_slots: 0 and non-zero indicate REG_ALL_NIC - * REG_ONE_NIC, respectively. - * nr_rx_slots: CPU core index. This also indicates the - * first queue in the case of REG_ONE_NIC - * nr_tx_rings: (REG_ONE_NIC only) indicates the - * number of CPU cores or the last queue + case NETMAP_REQ_VALE_POLLING_ENABLE: + case NETMAP_REQ_VALE_POLLING_DISABLE: + /* Reuse the following members in different meanings: + * + * nr_tx_slots: + * zero = NETMAP_POLLING_MODE_MULTI_CPU + * non-zero = NETMAP_POLLING_MODE_SINGLE_CPU + * + * nr_rx_slots: + * CPU core index. This also indicates the first queue + * in the case of MULTI_CPU. + * + * nr_tx_rings: + * (MULTI_CPU only) indicates the number of CPU cores + * or the last queue. */ - nmr.nr_flags |= nmr.nr_tx_slots ? - NR_REG_ONE_NIC : NR_REG_ALL_NIC; - nmr.nr_ringid = nmr.nr_rx_slots; - /* number of cores/rings */ - if (nmr.nr_flags == NR_REG_ALL_NIC) - nmr.nr_arg1 = 1; + if (nrr.nr_tx_slots == 0) { + /* multi_cpu */ + nrh.nr_body = (uintptr_t)&(struct nmreq_vale_polling){ + .nr_mode = NETMAP_POLLING_MODE_MULTI_CPU, + .nr_first_cpu_id = nrr.nr_rx_slots & + NETMAP_RING_MASK, + .nr_num_polling_cpus = (nrr.nr_tx_rings == 0) ? + 1 : nrr.nr_tx_rings + }; + } else { + /* single_cpu */ + nrh.nr_body = (uintptr_t)&(struct nmreq_vale_polling){ + .nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU, + .nr_first_cpu_id = nrr.nr_rx_slots & + NETMAP_RING_MASK, + .nr_num_polling_cpus = 1 + }; + } + error = ioctl(fd, NIOCCTRL, &nrh); + if (error == -1) + err(EX_OSERR, "%s: Could not %s polling", + nrh.nr_name, + nr_reqtype == NETMAP_REQ_VALE_POLLING_ENABLE ? + "start" : "stop"); + printf("%s: mode=%s first_cpu_id=%u polling_cpus=%u\n", + nrh.nr_name, + (nrr.nr_tx_slots == 0) ? "multi_cpu" : "single_cpu", + nrr.nr_rx_slots & NETMAP_RING_MASK, + (nrr.nr_tx_slots == 0) ? nrr.nr_tx_rings : 1); + break; + default: /* NETMAP_REQ_PORT_INFO_GET */ + nrh.nr_reqtype = NETMAP_REQ_PORT_INFO_GET; + nrpig = &(struct nmreq_port_info_get){ + .nr_mem_id = nr_mem_id + }; + nrh.nr_body = (uintptr_t)nrpig; + error = ioctl(fd, NIOCCTRL, &nrh); + if (error) + err(EX_OSERR, "Could not get if info for %s", name); else - nmr.nr_arg1 = nmr.nr_tx_rings; - - error = ioctl(fd, NIOCREGIF, &nmr); - if (!error) - D("polling on %s %s", nmr.nr_name, - nr_cmd == NETMAP_BDG_POLLING_ON ? - "started" : "stopped"); - else - D("polling on %s %s (err %d)", nmr.nr_name, - nr_cmd == NETMAP_BDG_POLLING_ON ? - "couldn't start" : "couldn't stop", error); + printf("%s: " + "tx_slots=%u tx_rings=%u " + "rx_slots=%u rx_rings=%u " + "mem_id=%u memsize=%jd\n", + nrh.nr_name, + nrpig->nr_tx_slots, nrpig->nr_tx_rings, + nrpig->nr_rx_slots, nrpig->nr_rx_rings, + nrpig->nr_mem_id, nrpig->nr_memsize); break; - - default: /* GINFO */ - nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; - error = ioctl(fd, NIOCGINFO, &nmr); - if (error) { - ND("Unable to get if info for %s", name); - perror(name); - } else - D("%s: %d queues.", name, nmr.nr_rx_rings); - break; } close(fd); - return error; + return (EX_OK); } static void usage(int errcode) { fprintf(stderr, - "Usage:\n" - "valectl arguments\n" - "\t-g interface interface name to get info\n" + "Usage: valectl [flags]\n" + "\t(no flag) list all of the bridged interfaces\n" + "\t-g valeSSS:PPP 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 list all or specified bridge's interfaces (default)\n" + "\t-l valeSSS:PPP list the specified interface\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-p valeSSS:PPP 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-P valeSSS:PPP stop polling\n" "\t-m memid to use when creating a new interface\n"); exit(errcode); } @@ -220,61 +277,68 @@ int main(int argc, char *argv[]) { - int ch, nr_cmd = 0, nr_arg = 0; - char *name = NULL, *nmr_config = NULL; - int nr_arg2 = 0; + int ch, nr_arg, nr_mem_id; + char *name, *nmr_config; + uint16_t nr_reqtype; + uint32_t nr_mode; + nr_arg = 0; + nr_reqtype = NETMAP_REQ_PORT_INFO_GET; + nr_mode = 0; + nr_mem_id = 0; + name = nmr_config = NULL; while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:")) != -1) { if (ch != 'C' && ch != 'm') name = optarg; /* default */ switch (ch) { - default: - fprintf(stderr, "bad option %c %s", ch, optarg); - usage(-1); - break; case 'd': - nr_cmd = NETMAP_BDG_DETACH; + nr_reqtype = NETMAP_REQ_VALE_DETACH; break; case 'a': - nr_cmd = NETMAP_BDG_ATTACH; + nr_reqtype = NETMAP_REQ_VALE_ATTACH; + nr_mode = NR_REG_ALL_NIC; break; case 'h': - nr_cmd = NETMAP_BDG_ATTACH; - nr_arg = NETMAP_BDG_HOST; + nr_reqtype = NETMAP_REQ_VALE_ATTACH; + nr_mode = NR_REG_NIC_SW; break; case 'n': - nr_cmd = NETMAP_BDG_NEWIF; + nr_reqtype = NETMAP_REQ_VALE_NEWIF; break; case 'r': - nr_cmd = NETMAP_BDG_DELIF; + nr_reqtype = NETMAP_REQ_VALE_DELIF; break; case 'g': - nr_cmd = 0; + nr_reqtype = NETMAP_REQ_PORT_INFO_GET; break; case 'l': - nr_cmd = NETMAP_BDG_LIST; + nr_reqtype = NETMAP_REQ_VALE_LIST; break; case 'C': nmr_config = strdup(optarg); break; case 'p': - nr_cmd = NETMAP_BDG_POLLING_ON; + nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE; break; case 'P': - nr_cmd = NETMAP_BDG_POLLING_OFF; + nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE; break; case 'm': - nr_arg2 = atoi(optarg); + nr_mem_id = atoi(optarg); break; + default: + usage(EX_USAGE); + break; } } if (optind != argc) { // fprintf(stderr, "optind %d argc %d\n", optind, argc); - usage(-1); + usage(EX_USAGE); } if (argc == 1) { - nr_cmd = NETMAP_BDG_LIST; + nr_reqtype = NETMAP_REQ_VALE_LIST; name = NULL; } - return bdg_ctl(name, nr_cmd, nr_arg, nmr_config, nr_arg2) ? 1 : 0; + return vale_ctl(name, nr_reqtype, nr_mode, nr_arg, nmr_config, + nr_mem_id) ? 1 : 0; }