1251139Sluigi/* 2260368Sluigi * Copyright (C) 2013-2014 Michio Honda. All rights reserved. 3251139Sluigi * 4251139Sluigi * Redistribution and use in source and binary forms, with or without 5251139Sluigi * modification, are permitted provided that the following conditions 6251139Sluigi * are met: 7251139Sluigi * 1. Redistributions of source code must retain the above copyright 8251139Sluigi * notice, this list of conditions and the following disclaimer. 9251139Sluigi * 2. Redistributions in binary form must reproduce the above copyright 10251139Sluigi * notice, this list of conditions and the following disclaimer in the 11251139Sluigi * documentation and/or other materials provided with the distribution. 12251139Sluigi * 13251139Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14251139Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15251139Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16251139Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17251139Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18251139Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19251139Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20251139Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21251139Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22251139Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23251139Sluigi * SUCH DAMAGE. 24251139Sluigi */ 25251139Sluigi 26251139Sluigi/* $FreeBSD: stable/11/tools/tools/netmap/vale-ctl.c 341432 2018-12-03 17:46:53Z vmaffione $ */ 27251139Sluigi 28341432Svmaffione#define NETMAP_WITH_LIBS 29341432Svmaffione#include <net/netmap_user.h> 30341432Svmaffione#include <net/netmap.h> 31341432Svmaffione 32251139Sluigi#include <errno.h> 33251139Sluigi#include <stdio.h> 34251139Sluigi#include <inttypes.h> /* PRI* macros */ 35251139Sluigi#include <string.h> /* strcmp */ 36251139Sluigi#include <fcntl.h> /* open */ 37251139Sluigi#include <unistd.h> /* close */ 38251139Sluigi#include <sys/ioctl.h> /* ioctl */ 39251139Sluigi#include <sys/param.h> 40261909Sluigi#include <sys/socket.h> /* apple needs sockaddr */ 41251139Sluigi#include <net/if.h> /* ifreq */ 42251139Sluigi#include <libgen.h> /* basename */ 43270063Sluigi#include <stdlib.h> /* atoi, free */ 44251139Sluigi 45270063Sluigi/* XXX cut and paste from pkt-gen.c because I'm not sure whether this 46270063Sluigi * program may include nm_util.h 47270063Sluigi */ 48270063Sluigivoid parse_nmr_config(const char* conf, struct nmreq *nmr) 49270063Sluigi{ 50270063Sluigi char *w, *tok; 51270063Sluigi int i, v; 52270063Sluigi 53270063Sluigi nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 54270063Sluigi nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 55270063Sluigi if (conf == NULL || ! *conf) 56270063Sluigi return; 57270063Sluigi w = strdup(conf); 58270063Sluigi for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 59270063Sluigi v = atoi(tok); 60270063Sluigi switch (i) { 61270063Sluigi case 0: 62270063Sluigi nmr->nr_tx_slots = nmr->nr_rx_slots = v; 63270063Sluigi break; 64270063Sluigi case 1: 65270063Sluigi nmr->nr_rx_slots = v; 66270063Sluigi break; 67270063Sluigi case 2: 68270063Sluigi nmr->nr_tx_rings = nmr->nr_rx_rings = v; 69270063Sluigi break; 70270063Sluigi case 3: 71270063Sluigi nmr->nr_rx_rings = v; 72270063Sluigi break; 73270063Sluigi default: 74270063Sluigi D("ignored config: %s", tok); 75270063Sluigi break; 76270063Sluigi } 77270063Sluigi } 78270063Sluigi D("txr %d txd %d rxr %d rxd %d", 79270063Sluigi nmr->nr_tx_rings, nmr->nr_tx_slots, 80270063Sluigi nmr->nr_rx_rings, nmr->nr_rx_slots); 81270063Sluigi free(w); 82270063Sluigi} 83270063Sluigi 84251139Sluigistatic int 85341432Svmaffionebdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2) 86251139Sluigi{ 87251139Sluigi struct nmreq nmr; 88251139Sluigi int error = 0; 89251139Sluigi int fd = open("/dev/netmap", O_RDWR); 90251139Sluigi 91251139Sluigi if (fd == -1) { 92251139Sluigi D("Unable to open /dev/netmap"); 93251139Sluigi return -1; 94251139Sluigi } 95251139Sluigi 96251139Sluigi bzero(&nmr, sizeof(nmr)); 97251139Sluigi nmr.nr_version = NETMAP_API; 98251139Sluigi if (name != NULL) /* might be NULL */ 99341432Svmaffione strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)-1); 100251139Sluigi nmr.nr_cmd = nr_cmd; 101270063Sluigi parse_nmr_config(nmr_config, &nmr); 102341432Svmaffione nmr.nr_arg2 = nr_arg2; 103251139Sluigi 104251139Sluigi switch (nr_cmd) { 105270063Sluigi case NETMAP_BDG_DELIF: 106270063Sluigi case NETMAP_BDG_NEWIF: 107270063Sluigi error = ioctl(fd, NIOCREGIF, &nmr); 108270063Sluigi if (error == -1) { 109270063Sluigi ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 110270063Sluigi perror(name); 111270063Sluigi } else { 112270063Sluigi ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 113270063Sluigi } 114270063Sluigi break; 115251139Sluigi case NETMAP_BDG_ATTACH: 116251139Sluigi case NETMAP_BDG_DETACH: 117341432Svmaffione nmr.nr_flags = NR_REG_ALL_NIC; 118341432Svmaffione if (nr_arg && nr_arg != NETMAP_BDG_HOST) { 119341432Svmaffione nmr.nr_flags = NR_REG_NIC_SW; 120251139Sluigi nr_arg = 0; 121341432Svmaffione } 122251139Sluigi nmr.nr_arg1 = nr_arg; 123251139Sluigi error = ioctl(fd, NIOCREGIF, &nmr); 124260700Sluigi if (error == -1) { 125260700Sluigi ND("Unable to %s %s to the bridge", nr_cmd == 126251139Sluigi NETMAP_BDG_DETACH?"detach":"attach", name); 127260700Sluigi perror(name); 128260700Sluigi } else 129260700Sluigi ND("Success to %s %s to the bridge", nr_cmd == 130251139Sluigi NETMAP_BDG_DETACH?"detach":"attach", name); 131251139Sluigi break; 132251139Sluigi 133251139Sluigi case NETMAP_BDG_LIST: 134251139Sluigi if (strlen(nmr.nr_name)) { /* name to bridge/port info */ 135251139Sluigi error = ioctl(fd, NIOCGINFO, &nmr); 136260700Sluigi if (error) { 137260700Sluigi ND("Unable to obtain info for %s", name); 138260700Sluigi perror(name); 139260700Sluigi } else 140251139Sluigi D("%s at bridge:%d port:%d", name, nmr.nr_arg1, 141251139Sluigi nmr.nr_arg2); 142251139Sluigi break; 143251139Sluigi } 144251139Sluigi 145251139Sluigi /* scan all the bridges and ports */ 146251139Sluigi nmr.nr_arg1 = nmr.nr_arg2 = 0; 147251139Sluigi for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) { 148251139Sluigi D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2, 149251139Sluigi nmr.nr_name); 150251139Sluigi nmr.nr_name[0] = '\0'; 151251139Sluigi } 152251139Sluigi 153251139Sluigi break; 154251139Sluigi 155341432Svmaffione case NETMAP_BDG_POLLING_ON: 156341432Svmaffione case NETMAP_BDG_POLLING_OFF: 157341432Svmaffione /* We reuse nmreq fields as follows: 158341432Svmaffione * nr_tx_slots: 0 and non-zero indicate REG_ALL_NIC 159341432Svmaffione * REG_ONE_NIC, respectively. 160341432Svmaffione * nr_rx_slots: CPU core index. This also indicates the 161341432Svmaffione * first queue in the case of REG_ONE_NIC 162341432Svmaffione * nr_tx_rings: (REG_ONE_NIC only) indicates the 163341432Svmaffione * number of CPU cores or the last queue 164341432Svmaffione */ 165341432Svmaffione nmr.nr_flags |= nmr.nr_tx_slots ? 166341432Svmaffione NR_REG_ONE_NIC : NR_REG_ALL_NIC; 167341432Svmaffione nmr.nr_ringid = nmr.nr_rx_slots; 168341432Svmaffione /* number of cores/rings */ 169341432Svmaffione if (nmr.nr_flags == NR_REG_ALL_NIC) 170341432Svmaffione nmr.nr_arg1 = 1; 171341432Svmaffione else 172341432Svmaffione nmr.nr_arg1 = nmr.nr_tx_rings; 173341432Svmaffione 174341432Svmaffione error = ioctl(fd, NIOCREGIF, &nmr); 175341432Svmaffione if (!error) 176341432Svmaffione D("polling on %s %s", nmr.nr_name, 177341432Svmaffione nr_cmd == NETMAP_BDG_POLLING_ON ? 178341432Svmaffione "started" : "stopped"); 179341432Svmaffione else 180341432Svmaffione D("polling on %s %s (err %d)", nmr.nr_name, 181341432Svmaffione nr_cmd == NETMAP_BDG_POLLING_ON ? 182341432Svmaffione "couldn't start" : "couldn't stop", error); 183341432Svmaffione break; 184341432Svmaffione 185251139Sluigi default: /* GINFO */ 186251139Sluigi nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; 187251139Sluigi error = ioctl(fd, NIOCGINFO, &nmr); 188260700Sluigi if (error) { 189260700Sluigi ND("Unable to get if info for %s", name); 190260700Sluigi perror(name); 191260700Sluigi } else 192251139Sluigi D("%s: %d queues.", name, nmr.nr_rx_rings); 193251139Sluigi break; 194251139Sluigi } 195251139Sluigi close(fd); 196251139Sluigi return error; 197251139Sluigi} 198251139Sluigi 199341432Svmaffionestatic void 200341432Svmaffioneusage(int errcode) 201341432Svmaffione{ 202341432Svmaffione fprintf(stderr, 203341432Svmaffione "Usage:\n" 204341432Svmaffione "vale-ctl arguments\n" 205341432Svmaffione "\t-g interface interface name to get info\n" 206341432Svmaffione "\t-d interface interface name to be detached\n" 207341432Svmaffione "\t-a interface interface name to be attached\n" 208341432Svmaffione "\t-h interface interface name to be attached with the host stack\n" 209341432Svmaffione "\t-n interface interface name to be created\n" 210341432Svmaffione "\t-r interface interface name to be deleted\n" 211341432Svmaffione "\t-l list all or specified bridge's interfaces (default)\n" 212341432Svmaffione "\t-C string ring/slot setting of an interface creating by -n\n" 213341432Svmaffione "\t-p interface start polling. Additional -C x,y,z configures\n" 214341432Svmaffione "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n" 215341432Svmaffione "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n" 216341432Svmaffione "\t\t z: (ONE_NIC only) num of total cores/rings\n" 217341432Svmaffione "\t-P interface stop polling\n" 218341432Svmaffione "\t-m memid to use when creating a new interface\n"); 219341432Svmaffione exit(errcode); 220341432Svmaffione} 221341432Svmaffione 222251139Sluigiint 223251139Sluigimain(int argc, char *argv[]) 224251139Sluigi{ 225251139Sluigi int ch, nr_cmd = 0, nr_arg = 0; 226270063Sluigi char *name = NULL, *nmr_config = NULL; 227341432Svmaffione int nr_arg2 = 0; 228251139Sluigi 229341432Svmaffione while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:")) != -1) { 230341432Svmaffione if (ch != 'C' && ch != 'm') 231341432Svmaffione name = optarg; /* default */ 232251139Sluigi switch (ch) { 233251139Sluigi default: 234251139Sluigi fprintf(stderr, "bad option %c %s", ch, optarg); 235341432Svmaffione usage(-1); 236341432Svmaffione break; 237251139Sluigi case 'd': 238251139Sluigi nr_cmd = NETMAP_BDG_DETACH; 239251139Sluigi break; 240251139Sluigi case 'a': 241251139Sluigi nr_cmd = NETMAP_BDG_ATTACH; 242251139Sluigi break; 243251139Sluigi case 'h': 244251139Sluigi nr_cmd = NETMAP_BDG_ATTACH; 245251139Sluigi nr_arg = NETMAP_BDG_HOST; 246251139Sluigi break; 247270063Sluigi case 'n': 248270063Sluigi nr_cmd = NETMAP_BDG_NEWIF; 249270063Sluigi break; 250270063Sluigi case 'r': 251270063Sluigi nr_cmd = NETMAP_BDG_DELIF; 252270063Sluigi break; 253251139Sluigi case 'g': 254251139Sluigi nr_cmd = 0; 255251139Sluigi break; 256251139Sluigi case 'l': 257251139Sluigi nr_cmd = NETMAP_BDG_LIST; 258251139Sluigi break; 259270063Sluigi case 'C': 260270063Sluigi nmr_config = strdup(optarg); 261270063Sluigi break; 262341432Svmaffione case 'p': 263341432Svmaffione nr_cmd = NETMAP_BDG_POLLING_ON; 264341432Svmaffione break; 265341432Svmaffione case 'P': 266341432Svmaffione nr_cmd = NETMAP_BDG_POLLING_OFF; 267341432Svmaffione break; 268341432Svmaffione case 'm': 269341432Svmaffione nr_arg2 = atoi(optarg); 270341432Svmaffione break; 271251139Sluigi } 272251139Sluigi } 273341432Svmaffione if (optind != argc) { 274341432Svmaffione // fprintf(stderr, "optind %d argc %d\n", optind, argc); 275341432Svmaffione usage(-1); 276341432Svmaffione } 277341432Svmaffione if (argc == 1) { 278251139Sluigi nr_cmd = NETMAP_BDG_LIST; 279341432Svmaffione name = NULL; 280341432Svmaffione } 281341432Svmaffione return bdg_ctl(name, nr_cmd, nr_arg, nmr_config, nr_arg2) ? 1 : 0; 282251139Sluigi} 283