78a2f9a94d
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
281 lines
7.6 KiB
C
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;
|
|
}
|