[libvirt] [PATCH v4 0/3] BSD implementation of virNetDevTapCreate() and virNetDevTapDelete()

Changes from v3: * Include linux/if.h header fix so it won't lost why Eric is on vacation * Fix struct virIfreq definition in case when HAVE_STRUCT_IFREQ is not defined (thanks to Laine Stump for noticing that) Roman Bogorodskiy (3): Make virNetDevSetupControl() public. BSD: implement virNetDevTapCreate() and virNetDevTapDelete() portability: use net/if.h instead of linux/if.h src/libvirt_private.syms | 1 + src/util/virnetdev.c | 15 ++++- src/util/virnetdev.h | 15 ++++- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevtap.c | 118 ++++++++++++++++++++++++++++++++++++++- src/util/virnetdevvportprofile.c | 2 +- 6 files changed, 146 insertions(+), 7 deletions(-) -- 1.7.11.5

This method is useful not only in virnetdev.c. --- src/libvirt_private.syms | 1 + src/util/virnetdev.c | 15 +++++++++++++-- src/util/virnetdev.h | 14 +++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 042081f..f26b8aa 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1530,6 +1530,7 @@ virNetDevSetMTUFromDevice; virNetDevSetName; virNetDevSetNamespace; virNetDevSetOnline; +virNetDevSetupControl; virNetDevValidateConfig; diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 1a22126..f6b7e12 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -88,11 +88,22 @@ static int virNetDevSetupControlFull(const char *ifname, } -static int virNetDevSetupControl(const char *ifname, - struct ifreq *ifr) +int +virNetDevSetupControl(const char *ifname, + struct ifreq *ifr) { return virNetDevSetupControlFull(ifname, ifr, VIR_NETDEV_FAMILY, SOCK_DGRAM); } +#else +int +virNetDevSetupControl(const char *ifname ATTRIBUTE_UNUSED, + void *ifr ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, + _("Network device configuration is not supported " + "on this platform")); + return -1; +} #endif diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index bc0777c..86c1f18 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2007-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,11 +23,23 @@ #ifndef __VIR_NETDEV_H__ # define __VIR_NETDEV_H__ +# include <net/if.h> + # include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" # include "virpci.h" +# ifdef HAVE_STRUCT_IFREQ +typedef struct ifreq virIfreq; +# else +typedef struct {} virIfreq; +# endif + +int virNetDevSetupControl(const char *ifname, + virIfreq *ifr) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int virNetDevExists(const char *brname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; -- 1.7.11.5

On 13.06.2013 08:26, Roman Bogorodskiy wrote:
This method is useful not only in virnetdev.c. --- src/libvirt_private.syms | 1 + src/util/virnetdev.c | 15 +++++++++++++-- src/util/virnetdev.h | 14 +++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 042081f..f26b8aa 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1530,6 +1530,7 @@ virNetDevSetMTUFromDevice; virNetDevSetName; virNetDevSetNamespace; virNetDevSetOnline; +virNetDevSetupControl; virNetDevValidateConfig;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 1a22126..f6b7e12 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -88,11 +88,22 @@ static int virNetDevSetupControlFull(const char *ifname, }
-static int virNetDevSetupControl(const char *ifname, - struct ifreq *ifr) +int +virNetDevSetupControl(const char *ifname, + struct ifreq *ifr) { return virNetDevSetupControlFull(ifname, ifr, VIR_NETDEV_FAMILY, SOCK_DGRAM); } +#else +int +virNetDevSetupControl(const char *ifname ATTRIBUTE_UNUSED, + void *ifr ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS,
s/$/ "%s"/
+ _("Network device configuration is not supported " + "on this platform")); + return -1; +} #endif
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index bc0777c..86c1f18 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2007-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,11 +23,23 @@ #ifndef __VIR_NETDEV_H__ # define __VIR_NETDEV_H__
+# include <net/if.h> +
Since virnetdev.c already includes <linux/if.h> this chunk makes the compilation fail. It's, however, sufficient, to apply 3/3 prior to this patch.
# include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" # include "virpci.h"
+# ifdef HAVE_STRUCT_IFREQ +typedef struct ifreq virIfreq; +# else +typedef struct {} virIfreq;
s/struct {}/void/
+# endif + +int virNetDevSetupControl(const char *ifname, + virIfreq *ifr) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int virNetDevExists(const char *brname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
Michal

