mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
util: netlink: Introduce virNetlinkNewLink helper
This patch introduces virNetlinkNewLink helper which wraps the common libnl/netlink code to create a new link. Signed-off-by: Shi Lei <shi_lei@massclouds.com> Signed-off-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
parent
5ea2abb3bf
commit
a2e5aad003
@ -2446,6 +2446,7 @@ virNetlinkEventServiceStop;
|
||||
virNetlinkEventServiceStopAll;
|
||||
virNetlinkGetErrorCode;
|
||||
virNetlinkGetNeighbor;
|
||||
virNetlinkNewLink;
|
||||
virNetlinkShutdown;
|
||||
virNetlinkStartup;
|
||||
|
||||
|
@ -488,6 +488,131 @@ virNetlinkDumpLink(const char *ifname, int ifindex,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
@ -1182,6 +1307,17 @@ virNetlinkDelLink(const char *ifname ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
|
@ -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 int *ifindex; /* The index for the 'link' device */
|
||||
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,
|
||||
virNetlinkNewLinkDataPtr data,
|
||||
int *error);
|
||||
|
||||
typedef int (*virNetlinkDelLinkFallback)(const char *ifname);
|
||||
|
||||
int virNetlinkDelLink(const char *ifname, virNetlinkDelLinkFallback fallback);
|
||||
|
Loading…
x
Reference in New Issue
Block a user