freebsd-dev/usr.sbin/valectl/valectl.c
Vincenzo Maffione c7c7805531 add valectl to the system commands
The valectl(4) program is used to manage vale(4) switches.
Add it to the system commands so that it can be used right away.
This program was previously called vale-ctl, and stored in
tools/tools/netmap

Reviewed by:	hrs, bcr, lwhsu, kevans
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D22146
2019-10-31 21:01:34 +00:00

281 lines
7.6 KiB
C

/*
* 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 NETMAP_WITH_LIBS
#include <net/netmap_user.h>
#include <net/netmap.h>
#include <errno.h>
#include <stdio.h>
#include <inttypes.h> /* PRI* macros */
#include <string.h> /* strcmp */
#include <fcntl.h> /* open */
#include <unistd.h> /* close */
#include <sys/ioctl.h> /* ioctl */
#include <sys/param.h>
#include <sys/socket.h> /* apple needs sockaddr */
#include <net/if.h> /* ifreq */
#include <libgen.h> /* basename */
#include <stdlib.h> /* atoi, free */
static void
parse_nmr_config(const char* conf, struct nmreq *nmr)
{
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);
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;
break;
case 1:
nmr->nr_rx_slots = v;
break;
case 2:
nmr->nr_tx_rings = nmr->nr_rx_rings = v;
break;
case 3:
nmr->nr_rx_rings = v;
break;
default:
D("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)
{
struct nmreq nmr;
int error = 0;
int fd = open("/dev/netmap", O_RDWR);
if (fd == -1) {
D("Unable to open /dev/netmap");
return -1;
}
bzero(&nmr, sizeof(nmr));
nmr.nr_version = NETMAP_API;
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;
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);
}
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);
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);
break;
}
/* 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
*/
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;
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);
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;
}
static void
usage(int errcode)
{
fprintf(stderr,
"Usage:\n"
"valectl 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 list all or specified bridge's interfaces (default)\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");
exit(errcode);
}
int
main(int argc, char *argv[])
{
int ch, nr_cmd = 0, nr_arg = 0;
char *name = NULL, *nmr_config = NULL;
int nr_arg2 = 0;
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;
break;
case 'a':
nr_cmd = NETMAP_BDG_ATTACH;
break;
case 'h':
nr_cmd = NETMAP_BDG_ATTACH;
nr_arg = NETMAP_BDG_HOST;
break;
case 'n':
nr_cmd = NETMAP_BDG_NEWIF;
break;
case 'r':
nr_cmd = NETMAP_BDG_DELIF;
break;
case 'g':
nr_cmd = 0;
break;
case 'l':
nr_cmd = NETMAP_BDG_LIST;
break;
case 'C':
nmr_config = strdup(optarg);
break;
case 'p':
nr_cmd = NETMAP_BDG_POLLING_ON;
break;
case 'P':
nr_cmd = NETMAP_BDG_POLLING_OFF;
break;
case 'm':
nr_arg2 = atoi(optarg);
break;
}
}
if (optind != argc) {
// fprintf(stderr, "optind %d argc %d\n", optind, argc);
usage(-1);
}
if (argc == 1) {
nr_cmd = NETMAP_BDG_LIST;
name = NULL;
}
return bdg_ctl(name, nr_cmd, nr_arg, nmr_config, nr_arg2) ? 1 : 0;
}