---
src/util/virnetdevtap.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 137 insertions(+), 3 deletions(-)
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index a884de1..426d629 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,141 @@ 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;
+
+ s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (s < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to create socket"));
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (virStrcpyStatic(ifr.ifr_name, "tap") == NULL) {
+ virReportSystemError(ERANGE,
+ _("Network interface name '%s' is too
long"),
+ *ifname);
+ goto cleanup;
+
+ }
+
+ if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create tap device %s"),
+ NULLSTR(*ifname));
+ goto cleanup;
+ }
+
+ char *newifname = NULL;
+ if (strstr(*ifname, "%d") == NULL) {
+ newifname = *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();
+ ret = - 1;
+ goto cleanup;
+ }
+
+ if (virNetDevExists(virBufferCurrentContent(&newname)) == 0) {
+ newifname = strdup(virBufferContentAndReset(&newname));
+ break;
+ }
+ }
+ }
+
+ if (newifname == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to generate new name for interface %s"),
+ ifr.ifr_name);
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (virNetDevSetName(ifr.ifr_name, newifname) == -1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to rename interface %s to %s"),
+ ifr.ifr_name, newifname);
+ ret = -1;
+ goto cleanup;
+ }
+
+ *ifname = newifname;
+
+ if (tapfd) {
+ char *dev_prefix = "/dev/";
+ char *dev_path;
+ int dev_path_len = strlen(dev_prefix) + strlen(*ifname) + 1;
+
+ if (VIR_ALLOC_N(dev_path, dev_path_len) < 0) {
+ virReportOOMError();
+ ret = -1;
+ goto cleanup;
+ }
+ snprintf(dev_path, dev_path_len, "%s%s", dev_prefix, *ifname);
+
+ *tapfd = open(dev_path, O_RDWR);
+
+ VIR_FREE(dev_path);
+ }
+
+ ret = 0;
+cleanup:
+ if (ret < 0)
+ VIR_FORCE_CLOSE(s);
+
+ return ret;
+}
+
+int virNetDevTapDelete(const char *ifname)
+{
+ int s;
+ struct ifreq ifr;
+ int ret = -1;
+
+ s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (s < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to create socket"));
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL) {
+ virReportSystemError(ERANGE,
+ _("Network interface name '%s' is too
long"),
+ ifname);
+ goto cleanup;
+ }
+
+ 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
int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED,
int *tapfd ATTRIBUTE_UNUSED,
unsigned int flags ATTRIBUTE_UNUSED)
@@ -245,7 +379,7 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
_("Unable to delete TAP devices on this platform"));
return -1;
}
-#endif /* ! TUNSETIFF */
+#endif
/**
--
1.8.0