Browse Source

[linux] Add the tap driver

Add the tap driver that can be used like:
$ ./ipxe.linux --net tap,if=tap0,mac=00:0c:29:c5:39:a1
The if setting is mandatory.

Signed-off-by: Piotr Jaroszyński <p.jaroszynski@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Piotr Jaroszyński 14 years ago
parent
commit
d60cbe43b7
4 changed files with 257 additions and 0 deletions
  1. 5
    0
      src/config/config.c
  2. 2
    0
      src/config/defaults/linux.h
  3. 249
    0
      src/drivers/linux/tap.c
  4. 1
    0
      src/include/ipxe/errfile.h

+ 5
- 0
src/config/config.c View File

@@ -263,3 +263,8 @@ REQUIRE_OBJECT ( gdbstub_cmd );
263 263
  */
264 264
 REQUIRE_OBJECT ( device );
265 265
 REQUIRE_OBJECT ( embedded );
266
+
267
+/* linux drivers aren't picked up by the parserom utility so drag them in here */
268
+#ifdef DRIVERS_LINUX
269
+REQUIRE_OBJECT ( tap );
270
+#endif

+ 2
- 0
src/config/defaults/linux.h View File

@@ -14,6 +14,8 @@
14 14
 #define NAP_LINUX
15 15
 #define SMBIOS_LINUX
16 16
 
17
+#define DRIVERS_LINUX
18
+
17 19
 #define IMAGE_SCRIPT
18 20
 
19 21
 #endif /* CONFIG_DEFAULTS_LINUX_H */

+ 249
- 0
src/drivers/linux/tap.c View File

