bridge.c revision 9365d6cf
1/*-
2 *   BSD LICENSE
3 *
4 *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5 *   All rights reserved.
6 *
7 *   Redistribution and use in source and binary forms, with or without
8 *   modification, are permitted provided that the following conditions
9 *   are met:
10 *
11 *     * Redistributions of source code must retain the above copyright
12 *       notice, this list of conditions and the following disclaimer.
13 *     * Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *     * Neither the name of Intel Corporation nor the names of its
18 *       contributors may be used to endorse or promote products derived
19 *       from this software without specific prior written permission.
20 *
21 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <fcntl.h>
35#include <getopt.h>
36#include <inttypes.h>
37#include <signal.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <sys/mman.h>
41
42#include <rte_eal.h>
43#include <rte_ethdev.h>
44#include <rte_mbuf.h>
45#include <rte_mempool.h>
46#include <rte_string_fns.h>
47#include "compat_netmap.h"
48
49
50#define BUF_SIZE	RTE_MBUF_DEFAULT_DATAROOM
51#define MBUF_DATA_SIZE	(BUF_SIZE + RTE_PKTMBUF_HEADROOM)
52
53#define MBUF_PER_POOL	8192
54
55struct rte_eth_conf eth_conf = {
56	.rxmode = {
57		.split_hdr_size = 0,
58		.header_split   = 0,
59		.hw_ip_checksum = 0,
60		.hw_vlan_filter = 0,
61		.jumbo_frame    = 0,
62		.hw_strip_crc   = 1,
63	},
64	.txmode = {
65		.mq_mode = ETH_MQ_TX_NONE,
66	},
67};
68
69#define	MAX_QUEUE_NUM	1
70#define	RX_QUEUE_NUM	1
71#define	TX_QUEUE_NUM	1
72
73#define	MAX_DESC_NUM	0x400
74#define	RX_DESC_NUM	0x100
75#define	TX_DESC_NUM	0x200
76
77#define	RX_SYNC_NUM	0x20
78#define	TX_SYNC_NUM	0x20
79
80struct rte_netmap_port_conf port_conf = {
81	.eth_conf = &eth_conf,
82	.socket_id = SOCKET_ID_ANY,
83	.nr_tx_rings = TX_QUEUE_NUM,
84	.nr_rx_rings = RX_QUEUE_NUM,
85	.nr_tx_slots = TX_DESC_NUM,
86	.nr_rx_slots = RX_DESC_NUM,
87	.tx_burst = TX_SYNC_NUM,
88	.rx_burst = RX_SYNC_NUM,
89};
90
91struct rte_netmap_conf netmap_conf = {
92	.socket_id = SOCKET_ID_ANY,
93	.max_bufsz = BUF_SIZE,
94	.max_rings = MAX_QUEUE_NUM,
95	.max_slots = MAX_DESC_NUM,
96};
97
98static int stop = 0;
99
100#define	MAX_PORT_NUM	2
101
102struct netmap_port {
103	int fd;
104	struct netmap_if *nmif;
105	struct netmap_ring *rx_ring;
106	struct netmap_ring *tx_ring;
107	const char *str;
108	uint8_t id;
109};
110
111static struct {
112	uint32_t num;
113	struct netmap_port p[MAX_PORT_NUM];
114	void *mem;
115} ports;
116
117static void
118usage(const char *prgname)
119{
120	fprintf(stderr, "Usage: %s [EAL args] -- [OPTION]...\n"
121		"-h, --help   \t Show this help message and exit\n"
122		"-i INTERFACE_A   \t Interface (DPDK port number) to use\n"
123		"[ -i INTERFACE_B   \t Interface (DPDK port number) to use ]\n",
124		prgname);
125}
126
127static uint8_t
128parse_portid(const char *portid_str)
129{
130	char *end;
131	unsigned id;
132
133	id = strtoul(portid_str, &end, 10);
134
135	if (end == portid_str || *end != '\0' || id > RTE_MAX_ETHPORTS)
136		rte_exit(EXIT_FAILURE, "Invalid port number\n");
137
138	return (uint8_t) id;
139}
140
141static int
142parse_args(int argc, char **argv)
143{
144	int opt;
145
146	while ((opt = getopt(argc, argv, "hi:")) != -1) {
147		switch (opt) {
148		case 'h':
149			usage(argv[0]);
150			rte_exit(EXIT_SUCCESS, "exiting...");
151			break;
152		case 'i':
153			if (ports.num >= RTE_DIM(ports.p)) {
154				usage(argv[0]);
155				rte_exit(EXIT_FAILURE, "configs with %u "
156					"ports are not supported\n",
157					ports.num + 1);
158
159			}
160
161			ports.p[ports.num].str = optarg;
162			ports.p[ports.num].id = parse_portid(optarg);
163			ports.num++;
164			break;
165		default:
166			usage(argv[0]);
167			rte_exit(EXIT_FAILURE, "invalid option: %c\n", opt);
168		}
169	}
170
171	return 0;
172}
173
174static void sigint_handler(__rte_unused int sig)
175{
176	stop = 1;
177	signal(SIGINT, SIG_DFL);
178}
179
180static void move(int n, struct netmap_ring *rx, struct netmap_ring *tx)
181{
182	uint32_t tmp;
183
184	while (n-- > 0) {
185		tmp = tx->slot[tx->cur].buf_idx;
186
187		tx->slot[tx->cur].buf_idx = rx->slot[rx->cur].buf_idx;
188		tx->slot[tx->cur].len     = rx->slot[rx->cur].len;
189		tx->slot[tx->cur].flags  |= NS_BUF_CHANGED;
190		tx->cur = NETMAP_RING_NEXT(tx, tx->cur);
191		tx->avail--;
192
193		rx->slot[rx->cur].buf_idx = tmp;
194		rx->slot[rx->cur].flags  |= NS_BUF_CHANGED;
195		rx->cur = NETMAP_RING_NEXT(rx, rx->cur);
196		rx->avail--;
197	}
198}
199
200static int
201netmap_port_open(uint32_t idx)
202{
203	int err;
204	struct netmap_port *port;
205	struct nmreq req;
206
207	port = ports.p + idx;
208
209	port->fd = rte_netmap_open("/dev/netmap", O_RDWR);
210
211	snprintf(req.nr_name, sizeof(req.nr_name), "%s", port->str);
212	req.nr_version = NETMAP_API;
213	req.nr_ringid = 0;
214
215	err = rte_netmap_ioctl(port->fd, NIOCGINFO, &req);
216	if (err) {
217		printf("[E] NIOCGINFO ioctl failed (error %d)\n", err);
218		return err;
219	}
220
221	snprintf(req.nr_name, sizeof(req.nr_name), "%s", port->str);
222	req.nr_version = NETMAP_API;
223	req.nr_ringid = 0;
224
225	err = rte_netmap_ioctl(port->fd, NIOCREGIF, &req);
226	if (err) {
227		printf("[E] NIOCREGIF ioctl failed (error %d)\n", err);
228		return err;
229	}
230
231	/* mmap only once. */
232	if (ports.mem == NULL)
233		ports.mem = rte_netmap_mmap(NULL, req.nr_memsize,
234			PROT_WRITE | PROT_READ, MAP_PRIVATE, port->fd, 0);
235
236	if (ports.mem == MAP_FAILED) {
237		printf("[E] NETMAP mmap failed for fd: %d)\n", port->fd);
238		return -ENOMEM;
239	}
240
241	port->nmif = NETMAP_IF(ports.mem, req.nr_offset);
242
243	port->tx_ring = NETMAP_TXRING(port->nmif, 0);
244	port->rx_ring = NETMAP_RXRING(port->nmif, 0);
245
246	return 0;
247}
248
249
250int main(int argc, char *argv[])
251{
252	int err, ret;
253	uint32_t i, pmsk;
254	struct nmreq req;
255	struct pollfd pollfd[MAX_PORT_NUM];
256	struct rte_mempool *pool;
257	struct netmap_ring *rx_ring, *tx_ring;
258
259	ret = rte_eal_init(argc, argv);
260	if (ret < 0)
261		rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n");
262
263	argc -= ret;
264	argv += ret;
265
266	parse_args(argc, argv);
267
268	if (ports.num == 0)
269		rte_exit(EXIT_FAILURE, "no ports specified\n");
270
271	if (rte_eth_dev_count() < 1)
272		rte_exit(EXIT_FAILURE, "Not enough ethernet ports available\n");
273
274	pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0,
275		MBUF_DATA_SIZE, rte_socket_id());
276	if (pool == NULL)
277		rte_exit(EXIT_FAILURE, "Couldn't create mempool\n");
278
279	netmap_conf.socket_id = rte_socket_id();
280	err = rte_netmap_init(&netmap_conf);
281
282	if (err < 0)
283		rte_exit(EXIT_FAILURE,
284			"Couldn't initialize librte_compat_netmap\n");
285	else
286		printf("librte_compat_netmap initialized\n");
287
288	port_conf.pool = pool;
289	port_conf.socket_id = rte_socket_id();
290
291	for (i = 0; i != ports.num; i++) {
292
293		err = rte_netmap_init_port(ports.p[i].id, &port_conf);
294		if (err < 0)
295			rte_exit(EXIT_FAILURE, "Couldn't setup port %hhu\n",
296				ports.p[i].id);
297
298		rte_eth_promiscuous_enable(ports.p[i].id);
299	}
300
301	for (i = 0; i != ports.num; i++) {
302
303		err = netmap_port_open(i);
304		if (err) {
305			rte_exit(EXIT_FAILURE, "Couldn't set port %hhu "
306				"under NETMAP control\n",
307				ports.p[i].id);
308		}
309		else
310			printf("Port %hhu now in Netmap mode\n", ports.p[i].id);
311	}
312
313	memset(pollfd, 0, sizeof(pollfd));
314
315	for (i = 0; i != ports.num; i++) {
316		pollfd[i].fd = ports.p[i].fd;
317		pollfd[i].events = POLLIN | POLLOUT;
318	}
319
320	signal(SIGINT, sigint_handler);
321
322	pmsk = ports.num - 1;
323
324	printf("Bridge up and running!\n");
325
326	while (!stop) {
327		uint32_t n_pkts;
328
329		pollfd[0].revents = 0;
330		pollfd[1].revents = 0;
331
332		ret = rte_netmap_poll(pollfd, ports.num, 0);
333		if (ret < 0) {
334	   		stop = 1;
335	    		printf("[E] poll returned with error %d\n", ret);
336		}
337
338		if (((pollfd[0].revents | pollfd[1].revents) & POLLERR) != 0) {
339			printf("POLLERR!\n");
340		}
341
342		if ((pollfd[0].revents & POLLIN) != 0 &&
343				(pollfd[pmsk].revents & POLLOUT) != 0) {
344
345			rx_ring = ports.p[0].rx_ring;
346			tx_ring = ports.p[pmsk].tx_ring;
347
348			n_pkts = RTE_MIN(rx_ring->avail, tx_ring->avail);
349			move(n_pkts, rx_ring, tx_ring);
350		}
351
352		if (pmsk != 0 && (pollfd[pmsk].revents & POLLIN) != 0 &&
353				(pollfd[0].revents & POLLOUT) != 0) {
354
355			rx_ring = ports.p[pmsk].rx_ring;
356			tx_ring = ports.p[0].tx_ring;
357
358			n_pkts = RTE_MIN(rx_ring->avail, tx_ring->avail);
359			move(n_pkts, rx_ring, tx_ring);
360		}
361	}
362
363	printf("Bridge stopped!\n");
364
365	for (i = 0; i != ports.num; i++) {
366		err = rte_netmap_ioctl(ports.p[i].fd, NIOCUNREGIF, &req);
367		if (err) {
368			printf("[E] NIOCUNREGIF ioctl failed (error %d)\n",
369				err);
370		}
371		else
372			printf("Port %hhu unregistered from Netmap mode\n", ports.p[i].id);
373
374		rte_netmap_close(ports.p[i].fd);
375	}
376	return 0;
377}
378