This patch introduces virNetlinkNewLink which wraps newlink code using libnl. Signed-off-by: Shi Lei <shi_lei@xxxxxxxxxxxxxx> --- src/libvirt_private.syms | 1 + src/util/virnetlink.c | 120 +++++++++++++++++++++++++++++++++++++-- src/util/virnetlink.h | 13 +++++ 3 files changed, 129 insertions(+), 5 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e2340d2..77c9b9e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2447,6 +2447,7 @@ virNetlinkEventServiceStop; virNetlinkEventServiceStopAll; virNetlinkGetErrorCode; virNetlinkGetNeighbor; +virNetlinkNewLink; virNetlinkShutdown; virNetlinkStartup; diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 8f06446..32aa62d 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -420,10 +420,8 @@ virNetlinkDumpLink(const char *ifname, int ifindex, if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) goto buffer_too_small; - if (ifname) { - if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) - goto buffer_too_small; - } + if (ifname && nla_put_string(nl_msg, IFLA_IFNAME, ifname) < 0) + goto buffer_too_small; # ifdef RTEXT_FILTER_VF /* if this filter exists in the kernel's netlink implementation, @@ -488,6 +486,118 @@ virNetlinkDumpLink(const char *ifname, int ifindex, } +/** + * virNetlinkNewLink: + * + * @ifname: Name of the link + * @type: The type of device, i.e., "bridge", "macvtap", "macvlan" + * @ifindex: The index for the 'link' device + * @data: The extra args for creating the netlink interface + * @error: for retrieving error code + * + * Create a network "link" (aka interface aka device) with the given + * args. This works for many different types of network devices, + * including macvtap and bridges. + * + * Returns 0 on success, -1 on fatal error. + */ +int +virNetlinkNewLink(const char *ifname, + const char *type, + const int *ifindex, + virNetlinkNewLinkDataPtr data, + 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; + + if (!data) + 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 (ifindex && nla_put_u32(nl_msg, IFLA_LINK, *ifindex) < 0) + goto buffer_too_small; + + if (data->mac && nla_put(nl_msg, IFLA_ADDRESS, VIR_MAC_BUFLEN, data->mac) < 0) + goto buffer_too_small; + + if (ifname && nla_put_string(nl_msg, IFLA_IFNAME, ifname) < 0) + goto buffer_too_small; + + if (!(linkinfo = nla_nest_start(nl_msg, IFLA_LINKINFO))) + goto buffer_too_small; + + if (type && nla_put_string(nl_msg, IFLA_INFO_KIND, type) < 0) + goto buffer_too_small; + + if ((STREQ(type, "macvtap") || STREQ(type, "macvlan")) && + data->macvlan_mode && *data->macvlan_mode > 0) { + if (!(infodata = nla_nest_start(nl_msg, IFLA_INFO_DATA))) + goto buffer_too_small; + + if (nla_put_u32(nl_msg, IFLA_MACVLAN_MODE, *data->macvlan_mode) < 0) + goto buffer_too_small; + + nla_nest_end(nl_msg, infodata); + } + + nla_nest_end(nl_msg, linkinfo); + + 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: * @@ -522,7 +632,7 @@ virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback) if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0) goto buffer_too_small; - if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) + if (ifname && nla_put_string(nl_msg, IFLA_IFNAME, ifname) < 0) goto buffer_too_small; if (virNetlinkCommand(nl_msg, &resp, &recvbuflen, 0, 0, diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index 1e1e616..8163a81 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -65,6 +65,19 @@ int virNetlinkDumpCommand(struct nl_msg *nl_msg, unsigned int protocol, unsigned int groups, void *opaque); +typedef struct _virNetlinkNewLinkData virNetlinkNewLinkData; +typedef virNetlinkNewLinkData *virNetlinkNewLinkDataPtr; +struct _virNetlinkNewLinkData { + const virMacAddr *mac; /* The MAC address of the device */ + const uint32_t *macvlan_mode; /* The mode of macvlan */ +}; + +int virNetlinkNewLink(const char *ifname, + const char *type, + const int *ifindex, + virNetlinkNewLinkDataPtr data, + int *error); + typedef int (*virNetlinkDelLinkFallback)(const char *ifname); int virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback); -- 2.17.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list