Implementation uses SIOCIFCREATE2 and SIOCIFDESTROY ioctls. --- src/util/virnetdevtap.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index bb4b3ba..265676c 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -275,7 +275,121 @@ cleanup: VIR_FORCE_CLOSE(fd); return ret; } -#else /* ! TUNSETIFF */ +#elif defined(SIOCIFCREATE2) && defined(SIOCIFDESTROY) +int virNetDevTapCreate(char **ifname, + int *tapfd, + int tapfdSize, + unsigned int flags ATTRIBUTE_UNUSED) +{ + int s; + struct ifreq ifr; + int ret = -1; + char *newifname = NULL; + + if (tapfdSize > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Multiqueue devices are not supported on this system")); + goto cleanup; + } + + /* 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; + } + + /* 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) { + int i; + for (i = 0; i <= IF_MAXUNIT; i++) { + char *newname; + if (virAsprintf(&newname, *ifname, i) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virNetDevExists(newname) == 0) { + newifname = newname; + break; + } + + VIR_FREE(newname); + } + 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; + } + } + + if (tapfd) { + char *dev_path = NULL; + if (virAsprintf(&dev_path, "/dev/%s", ifr.ifr_name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((*tapfd = open(dev_path, O_RDWR)) < 0) { + virReportSystemError(errno, + _("Unable to open %s"), + dev_path); + VIR_FREE(dev_path); + goto cleanup; + } + + VIR_FREE(dev_path); + } + + if (virNetDevSetName(ifr.ifr_name, *ifname) == -1) { + goto cleanup; + } + + + ret = 0; +cleanup: + VIR_FORCE_CLOSE(s); + + return ret; +} + +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 int virNetDevTapCreate(char **ifname ATTRIBUTE_UNUSED, int *tapfd ATTRIBUTE_UNUSED, int tapfdSize ATTRIBUTE_UNUSED, @@ -291,7 +405,7 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED) _("Unable to delete TAP devices on this platform")); return -1; } -#endif /* ! TUNSETIFF */ +#endif /** -- 1.7.11.5

--- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevvportprofile.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 6c338fa..a61c45f 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -49,7 +49,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST, # include <sys/socket.h> # include <sys/ioctl.h> -# include <linux/if.h> +# include <net/if.h> # include <linux/if_tun.h> /* Older kernels lacked this enum value. */ diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index c337fb3..0f1b6a1 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -49,7 +49,7 @@ VIR_ENUM_IMPL(virNetDevVPortProfileOp, VIR_NETDEV_VPORT_PROFILE_OP_LAST, # include <sys/socket.h> # include <sys/ioctl.h> -# include <linux/if.h> +# include <net/if.h> # include <linux/if_tun.h> # include "virnetlink.h" -- 1.7.11.5

On 13.06.2013 08:26, Roman Bogorodskiy wrote:
Changes from v3:
* Include linux/if.h header fix so it won't lost why Eric is on vacation * Fix struct virIfreq definition in case when HAVE_STRUCT_IFREQ is not defined (thanks to Laine Stump for noticing that)
Roman Bogorodskiy (3): Make virNetDevSetupControl() public. BSD: implement virNetDevTapCreate() and virNetDevTapDelete() portability: use net/if.h instead of linux/if.h
src/libvirt_private.syms | 1 + src/util/virnetdev.c | 15 ++++- src/util/virnetdev.h | 15 ++++- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevtap.c | 118 ++++++++++++++++++++++++++++++++++++++- src/util/virnetdevvportprofile.c | 2 +- 6 files changed, 146 insertions(+), 7 deletions(-)
ACK series. I've moved 3/3 up the front and pushed. Michal
participants (2)
-
Michal Privoznik
-
Roman Bogorodskiy