xref: /freebsd/usr.sbin/valectl/valectl.c (revision c7c780553187d5a8ccb6d17e03c43e0c6daf8ecc)
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