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