}
+/**
+ * virNetlinkNewLink:
+ *
+ * @ifname: name of the link
+ * @type: the type of the device, i.e. "bridge", "macvtap", "macvlan"
+ * @extra_args: the extra args for creating the netlink interface
+ * @error: netlink error code
+ *
+ * A generic wrapper to create a network link.
+ *
+ * Returns 0 on success, -1 on error. Additionally, if the @error is
+ * non-zero, then a failure occurred during virNetlinkCommand, but
+ * no error message is generated leaving it up to the caller to handle
+ * the condition.
+ */
+int
+virNetlinkNewLink(const char *ifname,
+ const char *type,
+ virNetlinkNewLinkDataPtr extra_args,
+ int *error)
+{
+ struct nlmsgerr *err;
+ struct nlattr *linkinfo = NULL;
+ struct nlattr *infodata = NULL;
+ unsigned int buflen;
+ struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
+ VIR_AUTOPTR(virNetlinkMsg) nl_msg = NULL;
+ VIR_AUTOFREE(struct nlmsghdr *) resp = NULL;
+
+ *error = 0;
+
+ VIR_DEBUG("Creating %s interface '%s'", type, ifname);
+
+ if (!ifname || !type) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("both interface name and type must not be NULL"));
+ return -1;
+ }
+
+ 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 (ifname && nla_put(nl_msg, IFLA_IFNAME,
+ (strlen(ifname) + 1), ifname) < 0)
+ goto buffer_too_small;
+
+ if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO)))
+ goto buffer_too_small;
+
+ if (type && nla_put(nl_msg, IFLA_INFO_KIND, (strlen(type) + 1), type) < 0)
+ goto buffer_too_small;
+
+ if ((STREQ(type, "macvtap") || STREQ(type, "macvlan")) &&
+ extra_args &&
+ extra_args->macvlan_mode &&
+ *extra_args->macvlan_mode > 0) {
+ if (!(infodata = nla_nest_start(nl_msg, IFLA_INFO_DATA)))
+ goto buffer_too_small;
+
+ if (nla_put(nl_msg, IFLA_MACVLAN_MODE,
+ sizeof(uint32_t), extra_args->macvlan_mode) < 0)
+ goto buffer_too_small;
+
+ nla_nest_end(nl_msg, infodata);
+ }
+
+ nla_nest_end(nl_msg, linkinfo);
+
+ if (extra_args) {
+ if (extra_args->ifindex &&
+ nla_put(nl_msg, IFLA_LINK,
+ sizeof(uint32_t), extra_args->ifindex) < 0)
+ goto buffer_too_small;
+
+ if (extra_args->mac &&
+ nla_put(nl_msg, IFLA_ADDRESS, VIR_MAC_BUFLEN, extra_args->mac) < 0)
+ goto buffer_too_small;
+ }
+
+ if (virNetlinkCommand(nl_msg, &resp, &buflen, 0, 0, NETLINK_ROUTE, 0) < 0)
+ return -1;
+
+ if (buflen < 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;
+
+ if (err->error < 0) {
+ *error = err->error;
+ return -1;
+ }
+ break;
+
+ case NLMSG_DONE:
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+ return 0;
+
+ malformed_resp:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ return -1;
+
+ buffer_too_small:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("allocated netlink buffer is too small"));
+ return -1;
+}
+
+
/**
* virNetlinkDelLink:
*
}
+int
+virNetlinkNewLink(const char *ifname ATTRIBUTE_UNUSED,
+ const char *type ATTRIBUTE_UNUSED,
+ virNetlinkNewLinkDataPtr extra_args ATTRIBUTE_UNUSED,
+ int *error ATTRIBUTE_UNUSED)
+{
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
+ return -1;
+}
+
+
int
virNetlinkGetNeighbor(void **nlData ATTRIBUTE_UNUSED,
uint32_t src_pid ATTRIBUTE_UNUSED,