1*c7c78055SVincenzo Maffione /* 2*c7c78055SVincenzo Maffione * Copyright (C) 2013-2014 Michio Honda. All rights reserved. 3*c7c78055SVincenzo Maffione * 4*c7c78055SVincenzo Maffione * Redistribution and use in source and binary forms, with or without 5*c7c78055SVincenzo Maffione * modification, are permitted provided that the following conditions 6*c7c78055SVincenzo Maffione * are met: 7*c7c78055SVincenzo Maffione * 1. Redistributions of source code must retain the above copyright 8*c7c78055SVincenzo Maffione * notice, this list of conditions and the following disclaimer. 9*c7c78055SVincenzo Maffione * 2. Redistributions in binary form must reproduce the above copyright 10*c7c78055SVincenzo Maffione * notice, this list of conditions and the following disclaimer in the 11*c7c78055SVincenzo Maffione * documentation and/or other materials provided with the distribution. 12*c7c78055SVincenzo Maffione * 13*c7c78055SVincenzo Maffione * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*c7c78055SVincenzo Maffione * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*c7c78055SVincenzo Maffione * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*c7c78055SVincenzo Maffione * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*c7c78055SVincenzo Maffione * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*c7c78055SVincenzo Maffione * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*c7c78055SVincenzo Maffione * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*c7c78055SVincenzo Maffione * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*c7c78055SVincenzo Maffione * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*c7c78055SVincenzo Maffione * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*c7c78055SVincenzo Maffione * SUCH DAMAGE. 24*c7c78055SVincenzo Maffione */ 25*c7c78055SVincenzo Maffione 26*c7c78055SVincenzo Maffione /* $FreeBSD$ */ 27*c7c78055SVincenzo Maffione 28*c7c78055SVincenzo Maffione #define NETMAP_WITH_LIBS 29*c7c78055SVincenzo Maffione #include <net/netmap_user.h> 30*c7c78055SVincenzo Maffione #include <net/netmap.h> 31*c7c78055SVincenzo Maffione 32*c7c78055SVincenzo Maffione #include <errno.h> 33*c7c78055SVincenzo Maffione #include <stdio.h> 34*c7c78055SVincenzo Maffione #include <inttypes.h> /* PRI* macros */ 35*c7c78055SVincenzo Maffione #include <string.h> /* strcmp */ 36*c7c78055SVincenzo Maffione #include <fcntl.h> /* open */ 37*c7c78055SVincenzo Maffione #include <unistd.h> /* close */ 38*c7c78055SVincenzo Maffione #include <sys/ioctl.h> /* ioctl */ 39*c7c78055SVincenzo Maffione #include <sys/param.h> 40*c7c78055SVincenzo Maffione #include <sys/socket.h> /* apple needs sockaddr */ 41*c7c78055SVincenzo Maffione #include <net/if.h> /* ifreq */ 42*c7c78055SVincenzo Maffione #include <libgen.h> /* basename */ 43*c7c78055SVincenzo Maffione #include <stdlib.h> /* atoi, free */ 44*c7c78055SVincenzo Maffione 45*c7c78055SVincenzo Maffione static void 46*c7c78055SVincenzo Maffione parse_nmr_config(const char* conf, struct nmreq *nmr) 47*c7c78055SVincenzo Maffione { 48*c7c78055SVincenzo Maffione char *w, *tok; 49*c7c78055SVincenzo Maffione int i, v; 50*c7c78055SVincenzo Maffione 51*c7c78055SVincenzo Maffione nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 52*c7c78055SVincenzo Maffione nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 53*c7c78055SVincenzo Maffione if (conf == NULL || ! *conf) 54*c7c78055SVincenzo Maffione return; 55*c7c78055SVincenzo Maffione w = strdup(conf); 56*c7c78055SVincenzo Maffione for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 57*c7c78055SVincenzo Maffione v = atoi(tok); 58*c7c78055SVincenzo Maffione switch (i) { 59*c7c78055SVincenzo Maffione case 0: 60*c7c78055SVincenzo Maffione nmr->nr_tx_slots = nmr->nr_rx_slots = v; 61*c7c78055SVincenzo Maffione break; 62*c7c78055SVincenzo Maffione case 1: 63*c7c78055SVincenzo Maffione nmr->nr_rx_slots = v; 64*c7c78055SVincenzo Maffione break; 65*c7c78055SVincenzo Maffione case 2: 66*c7c78055SVincenzo Maffione nmr->nr_tx_rings = nmr->nr_rx_rings = v; 67*c7c78055SVincenzo Maffione break; 68*c7c78055SVincenzo Maffione case 3: 69*c7c78055SVincenzo Maffione nmr->nr_rx_rings = v; 70*c7c78055SVincenzo Maffione break; 71*c7c78055SVincenzo Maffione default: 72*c7c78055SVincenzo Maffione D("ignored config: %s", tok); 73*c7c78055SVincenzo Maffione break; 74*c7c78055SVincenzo Maffione } 75*c7c78055SVincenzo Maffione } 76*c7c78055SVincenzo Maffione D("txr %d txd %d rxr %d rxd %d", 77*c7c78055SVincenzo Maffione nmr->nr_tx_rings, nmr->nr_tx_slots, 78*c7c78055SVincenzo Maffione nmr->nr_rx_rings, nmr->nr_rx_slots); 79*c7c78055SVincenzo Maffione free(w); 80*c7c78055SVincenzo Maffione } 81*c7c78055SVincenzo Maffione 82*c7c78055SVincenzo Maffione static int 83*c7c78055SVincenzo Maffione bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config, int nr_arg2) 84*c7c78055SVincenzo Maffione { 85*c7c78055SVincenzo Maffione struct nmreq nmr; 86*c7c78055SVincenzo Maffione int error = 0; 87*c7c78055SVincenzo Maffione int fd = open("/dev/netmap", O_RDWR); 88*c7c78055SVincenzo Maffione 89*c7c78055SVincenzo Maffione if (fd == -1) { 90*c7c78055SVincenzo Maffione D("Unable to open /dev/netmap"); 91*c7c78055SVincenzo Maffione return -1; 92*c7c78055SVincenzo Maffione } 93*c7c78055SVincenzo Maffione 94*c7c78055SVincenzo Maffione bzero(&nmr, sizeof(nmr)); 95*c7c78055SVincenzo Maffione nmr.nr_version = NETMAP_API; 96*c7c78055SVincenzo Maffione if (name != NULL) /* might be NULL */ 97*c7c78055SVincenzo Maffione strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)-1); 98*c7c78055SVincenzo Maffione nmr.nr_cmd = nr_cmd; 99*c7c78055SVincenzo Maffione parse_nmr_config(nmr_config, &nmr); 100*c7c78055SVincenzo Maffione nmr.nr_arg2 = nr_arg2; 101*c7c78055SVincenzo Maffione 102*c7c78055SVincenzo Maffione switch (nr_cmd) { 103*c7c78055SVincenzo Maffione case NETMAP_BDG_DELIF: 104*c7c78055SVincenzo Maffione case NETMAP_BDG_NEWIF: 105*c7c78055SVincenzo Maffione error = ioctl(fd, NIOCREGIF, &nmr); 106*c7c78055SVincenzo Maffione if (error == -1) { 107*c7c78055SVincenzo Maffione ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 108*c7c78055SVincenzo Maffione perror(name); 109*c7c78055SVincenzo Maffione } else { 110*c7c78055SVincenzo Maffione ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 111*c7c78055SVincenzo Maffione } 112*c7c78055SVincenzo Maffione break; 113*c7c78055SVincenzo Maffione case NETMAP_BDG_ATTACH: 114*c7c78055SVincenzo Maffione case NETMAP_BDG_DETACH: 115*c7c78055SVincenzo Maffione nmr.nr_flags = NR_REG_ALL_NIC; 116*c7c78055SVincenzo Maffione if (nr_arg && nr_arg != NETMAP_BDG_HOST) { 117*c7c78055SVincenzo Maffione nmr.nr_flags = NR_REG_NIC_SW; 118*c7c78055SVincenzo Maffione nr_arg = 0; 119*c7c78055SVincenzo Maffione } 120*c7c78055SVincenzo Maffione nmr.nr_arg1 = nr_arg; 121*c7c78055SVincenzo Maffione error = ioctl(fd, NIOCREGIF, &nmr); 122*c7c78055SVincenzo Maffione if (error == -1) { 123*c7c78055SVincenzo Maffione ND("Unable to %s %s to the bridge", nr_cmd == 124*c7c78055SVincenzo Maffione NETMAP_BDG_DETACH?"detach":"attach", name); 125*c7c78055SVincenzo Maffione perror(name); 126*c7c78055SVincenzo Maffione } else 127*c7c78055SVincenzo Maffione ND("Success to %s %s to the bridge", nr_cmd == 128*c7c78055SVincenzo Maffione NETMAP_BDG_DETACH?"detach":"attach", name); 129*c7c78055SVincenzo Maffione break; 130*c7c78055SVincenzo Maffione 131*c7c78055SVincenzo Maffione case NETMAP_BDG_LIST: 132*c7c78055SVincenzo Maffione if (strlen(nmr.nr_name)) { /* name to bridge/port info */ 133*c7c78055SVincenzo Maffione error = ioctl(fd, NIOCGINFO, &nmr); 134*c7c78055SVincenzo Maffione if (error) { 135*c7c78055SVincenzo Maffione ND("Unable to obtain info for %s", name); 136*c7c78055SVincenzo Maffione perror(name); 137*c7c78055SVincenzo Maffione } else 138*c7c78055SVincenzo Maffione D("%s at bridge:%d port:%d", name, nmr.nr_arg1, 139*c7c78055SVincenzo Maffione nmr.nr_arg2); 140*c7c78055SVincenzo Maffione break; 141*c7c78055SVincenzo Maffione } 142*c7c78055SVincenzo Maffione 143*c7c78055SVincenzo Maffione /* scan all the bridges and ports */ 144*c7c78055SVincenzo Maffione nmr.nr_arg1 = nmr.nr_arg2 = 0; 145*c7c78055SVincenzo Maffione for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) { 146*c7c78055SVincenzo Maffione D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2, 147*c7c78055SVincenzo Maffione nmr.nr_name); 148*c7c78055SVincenzo Maffione nmr.nr_name[0] = '\0'; 149*c7c78055SVincenzo Maffione } 150*c7c78055SVincenzo Maffione 151*c7c78055SVincenzo Maffione break; 152*c7c78055SVincenzo Maffione 153*c7c78055SVincenzo Maffione case NETMAP_BDG_POLLING_ON: 154*c7c78055SVincenzo Maffione case NETMAP_BDG_POLLING_OFF: 155*c7c78055SVincenzo Maffione /* We reuse nmreq fields as follows: 156*c7c78055SVincenzo Maffione * nr_tx_slots: 0 and non-zero indicate REG_ALL_NIC 157*c7c78055SVincenzo Maffione * REG_ONE_NIC, respectively. 158*c7c78055SVincenzo Maffione * nr_rx_slots: CPU core index. This also indicates the 159*c7c78055SVincenzo Maffione * first queue in the case of REG_ONE_NIC 160*c7c78055SVincenzo Maffione * nr_tx_rings: (REG_ONE_NIC only) indicates the 161*c7c78055SVincenzo Maffione * number of CPU cores or the last queue 162*c7c78055SVincenzo Maffione */ 163*c7c78055SVincenzo Maffione nmr.nr_flags |= nmr.nr_tx_slots ? 164*c7c78055SVincenzo Maffione NR_REG_ONE_NIC : NR_REG_ALL_NIC; 165*c7c78055SVincenzo Maffione nmr.nr_ringid = nmr.nr_rx_slots; 166*c7c78055SVincenzo Maffione /* number of cores/rings */ 167*c7c78055SVincenzo Maffione if (nmr.nr_flags == NR_REG_ALL_NIC) 168*c7c78055SVincenzo Maffione nmr.nr_arg1 = 1; 169*c7c78055SVincenzo Maffione else 170*c7c78055SVincenzo Maffione nmr.nr_arg1 = nmr.nr_tx_rings; 171*c7c78055SVincenzo Maffione 172*c7c78055SVincenzo Maffione error = ioctl(fd, NIOCREGIF, &nmr); 173*c7c78055SVincenzo Maffione if (!error) 174*c7c78055SVincenzo Maffione D("polling on %s %s", nmr.nr_name, 175*c7c78055SVincenzo Maffione nr_cmd == NETMAP_BDG_POLLING_ON ? 176*c7c78055SVincenzo Maffione "started" : "stopped"); 177*c7c78055SVincenzo Maffione else 178*c7c78055SVincenzo Maffione D("polling on %s %s (err %d)", nmr.nr_name, 179*c7c78055SVincenzo Maffione nr_cmd == NETMAP_BDG_POLLING_ON ? 180*c7c78055SVincenzo Maffione "couldn't start" : "couldn't stop", error); 181*c7c78055SVincenzo Maffione break; 182*c7c78055SVincenzo Maffione 183*c7c78055SVincenzo Maffione default: /* GINFO */ 184*c7c78055SVincenzo Maffione nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; 185*c7c78055SVincenzo Maffione error = ioctl(fd, NIOCGINFO, &nmr); 186*c7c78055SVincenzo Maffione if (error) { 187*c7c78055SVincenzo Maffione ND("Unable to get if info for %s", name); 188*c7c78055SVincenzo Maffione perror(name); 189*c7c78055SVincenzo Maffione } else 190*c7c78055SVincenzo Maffione D("%s: %d queues.", name, nmr.nr_rx_rings); 191*c7c78055SVincenzo Maffione break; 192*c7c78055SVincenzo Maffione } 193*c7c78055SVincenzo Maffione close(fd); 194*c7c78055SVincenzo Maffione return error; 195*c7c78055SVincenzo Maffione } 196*c7c78055SVincenzo Maffione 197*c7c78055SVincenzo Maffione static void 198*c7c78055SVincenzo Maffione usage(int errcode) 199*c7c78055SVincenzo Maffione { 200*c7c78055SVincenzo Maffione fprintf(stderr, 201*c7c78055SVincenzo Maffione "Usage:\n" 202*c7c78055SVincenzo Maffione "valectl arguments\n" 203*c7c78055SVincenzo Maffione "\t-g interface interface name to get info\n" 204*c7c78055SVincenzo Maffione "\t-d interface interface name to be detached\n" 205*c7c78055SVincenzo Maffione "\t-a interface interface name to be attached\n" 206*c7c78055SVincenzo Maffione "\t-h interface interface name to be attached with the host stack\n" 207*c7c78055SVincenzo Maffione "\t-n interface interface name to be created\n" 208*c7c78055SVincenzo Maffione "\t-r interface interface name to be deleted\n" 209*c7c78055SVincenzo Maffione "\t-l list all or specified bridge's interfaces (default)\n" 210*c7c78055SVincenzo Maffione "\t-C string ring/slot setting of an interface creating by -n\n" 211*c7c78055SVincenzo Maffione "\t-p interface start polling. Additional -C x,y,z configures\n" 212*c7c78055SVincenzo Maffione "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n" 213*c7c78055SVincenzo Maffione "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n" 214*c7c78055SVincenzo Maffione "\t\t z: (ONE_NIC only) num of total cores/rings\n" 215*c7c78055SVincenzo Maffione "\t-P interface stop polling\n" 216*c7c78055SVincenzo Maffione "\t-m memid to use when creating a new interface\n"); 217*c7c78055SVincenzo Maffione exit(errcode); 218*c7c78055SVincenzo Maffione } 219*c7c78055SVincenzo Maffione 220*c7c78055SVincenzo Maffione int 221*c7c78055SVincenzo Maffione main(int argc, char *argv[]) 222*c7c78055SVincenzo Maffione { 223*c7c78055SVincenzo Maffione int ch, nr_cmd = 0, nr_arg = 0; 224*c7c78055SVincenzo Maffione char *name = NULL, *nmr_config = NULL; 225*c7c78055SVincenzo Maffione int nr_arg2 = 0; 226*c7c78055SVincenzo Maffione 227*c7c78055SVincenzo Maffione while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:m:")) != -1) { 228*c7c78055SVincenzo Maffione if (ch != 'C' && ch != 'm') 229*c7c78055SVincenzo Maffione name = optarg; /* default */ 230*c7c78055SVincenzo Maffione switch (ch) { 231*c7c78055SVincenzo Maffione default: 232*c7c78055SVincenzo Maffione fprintf(stderr, "bad option %c %s", ch, optarg); 233*c7c78055SVincenzo Maffione usage(-1); 234*c7c78055SVincenzo Maffione break; 235*c7c78055SVincenzo Maffione case 'd': 236*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_DETACH; 237*c7c78055SVincenzo Maffione break; 238*c7c78055SVincenzo Maffione case 'a': 239*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_ATTACH; 240*c7c78055SVincenzo Maffione break; 241*c7c78055SVincenzo Maffione case 'h': 242*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_ATTACH; 243*c7c78055SVincenzo Maffione nr_arg = NETMAP_BDG_HOST; 244*c7c78055SVincenzo Maffione break; 245*c7c78055SVincenzo Maffione case 'n': 246*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_NEWIF; 247*c7c78055SVincenzo Maffione break; 248*c7c78055SVincenzo Maffione case 'r': 249*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_DELIF; 250*c7c78055SVincenzo Maffione break; 251*c7c78055SVincenzo Maffione case 'g': 252*c7c78055SVincenzo Maffione nr_cmd = 0; 253*c7c78055SVincenzo Maffione break; 254*c7c78055SVincenzo Maffione case 'l': 255*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_LIST; 256*c7c78055SVincenzo Maffione break; 257*c7c78055SVincenzo Maffione case 'C': 258*c7c78055SVincenzo Maffione nmr_config = strdup(optarg); 259*c7c78055SVincenzo Maffione break; 260*c7c78055SVincenzo Maffione case 'p': 261*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_POLLING_ON; 262*c7c78055SVincenzo Maffione break; 263*c7c78055SVincenzo Maffione case 'P': 264*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_POLLING_OFF; 265*c7c78055SVincenzo Maffione break; 266*c7c78055SVincenzo Maffione case 'm': 267*c7c78055SVincenzo Maffione nr_arg2 = atoi(optarg); 268*c7c78055SVincenzo Maffione break; 269*c7c78055SVincenzo Maffione } 270*c7c78055SVincenzo Maffione } 271*c7c78055SVincenzo Maffione if (optind != argc) { 272*c7c78055SVincenzo Maffione // fprintf(stderr, "optind %d argc %d\n", optind, argc); 273*c7c78055SVincenzo Maffione usage(-1); 274*c7c78055SVincenzo Maffione } 275*c7c78055SVincenzo Maffione if (argc == 1) { 276*c7c78055SVincenzo Maffione nr_cmd = NETMAP_BDG_LIST; 277*c7c78055SVincenzo Maffione name = NULL; 278*c7c78055SVincenzo Maffione } 279*c7c78055SVincenzo Maffione return bdg_ctl(name, nr_cmd, nr_arg, nmr_config, nr_arg2) ? 1 : 0; 280*c7c78055SVincenzo Maffione } 281