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