commit fc7b23db switched from using ioctl(SIOCBRADDBR) to using a
netlink RTM_NEWLINK message with an IFLA_INFO_KIND of "bridge", which
is the more modern way to create a bridge. However, although older
kernels (e.g. 2.6.32, in RHEL6/CentOS6) support creating *some* link
types with RTM_NEWLINK, they don't support creating bridges, and there
is no compile-time way to figure this out (since the "type" isn't an
enum, but rather a character string).
This patch moves the body of the SIOCBRADDBR version of
virNetDevBridgeCreate() into a static function, calls the new function
from the original, and also calls the new function from the
RTM_NEWLINK version if the RTM_NEWLINK message generates an EOPNOTSUPP
error.
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=1252780
---
src/util/virnetdevbridge.c | 64 ++++++++++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 19 deletions(-)
diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c
index aa255d6..ae38901 100644
--- a/src/util/virnetdevbridge.c
+++ b/src/util/virnetdevbridge.c
@@ -394,8 +394,33 @@ virNetDevBridgePortSetUnicastFlood(const char *brname
ATTRIBUTE_UNUSED,
*
* Returns 0 in case of success or -1 on failure
*/
+#if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
+static int
+virNetDevBridgeCreateWithIoctl(const char *brname)
+{
+ int fd = -1;
+ int ret = -1;
+
+ if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
+ return -1;
+
+ if (ioctl(fd, SIOCBRADDBR, brname) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create bridge %s"), brname);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ return ret;
+}
+#endif
+
#if defined(__linux__) && defined(HAVE_LIBNL)
-int virNetDevBridgeCreate(const char *brname)
+int
+virNetDevBridgeCreate(const char *brname)
{
/* use a netlink RTM_NEWLINK message to create the bridge */
const char *type = "bridge";
@@ -441,6 +466,17 @@ int virNetDevBridgeCreate(const char *brname)
switch (err->error) {
case 0:
break;
+ case -EOPNOTSUPP:
+# if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
+ /* fallback to ioctl if netlink doesn't support creating
+ * bridges
+ */
+ rc = virNetDevBridgeCreateWithIoctl(brname);
+ goto cleanup;
+# endif
+ /* intentionally fall through if virNetDevBridgeCreateWithIoctl()
+ * isn't available.
+ */
default:
virReportSystemError(-err->error,
_("error creating bridge interface %s"),
@@ -470,29 +506,19 @@ int virNetDevBridgeCreate(const char *brname)
_("allocated netlink buffer is too small"));
goto cleanup;
}
-#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
-int virNetDevBridgeCreate(const char *brname)
-{
- int fd = -1;
- int ret = -1;
- if ((fd = virNetDevSetupControl(NULL, NULL)) < 0)
- return -1;
- if (ioctl(fd, SIOCBRADDBR, brname) < 0) {
- virReportSystemError(errno,
- _("Unable to create bridge %s"), brname);
- goto cleanup;
- }
+#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR)
+int
+virNetDevBridgeCreate(const char *brname)
+{
+ return virNetDevBridgeCreateWithIoctl(brname);
+}
- ret = 0;
- cleanup:
- VIR_FORCE_CLOSE(fd);
- return ret;
-}
#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCIFCREATE2)
-int virNetDevBridgeCreate(const char *brname)
+int
+virNetDevBridgeCreate(const char *brname)
{
int s;
struct ifreq ifr;
--
2.1.0