mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
virNetDevSetIPv4Address: libnl implementation
Add a default implementation of virNetDevSetIPv4Address using netlink and libnl. This avoids requiring /usr/sbin/ip or /usr/sbin/ifconfig external binaries.
This commit is contained in:
parent
b11a75dcb4
commit
4dc04d3ab4
@ -1740,6 +1740,7 @@ virNetlinkEventServiceLocalPid;
|
|||||||
virNetlinkEventServiceStart;
|
virNetlinkEventServiceStart;
|
||||||
virNetlinkEventServiceStop;
|
virNetlinkEventServiceStop;
|
||||||
virNetlinkEventServiceStopAll;
|
virNetlinkEventServiceStopAll;
|
||||||
|
virNetlinkGetErrorCode;
|
||||||
virNetlinkShutdown;
|
virNetlinkShutdown;
|
||||||
virNetlinkStartup;
|
virNetlinkStartup;
|
||||||
|
|
||||||
|
@ -823,6 +823,88 @@ int virNetDevGetVLanID(const char *ifname ATTRIBUTE_UNUSED,
|
|||||||
#endif /* ! SIOCGIFVLAN */
|
#endif /* ! SIOCGIFVLAN */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(HAVE_LIBNL)
|
||||||
|
|
||||||
|
static int
|
||||||
|
virNetDevGetIPAddressBinary(virSocketAddr *addr, void **data, size_t *len)
|
||||||
|
{
|
||||||
|
if (!addr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (VIR_SOCKET_ADDR_FAMILY(addr)) {
|
||||||
|
case AF_INET:
|
||||||
|
*data = &addr->data.inet4.sin_addr;
|
||||||
|
*len = sizeof(struct in_addr);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
*data = &addr->data.inet6.sin6_addr;
|
||||||
|
*len = sizeof(struct in6_addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nl_msg *
|
||||||
|
virNetDevCreateNetlinkAddressMessage(int messageType,
|
||||||
|
const char *ifname,
|
||||||
|
virSocketAddr *addr,
|
||||||
|
unsigned int prefix,
|
||||||
|
virSocketAddr *broadcast)
|
||||||
|
{
|
||||||
|
struct nl_msg *nlmsg = NULL;
|
||||||
|
struct ifaddrmsg ifa;
|
||||||
|
unsigned int ifindex;
|
||||||
|
void *addrData = NULL;
|
||||||
|
void *broadcastData = NULL;
|
||||||
|
size_t addrDataLen;
|
||||||
|
|
||||||
|
if (virNetDevGetIPAddressBinary(addr, &addrData, &addrDataLen) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (broadcast && virNetDevGetIPAddressBinary(broadcast, &broadcastData,
|
||||||
|
&addrDataLen) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Get the interface index */
|
||||||
|
if ((ifindex = if_nametoindex(ifname)) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(nlmsg = nlmsg_alloc_simple(messageType,
|
||||||
|
NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL))) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifa, 0, sizeof(ifa));
|
||||||
|
|
||||||
|
ifa.ifa_prefixlen = prefix;
|
||||||
|
ifa.ifa_family = VIR_SOCKET_ADDR_FAMILY(addr);
|
||||||
|
ifa.ifa_index = ifindex;
|
||||||
|
ifa.ifa_scope = 0;
|
||||||
|
|
||||||
|
if (nlmsg_append(nlmsg, &ifa, sizeof(ifa), NLMSG_ALIGNTO) < 0)
|
||||||
|
goto buffer_too_small;
|
||||||
|
|
||||||
|
if (nla_put(nlmsg, IFA_LOCAL, addrDataLen, addrData) < 0)
|
||||||
|
goto buffer_too_small;
|
||||||
|
|
||||||
|
if (nla_put(nlmsg, IFA_ADDRESS, addrDataLen, addrData) < 0)
|
||||||
|
goto buffer_too_small;
|
||||||
|
|
||||||
|
if (broadcastData &&
|
||||||
|
nla_put(nlmsg, IFA_BROADCAST, addrDataLen, broadcastData) < 0)
|
||||||
|
goto buffer_too_small;
|
||||||
|
|
||||||
|
return nlmsg;
|
||||||
|
|
||||||
|
buffer_too_small:
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("allocated netlink buffer is too small"));
|
||||||
|
nlmsg_free(nlmsg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virNetDevSetIPv4Address:
|
* virNetDevSetIPv4Address:
|
||||||
@ -836,6 +918,52 @@ int virNetDevGetVLanID(const char *ifname ATTRIBUTE_UNUSED,
|
|||||||
*
|
*
|
||||||
* Returns 0 in case of success or -1 in case of error.
|
* Returns 0 in case of success or -1 in case of error.
|
||||||
*/
|
*/
|
||||||
|
int virNetDevSetIPv4Address(const char *ifname,
|
||||||
|
virSocketAddr *addr,
|
||||||
|
unsigned int prefix)
|
||||||
|
{
|
||||||
|
virSocketAddr *broadcast = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
struct nl_msg *nlmsg = NULL;
|
||||||
|
struct nlmsghdr *resp = NULL;
|
||||||
|
unsigned int recvbuflen;
|
||||||
|
|
||||||
|
|
||||||
|
/* The caller needs to provide a correct address */
|
||||||
|
if (VIR_SOCKET_ADDR_FAMILY(addr) == AF_INET) {
|
||||||
|
/* compute a broadcast address if this is IPv4 */
|
||||||
|
if (VIR_ALLOC(broadcast) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (virSocketAddrBroadcastByPrefix(addr, prefix, broadcast) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(nlmsg = virNetDevCreateNetlinkAddressMessage(RTM_NEWADDR, ifname,
|
||||||
|
addr, prefix,
|
||||||
|
broadcast)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virNetlinkCommand(nlmsg, &resp, &recvbuflen, 0, 0,
|
||||||
|
NETLINK_ROUTE, 0) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
|
||||||
|
if (virNetlinkGetErrorCode(resp, recvbuflen) < 0) {
|
||||||
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
|
_("Error adding IP address to %s"), ifname);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
nlmsg_free(nlmsg);
|
||||||
|
VIR_FREE(resp);
|
||||||
|
VIR_FREE(broadcast);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* defined(__linux__) && defined(HAVE_LIBNL) */
|
||||||
|
|
||||||
int virNetDevSetIPv4Address(const char *ifname,
|
int virNetDevSetIPv4Address(const char *ifname,
|
||||||
virSocketAddr *addr,
|
virSocketAddr *addr,
|
||||||
@ -854,7 +982,7 @@ int virNetDevSetIPv4Address(const char *ifname,
|
|||||||
!(bcaststr = virSocketAddrFormat(&broadcast)))) {
|
!(bcaststr = virSocketAddrFormat(&broadcast)))) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#ifdef IFCONFIG_PATH
|
# ifdef IFCONFIG_PATH
|
||||||
cmd = virCommandNew(IFCONFIG_PATH);
|
cmd = virCommandNew(IFCONFIG_PATH);
|
||||||
virCommandAddArg(cmd, ifname);
|
virCommandAddArg(cmd, ifname);
|
||||||
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6))
|
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6))
|
||||||
@ -865,14 +993,14 @@ int virNetDevSetIPv4Address(const char *ifname,
|
|||||||
if (bcaststr)
|
if (bcaststr)
|
||||||
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
|
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
|
||||||
virCommandAddArg(cmd, "alias");
|
virCommandAddArg(cmd, "alias");
|
||||||
#else
|
# else
|
||||||
cmd = virCommandNew(IP_PATH);
|
cmd = virCommandNew(IP_PATH);
|
||||||
virCommandAddArgList(cmd, "addr", "add", NULL);
|
virCommandAddArgList(cmd, "addr", "add", NULL);
|
||||||
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
|
||||||
if (bcaststr)
|
if (bcaststr)
|
||||||
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
|
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
|
||||||
virCommandAddArgList(cmd, "dev", ifname, NULL);
|
virCommandAddArgList(cmd, "dev", ifname, NULL);
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
if (virCommandRun(cmd, NULL) < 0)
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -885,6 +1013,8 @@ int virNetDevSetIPv4Address(const char *ifname,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* defined(__linux__) && defined(HAVE_LIBNL) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virNetDevAddRoute:
|
* virNetDevAddRoute:
|
||||||
* @ifname: the interface name
|
* @ifname: the interface name
|
||||||
|
@ -276,6 +276,44 @@ int virNetlinkCommand(struct nl_msg *nl_msg,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int virNetlinkGetErrorCode(struct nlmsghdr *resp, unsigned int recvbuflen)
|
||||||
|
{
|
||||||
|
struct nlmsgerr *err;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
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: /* ACK */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = err->error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NLMSG_DONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto malformed_resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
malformed_resp:
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("malformed netlink response message"));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
virNetlinkEventServerLock(virNetlinkEventSrvPrivatePtr driver)
|
virNetlinkEventServerLock(virNetlinkEventSrvPrivatePtr driver)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +52,8 @@ int virNetlinkCommand(struct nl_msg *nl_msg,
|
|||||||
uint32_t src_pid, uint32_t dst_pid,
|
uint32_t src_pid, uint32_t dst_pid,
|
||||||
unsigned int protocol, unsigned int groups);
|
unsigned int protocol, unsigned int groups);
|
||||||
|
|
||||||
|
int virNetlinkGetErrorCode(struct nlmsghdr *resp, unsigned int recvbuflen);
|
||||||
|
|
||||||
typedef void (*virNetlinkEventHandleCallback)(struct nlmsghdr *,
|
typedef void (*virNetlinkEventHandleCallback)(struct nlmsghdr *,
|
||||||
unsigned int length,
|
unsigned int length,
|
||||||
struct sockaddr_nl *peer,
|
struct sockaddr_nl *peer,
|
||||||
|
Loading…
Reference in New Issue
Block a user