提交 4dc04d3a 编写于 作者: C Cédric Bosdonnat

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.
上级 b11a75dc
...@@ -1740,6 +1740,7 @@ virNetlinkEventServiceLocalPid; ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册