From fc7b23db02062f5649022db1fd238c4bcc28476a Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Mon, 23 Mar 2015 14:17:44 -0400 Subject: [PATCH] util: use netlink to create bridge devices Just as it is possible to delete a bridge device with the netlink RTM_DELLINK message, one can be created with the RTM_NEWLINK message. Because of differences in the format of the message, it's not as straightforward as with virNetlinkDelLink() to create a single utility function that can be used to create any type of interface, so the new netlink version of virNetDevBridgeCreate() does its own construction of the netlink message and calls virNetlinkCommand() itself. This doesn't provide any extra functionality, just provides symmetry with the previous commit. NB: We *could* alter the API of virNetDevBridgeCreate() to take a MAC address, and directly program that mac address into the bridge (by adding an IFLA_ADDRESS attribute, as is done in virNetDevMacVLanCreate()) rather than separately creating the "dummy tap" (e.g. virbr0-nic) to maintain a fixed mac address on the bridge, but the commit history of virnetdevbridge.c shows that the presence of this dummy tap is essential in some older versions of the kernel (between 2.6.39 and 3.1 or 3.2, possibly?) to proper operation of IPv6 DAD, and I don't want to take the chance of breaking something that I don't have the time/setup to test (my RHEL6 box is at kernel 2.6.32-544, and the next lowest kernel I have is 3.17) --- src/util/virnetdevbridge.c | 78 +++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index 2bad40a82a..6be8aa37e9 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -395,7 +395,83 @@ virNetDevBridgePortSetUnicastFlood(const char *brname ATTRIBUTE_UNUSED, * * Returns 0 in case of success or -1 on failure */ -#if defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR) +#if defined(__linux__) && defined(HAVE_LIBNL) +int virNetDevBridgeCreate(const char *brname) +{ + /* use a netlink RTM_NEWLINK message to create the bridge */ + const char *type = "bridge"; + int rc = -1; + struct nlmsghdr *resp = NULL; + struct nlmsgerr *err; + struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC }; + unsigned int recvbuflen; + struct nl_msg *nl_msg; + struct nlattr *linkinfo; + + nl_msg = nlmsg_alloc_simple(RTM_NEWLINK, + NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL); + if (!nl_msg) { + virReportOOMError(); + return -1; + } + + if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) + goto buffer_too_small; + if (nla_put(nl_msg, IFLA_IFNAME, strlen(brname)+1, brname) < 0) + goto buffer_too_small; + if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO))) + goto buffer_too_small; + if (nla_put(nl_msg, IFLA_INFO_KIND, strlen(type), type) < 0) + goto buffer_too_small; + nla_nest_end(nl_msg, linkinfo); + + if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0, + NETLINK_ROUTE, 0) < 0) { + goto cleanup; + } + + if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL) + goto malformed_resp; + + switch (resp->nlmsg_type) { + case NLMSG_ERROR: + err = (struct nlmsgerr *)NLMSG_DATA(resp); + if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) + goto malformed_resp; + + switch (err->error) { + case 0: + break; + default: + virReportSystemError(-err->error, + _("error creating bridge interface %s"), + brname); + goto cleanup; + } + break; + + case NLMSG_DONE: + break; + default: + goto malformed_resp; + } + + rc = 0; + cleanup: + nlmsg_free(nl_msg); + VIR_FREE(resp); + return rc; + + malformed_resp: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed netlink response message")); + goto cleanup; + buffer_too_small: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("allocated netlink buffer is too small")); + goto cleanup; +} +#elif defined(HAVE_STRUCT_IFREQ) && defined(SIOCBRADDBR) int virNetDevBridgeCreate(const char *brname) { int fd = -1; -- GitLab