1251139Sluigi/* 2262151Sluigi * 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$ */ 27251139Sluigi 28251139Sluigi#include <errno.h> 29251139Sluigi#include <stdio.h> 30251139Sluigi#include <inttypes.h> /* PRI* macros */ 31251139Sluigi#include <string.h> /* strcmp */ 32251139Sluigi#include <fcntl.h> /* open */ 33251139Sluigi#include <unistd.h> /* close */ 34251139Sluigi#include <sys/ioctl.h> /* ioctl */ 35251139Sluigi#include <sys/param.h> 36262151Sluigi#include <sys/socket.h> /* apple needs sockaddr */ 37251139Sluigi#include <net/if.h> /* ifreq */ 38251139Sluigi#include <net/netmap.h> 39251139Sluigi#include <net/netmap_user.h> 40251139Sluigi#include <libgen.h> /* basename */ 41270252Sluigi#include <stdlib.h> /* atoi, free */ 42251139Sluigi 43251139Sluigi/* debug support */ 44251139Sluigi#define ND(format, ...) do {} while(0) 45251139Sluigi#define D(format, ...) \ 46251139Sluigi fprintf(stderr, "%s [%d] " format "\n", \ 47251139Sluigi __FUNCTION__, __LINE__, ##__VA_ARGS__) 48251139Sluigi 49270252Sluigi/* XXX cut and paste from pkt-gen.c because I'm not sure whether this 50270252Sluigi * program may include nm_util.h 51270252Sluigi */ 52270252Sluigivoid parse_nmr_config(const char* conf, struct nmreq *nmr) 53270252Sluigi{ 54270252Sluigi char *w, *tok; 55270252Sluigi int i, v; 56270252Sluigi 57270252Sluigi nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 58270252Sluigi nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 59270252Sluigi if (conf == NULL || ! *conf) 60270252Sluigi return; 61270252Sluigi w = strdup(conf); 62270252Sluigi for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 63270252Sluigi v = atoi(tok); 64270252Sluigi switch (i) { 65270252Sluigi case 0: 66270252Sluigi nmr->nr_tx_slots = nmr->nr_rx_slots = v; 67270252Sluigi break; 68270252Sluigi case 1: 69270252Sluigi nmr->nr_rx_slots = v; 70270252Sluigi break; 71270252Sluigi case 2: 72270252Sluigi nmr->nr_tx_rings = nmr->nr_rx_rings = v; 73270252Sluigi break; 74270252Sluigi case 3: 75270252Sluigi nmr->nr_rx_rings = v; 76270252Sluigi break; 77270252Sluigi default: 78270252Sluigi D("ignored config: %s", tok); 79270252Sluigi break; 80270252Sluigi } 81270252Sluigi } 82270252Sluigi D("txr %d txd %d rxr %d rxd %d", 83270252Sluigi nmr->nr_tx_rings, nmr->nr_tx_slots, 84270252Sluigi nmr->nr_rx_rings, nmr->nr_rx_slots); 85270252Sluigi free(w); 86270252Sluigi} 87270252Sluigi 88251139Sluigistatic int 89270252Sluigibdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config) 90251139Sluigi{ 91251139Sluigi struct nmreq nmr; 92251139Sluigi int error = 0; 93251139Sluigi int fd = open("/dev/netmap", O_RDWR); 94251139Sluigi 95251139Sluigi if (fd == -1) { 96251139Sluigi D("Unable to open /dev/netmap"); 97251139Sluigi return -1; 98251139Sluigi } 99251139Sluigi 100251139Sluigi bzero(&nmr, sizeof(nmr)); 101251139Sluigi nmr.nr_version = NETMAP_API; 102251139Sluigi if (name != NULL) /* might be NULL */ 103251139Sluigi strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)); 104251139Sluigi nmr.nr_cmd = nr_cmd; 105270252Sluigi parse_nmr_config(nmr_config, &nmr); 106251139Sluigi 107251139Sluigi switch (nr_cmd) { 108270252Sluigi case NETMAP_BDG_DELIF: 109270252Sluigi case NETMAP_BDG_NEWIF: 110270252Sluigi error = ioctl(fd, NIOCREGIF, &nmr); 111270252Sluigi if (error == -1) { 112270252Sluigi ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 113270252Sluigi perror(name); 114270252Sluigi } else { 115270252Sluigi ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 116270252Sluigi } 117270252Sluigi break; 118251139Sluigi case NETMAP_BDG_ATTACH: 119251139Sluigi case NETMAP_BDG_DETACH: 120251139Sluigi if (nr_arg && nr_arg != NETMAP_BDG_HOST) 121251139Sluigi nr_arg = 0; 122251139Sluigi nmr.nr_arg1 = nr_arg; 123251139Sluigi error = ioctl(fd, NIOCREGIF, &nmr); 124262151Sluigi if (error == -1) { 125262151Sluigi ND("Unable to %s %s to the bridge", nr_cmd == 126251139Sluigi NETMAP_BDG_DETACH?"detach":"attach", name); 127262151Sluigi perror(name); 128262151Sluigi } else 129262151Sluigi 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); 136262151Sluigi if (error) { 137262151Sluigi ND("Unable to obtain info for %s", name); 138262151Sluigi perror(name); 139262151Sluigi } 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 155251139Sluigi default: /* GINFO */ 156251139Sluigi nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; 157251139Sluigi error = ioctl(fd, NIOCGINFO, &nmr); 158262151Sluigi if (error) { 159262151Sluigi ND("Unable to get if info for %s", name); 160262151Sluigi perror(name); 161262151Sluigi } else 162251139Sluigi D("%s: %d queues.", name, nmr.nr_rx_rings); 163251139Sluigi break; 164251139Sluigi } 165251139Sluigi close(fd); 166251139Sluigi return error; 167251139Sluigi} 168251139Sluigi 169251139Sluigiint 170251139Sluigimain(int argc, char *argv[]) 171251139Sluigi{ 172251139Sluigi int ch, nr_cmd = 0, nr_arg = 0; 173251139Sluigi const char *command = basename(argv[0]); 174270252Sluigi char *name = NULL, *nmr_config = NULL; 175251139Sluigi 176262151Sluigi if (argc > 3) { 177251139Sluigiusage: 178251139Sluigi fprintf(stderr, 179251139Sluigi "Usage:\n" 180251139Sluigi "%s arguments\n" 181251139Sluigi "\t-g interface interface name to get info\n" 182251139Sluigi "\t-d interface interface name to be detached\n" 183251139Sluigi "\t-a interface interface name to be attached\n" 184251139Sluigi "\t-h interface interface name to be attached with the host stack\n" 185270252Sluigi "\t-n interface interface name to be created\n" 186270252Sluigi "\t-r interface interface name to be deleted\n" 187262151Sluigi "\t-l list all or specified bridge's interfaces (default)\n" 188270252Sluigi "\t-C string ring/slot setting of an interface creating by -n\n" 189251139Sluigi "", command); 190251139Sluigi return 0; 191251139Sluigi } 192251139Sluigi 193270252Sluigi while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:")) != -1) { 194262151Sluigi name = optarg; /* default */ 195251139Sluigi switch (ch) { 196251139Sluigi default: 197251139Sluigi fprintf(stderr, "bad option %c %s", ch, optarg); 198251139Sluigi goto usage; 199251139Sluigi case 'd': 200251139Sluigi nr_cmd = NETMAP_BDG_DETACH; 201251139Sluigi break; 202251139Sluigi case 'a': 203251139Sluigi nr_cmd = NETMAP_BDG_ATTACH; 204251139Sluigi break; 205251139Sluigi case 'h': 206251139Sluigi nr_cmd = NETMAP_BDG_ATTACH; 207251139Sluigi nr_arg = NETMAP_BDG_HOST; 208251139Sluigi break; 209270252Sluigi case 'n': 210270252Sluigi nr_cmd = NETMAP_BDG_NEWIF; 211270252Sluigi break; 212270252Sluigi case 'r': 213270252Sluigi nr_cmd = NETMAP_BDG_DELIF; 214270252Sluigi break; 215251139Sluigi case 'g': 216251139Sluigi nr_cmd = 0; 217251139Sluigi break; 218251139Sluigi case 'l': 219251139Sluigi nr_cmd = NETMAP_BDG_LIST; 220262151Sluigi if (optind < argc && argv[optind][0] == '-') 221262151Sluigi name = NULL; 222251139Sluigi break; 223270252Sluigi case 'C': 224270252Sluigi nmr_config = strdup(optarg); 225270252Sluigi break; 226251139Sluigi } 227262151Sluigi if (optind != argc) { 228262151Sluigi // fprintf(stderr, "optind %d argc %d\n", optind, argc); 229262151Sluigi goto usage; 230262151Sluigi } 231251139Sluigi } 232251139Sluigi if (argc == 1) 233251139Sluigi nr_cmd = NETMAP_BDG_LIST; 234270252Sluigi return bdg_ctl(name, nr_cmd, nr_arg, nmr_config) ? 1 : 0; 235251139Sluigi} 236