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