@@ -0,0 +1,249 @@
1
+/*
2
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
+ */
18
+
19
+#include <errno.h>
20
+#include <string.h>
21
+#include <stdio.h>
22
+#include <linux_api.h>
23
+#include <ipxe/list.h>
24
+#include <ipxe/linux.h>
25
+#include <ipxe/malloc.h>
26
+#include <ipxe/device.h>
27
+#include <ipxe/netdevice.h>
28
+#include <ipxe/iobuf.h>
29
+#include <ipxe/ethernet.h>
30
+#include <ipxe/settings.h>
31
+#include <ipxe/socket.h>
32
+
33
+/* This hack prevents pre-2.6.32 headers from redefining struct sockaddr */
34
+#define __GLIBC__ 2
35
+#include <linux/socket.h>
36
+#undef __GLIBC__
37
+#include <linux/if.h>
38
+#include <linux/if_ether.h>
39
+#include <linux/if_tun.h>
40
+
41
+#define RX_BUF_SIZE 1536
42
+
43
+/** @file
44
+ *
45
+ * The TAP driver.
46
+ *
47
+ * The TAP is a Virtual Ethernet network device.
48
+ */
49
+
50
+struct tap_nic {
51
+	/** Tap interface name */
52
+	char * interface;
53
+	/** File descriptor of the opened tap device */
54
+	int fd;
55
+};
56
+
57
+/** Open the TAP device */
58
+static int tap_open(struct net_device * netdev)
59
+{
60
+	struct tap_nic * nic = netdev->priv;
61
+	struct ifreq ifr;
62
+	int ret;
63
+
64
+	nic->fd = linux_open("/dev/net/tun", O_RDWR);
65
+	if (nic->fd < 0) {
66
+		DBGC(nic, "tap %p open('/dev/net/tun') = %d (%s)\n", nic, nic->fd, linux_strerror(linux_errno));
67
+		return nic->fd;
68
+	}
69
+
70
+	memset(&ifr, 0, sizeof(ifr));
71
+	/* IFF_NO_PI for no extra packet information */
72
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
73
+	strncpy(ifr.ifr_name, nic->interface, IFNAMSIZ);
74
+	DBGC(nic, "tap %p interface = '%s'\n", nic, nic->interface);
75
+
76
+	ret = linux_ioctl(nic->fd, TUNSETIFF, &ifr);
77
+
78
+	if (ret != 0) {
79
+		DBGC(nic, "tap %p ioctl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
80
+		linux_close(nic->fd);
81
+		return ret;
82
+	}
83
+
84
+	/* Set nonblocking mode to make tap_poll easier */
85
+	ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
86
+
87
+	if (ret != 0) {
88
+		DBGC(nic, "tap %p fcntl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
89
+		linux_close(nic->fd);
90
+		return ret;
91
+	}
92
+
93
+	return 0;
94
+}
95
+
96
+/** Close the TAP device */
97
+static void tap_close(struct net_device *netdev)
98
+{
99
+	struct tap_nic * nic = netdev->priv;
100
+	linux_close(nic->fd);
101
+}
102
+
103
+/**
104
+ * Transmit an ethernet packet.
105
+ *
106
+ * The packet can be written to the TAP device and marked as complete immediately.
107
+ */
108
+static int tap_transmit(struct net_device *netdev, struct io_buffer *iobuf)
109
+{
110
+	struct tap_nic * nic = netdev->priv;
111
+	int rc;
112
+
113
+	/* Pad and align packet */
114
+	iob_pad(iobuf, ETH_ZLEN);
115
+
116
+	rc = linux_write(nic->fd, iobuf->data, iobuf->tail - iobuf->data);
117
+	DBGC2(nic, "tap %p wrote %d bytes\n", nic, rc);
118
+	netdev_tx_complete(netdev, iobuf);
119
+
120
+	return 0;
121
+}
122
+
123
+/** Poll for new packets */
124
+static void tap_poll(struct net_device *netdev)
125
+{
126
+	struct tap_nic * nic = netdev->priv;
127
+	struct pollfd pfd;
128
+	struct io_buffer * iobuf;
129
+	int r;
130
+
131
+	pfd.fd = nic->fd;
132
+	pfd.events = POLLIN;
133
+	if (linux_poll(&pfd, 1, 0) == -1) {
134
+		DBGC(nic, "tap %p poll failed (%s)\n", nic, linux_strerror(linux_errno));
135
+		return;
136
+	}
137
+	if ((pfd.revents & POLLIN) == 0)
138
+		return;
139
+
140
+	/* At this point we know there is at least one new packet to be read */
141
+
142
+	iobuf = alloc_iob(RX_BUF_SIZE);
143
+	if (! iobuf)
144
+		goto allocfail;
145
+
146
+	while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
147
+		DBGC2(nic, "tap %p read %d bytes\n", nic, r);
148
+
149
+		iob_put(iobuf, r);
150
+		netdev_rx(netdev, iobuf);
151
+
152
+		iobuf = alloc_iob(RX_BUF_SIZE);
153
+		if (! iobuf)
154
+			goto allocfail;
155
+	}
156
+
157
+	free_iob(iobuf);
158
+	return;
159
+
160
+allocfail:
161
+	DBGC(nic, "tap %p alloc_iob failed\n", nic);
162
+}
163
+
164
+/**
165
+ * Set irq.
166
+ *
167
+ * Not used on linux, provide a dummy implementation.
168
+ */
169
+static void tap_irq(struct net_device *netdev, int enable)
170
+{
171
+	struct tap_nic *nic = netdev->priv;
172
+
173
+	DBGC(nic, "tap %p irq enable = %d\n", nic, enable);
174
+}
175
+
176
+/** Tap operations */
177
+static struct net_device_operations tap_operations = {
178
+	.open		= tap_open,
179
+	.close		= tap_close,
180
+	.transmit	= tap_transmit,
181
+	.poll		= tap_poll,
182
+	.irq		= tap_irq,
183
+};
184
+
185
+/** Handle a device request for the tap driver */
186
+static int tap_probe(struct linux_device *device, struct linux_device_request *request)
187
+{
188
+	struct linux_setting *if_setting;
189
+	struct net_device *netdev;
190
+	struct tap_nic *nic;
191
+	int rc;
192
+
193
+	netdev = alloc_etherdev(sizeof(*nic));
194
+	if (! netdev)
195
+		return -ENOMEM;
196
+
197
+	netdev_init(netdev, &tap_operations);
198
+	nic = netdev->priv;
199
+	linux_set_drvdata(device, netdev);
200
+	netdev->dev = &device->dev;
201
+	memset(nic, 0, sizeof(*nic));
202
+
203
+	netdev_link_up(netdev);
204
+
205
+	if ((rc = register_netdev(netdev)) != 0)
206
+		goto err_register;
207
+
208
+	/* Look for the mandatory if setting */
209
+	if_setting = linux_find_setting("if", &request->settings);
210
+
211
+	/* No if setting */
212
+	if (! if_setting) {
213
+		printf("tap missing a mandatory if setting\n");
214
+		rc = -EINVAL;
215
+		goto err_settings;
216
+	}
217
+
218
+	nic->interface = if_setting->value;
219
+	if_setting->applied = 1;
220
+
221
+	/* Apply rest of the settings */
222
+	linux_apply_settings(&request->settings, &netdev->settings.settings);
223
+
224
+	return 0;
225
+
226
+err_settings:
227
+	unregister_netdev(netdev);
228
+err_register:
229
+	netdev_nullify(netdev);
230
+	netdev_put(netdev);
231
+	return rc;
232
+}
233
+
234
+/** Remove the device */
235
+static void tap_remove(struct linux_device *device)
236
+{
237
+	struct net_device *netdev = linux_get_drvdata(device);
238
+	unregister_netdev(netdev);
239
+	netdev_nullify(netdev);
240
+	netdev_put(netdev);
241
+}
242
+
243
+/** Tap linux_driver */
244
+struct linux_driver tap_driver __linux_driver = {
245
+	.name = "tap",
246
+	.probe = tap_probe,
247
+	.remove = tap_remove,
248
+	.can_probe = 1,
249
+};

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -128,6 +128,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
128 128
 #define ERRFILE_snponly		     ( ERRFILE_DRIVER | 0x005a0000 )
129 129
 #define ERRFILE_jme		     ( ERRFILE_DRIVER | 0x005b0000 )
130 130
 #define ERRFILE_virtio_net	     ( ERRFILE_DRIVER | 0x005c0000 )
131
+#define ERRFILE_tap		     ( ERRFILE_DRIVER | 0x005d0000 )
131 132
 
132 133
 #define ERRFILE_scsi		     ( ERRFILE_DRIVER | 0x00700000 )
133 134
 #define ERRFILE_arbel		     ( ERRFILE_DRIVER | 0x00710000 )

Loading…
Cancel
Save