diff mbox

[RFC] tap-linux: support opening arbitrary char devices

Message ID 200911262034.04440.arnd@arndb.de
State New
Headers show

Commit Message

Arnd Bergmann Nov. 26, 2009, 7:34 p.m. UTC
With the upcoming macvtap, we will want to open devices other than
/dev/net/tun but no longer need to call TUNSETIFF.

This makes it possible to do 'qemu -net tap,ifname=/dev/tap/macvtap0'
to refer to a chardev in addition to the current way of doing
'qemu -net tap,ifname=tap0' to refer to a tap network interface
set with TUNSETIFF. This is consistent with what we do on BSD.

This is guaranteed not to cause conflicts with existing usage,
because network devices on Linux cannot start with a '/'.

Alternatively, I could do a patch to use the -net tap,name=
parameter which documented to have a similar purpose but not
currently implemented at all.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Comments

Anthony Liguori Dec. 2, 2009, 3:46 p.m. UTC | #1
Arnd Bergmann wrote:
> With the upcoming macvtap, we will want to open devices other than
> /dev/net/tun but no longer need to call TUNSETIFF.
>   

What are the names of these devices and how do you the character devices 
get created in the first place?

This really isn't an "arbitrary" char device as it doesn't implement the 
same interface as tap.  Creation is done in a different manner.

> This makes it possible to do 'qemu -net tap,ifname=/dev/tap/macvtap0'
> to refer to a chardev in addition to the current way of doing
> 'qemu -net tap,ifname=tap0' to refer to a tap network interface
> set with TUNSETIFF. This is consistent with what we do on BSD.
>   

We definitely don't want to overload ifname like this.  
/dev/tap/macvtap0 is clearly not the interface name.

Regards,

Anthony Liguori
Arnd Bergmann Dec. 3, 2009, 1:33 p.m. UTC | #2
On Wednesday 02 December 2009, Anthony Liguori wrote:
> Arnd Bergmann wrote:
> > With the upcoming macvtap, we will want to open devices other than
> > /dev/net/tun but no longer need to call TUNSETIFF.
> >   
> 
> What are the names of these devices and how do you the character devices 
> get created in the first place?

Like a macvlan device, you use iproute2 to set up the interface, e.g.

ip link add link eth0 type macvtap mode vepa

This is consistent with how you'd set up macvlan, veth or vlan devices.
With my current code, the name that gets used for the character
device in absence of a matching udev rule will be /dev/tap%d with %d
being the interface index of the network device.
 
> > This makes it possible to do 'qemu -net tap,ifname=/dev/tap/macvtap0'
> > to refer to a chardev in addition to the current way of doing
> > 'qemu -net tap,ifname=tap0' to refer to a tap network interface
> > set with TUNSETIFF. This is consistent with what we do on BSD.
> 
> We definitely don't want to overload ifname like this.  
> /dev/tap/macvtap0 is clearly not the interface name.

tap interfaces on other operating systems already differ in this respect,
and macvtap seems to be much closer to what BSD and Solaris do
than the Linux tun/tap interface, judging from how they are used
in qemu.

Assuming you have a virtual interface "virteth0" (name made up to
be different from existing ones) with interface index 3, the syntax
would be

* Linux, with tap: (which doesn't really work with arbitrary devices):
qemu -net tap,ifname=virteth0

* Solaris: (opens /dev/tap3)
qemu -net tap,ifname=3

* BSD: (opens /dev/tap3)
qemu -net tap,ifname=tap3

I chose the full path name to be sure it does not conflict with existing
usage, "3" and "tap3" are both valid interface names, "/dev/tap3" is not.

If you prefer, I can add some logic to determine the character device name
from the network interface name, so that you can call it consistently
with the interface name on linux, wether using tun/tap or macvtap.
That patch will be somewhat more complicated than the one I posted.

Alternatively, I can use the documented "name=" parameter for
pointing to the character device, but that would be inconsitent with
the current usage on all the supported OSs.

	Arnd <><
diff mbox

Patch

diff --git a/net/tap-linux.c b/net/tap-linux.c
index 0f621a2..21f0167 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -36,10 +36,20 @@  int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
 {
     struct ifreq ifr;
     int fd, ret;
+    int open_named;
+    char *devname;
+
+    if (ifname_size >= 1 && *ifname == "/") {
+	open_named = 1;
+	devname = ifname;
+    } else {
+	open_named = 0;
+	devname = "/dev/net/tun";
+    }
 
-    TFR(fd = open("/dev/net/tun", O_RDWR));
+    TFR(fd = open(devname, O_RDWR));
     if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
+        fprintf(stderr, "warning: could not open %s: no virtual network emulation\n", devname);
         return -1;
     }
     memset(&ifr, 0, sizeof(ifr));
@@ -62,17 +72,20 @@  int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
         }
     }
 
-    if (ifname[0] != '\0')
-        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
-    else
-        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
-    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
-    if (ret != 0) {
-        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
-        close(fd);
-        return -1;
+    if (!open_named) {
+	if (ifname[0] != '\0')
+	    pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
+	else
+	    pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
+	ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+	if (ret != 0) {
+	    fprintf(stderr, "warning: could not configure %s: no virtual "
+		    "network emulation\n", devname);
+	    close(fd);
+	    return -1;
+	}
+	pstrcpy(ifname, ifname_size, ifr.ifr_name);
     }
-    pstrcpy(ifname, ifname_size, ifr.ifr_name);
     fcntl(fd, F_SETFL, O_NONBLOCK);
     return fd;
 }