
On 01/20/2013 11:22 AM, Roman Bogorodskiy wrote:
--- src/util/virnetdevtap.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-)
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index a884de1..1b02e1f 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -103,7 +103,7 @@ virNetDevProbeVnetHdr(int tapfd) #endif
-#ifdef TUNSETIFF +#if defined(TUNSETIFF) /** * virNetDevTapCreate: * @ifname: the interface name @@ -230,7 +230,113 @@ cleanup: VIR_FORCE_CLOSE(fd); return ret; } -#else /* ! TUNSETIFF */ +#elif defined(__FreeBSD__) +int virNetDevTapCreate(char **ifname, + int *tapfd, + unsigned int flags ATTRIBUTE_UNUSED) +{ + int s; + struct ifreq ifr; + int ret = -1; + char *newifname = NULL; + + /* As FreeBSD determines interface type by name, + * we have to create 'tap' interface first and + * then rename it to 'vnet' + */ + if ((s = virNetDevSetupControl("tap", &ifr)) < 0) + return -1; + + if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) { + virReportSystemError(errno, "%s", + _("Unable to create tap device")); + goto cleanup; + }
Trying to figure the relationship between this socket and the file (eg, tapfd) created below).
+ + /* In case we were given exact interface name (e.g. 'vnetN'), + * we just rename to it. If we have format string like + * 'vnet%d', we need to find the first available name that + * matches this pattern + */ + if (strstr(*ifname, "%d") == NULL) { + newifname = strdup(*ifname); + } else { + int i; + for (i = 0; i <= 255; i++) { + virBuffer newname = VIR_BUFFER_INITIALIZER; + virBufferAsprintf(&newname, *ifname, i); + + if (virBufferError(&newname)) { + virBufferFreeAndReset(&newname); + virReportOOMError(); + goto cleanup; + } + + if (virNetDevExists(virBufferCurrentContent(&newname)) == 0) { + newifname = strdup(virBufferContentAndReset(&newname)); + break; + } + } + } + + VIR_FREE(*ifname); + + if (newifname == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to generate new name for interface %s"), + ifr.ifr_name); + goto cleanup; + }
My comments from v1 still apply above. Since the "else" part of the above check is just replacing *ifname, then that's the only time we need to mess with *ifname. That is use "!=" and just replace *ifname at the end of the for loop as long as we generated one. The error message here would be wrong if you went through the existing "if" condition - it failed to strdup(). Thus you have: if (strstr(*ifname, "%d") != NULL) { int i; for (i = 0; i <= 255; i++) { virBuffer newname = VIR_BUFFER_INITIALIZER; virBufferAsprintf(&newname, *ifname, i); if (virBufferError(&newname)) { virBufferFreeAndReset(&newname); virReportOOMError(); goto cleanup; } if (virNetDevExists(virBufferCurrentContent(&newname)) == 0) { newifname = strdup(virBufferContentAndReset(&newname)); break; } } if (newifname) { VIR_FREE(*ifname); *ifname = newifname; } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Failed to generate new name for interface %s"), ifr.ifr_name); goto cleanup; } } Also, I missed this the first time around, is there an existing constant for 255? Or is it/will it be dynamic? Beyond that I have some "thoughts" around the use of 255. First, it could be a time consuming loop - there's a lot of open, ioctl/check, close going on (and that doesn't include all the printf & Buffer mgmt code). Second, what are the chances some day someone wants 1024 tap devices. This loop is then outdated and even worse performance wise. It's too bad there isn't a way to just request the next available device and let the driver handle things rather than a linear algorithm which will cause performance problems some day. Yes, I've been down this road before.
+ + if (virNetDevSetName(ifr.ifr_name, newifname) == -1) {
Assuming the above change, then 's/newifname/*ifname/'
+ goto cleanup; + } + + *ifname = newifname;
Removing the above too. The way the code is written now, if you goto cleanup from the SetName, then newifname is leaked.
+ + if (tapfd) { + char *dev_path = NULL; + if (virAsprintf(&dev_path, "/dev/%s", *ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + *tapfd = open(dev_path, O_RDWR); + + VIR_FREE(dev_path); + } + + ret = 0; +cleanup: + if (ret < 0) + VIR_FORCE_CLOSE(s); + + return ret; +}
On success, we leave here with 's' and 'tapfd' being opened, right? Since the TapDelete will open another 's', should the "if (ret < 0)" above be removed and we always close 's'? If tapfd == NULL, then what happens? Shouldn't the device path still be opened & closed (like the "existing" code)? As it stands you return zero, but haven't necessarily opened the new dev_path. I'm trying to learn the relationship between the two. What happens when/if *tapfd == -1 because open() failed? and ret = 0?
+ +int virNetDevTapDelete(const char *ifname) +{ + int s; + struct ifreq ifr; + int ret = -1; + + if ((s = virNetDevSetupControl(ifname, &ifr)) < 0) + return -1; + + if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) { + virReportSystemError(errno, + _("Unable to remove tap device %s"), + ifname); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FORCE_CLOSE(s); + return ret; +} + +#else /* !defined(__FreeBSD__) */ int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED, int *tapfd ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) @@ -245,7 +351,7 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED) _("Unable to delete TAP devices on this platform")); return -1; } -#endif /* ! TUNSETIFF */ +#endif
/**