[libvirt] [PATCH 0/4] Improve netlink to support all protocols.

These patches improved libvirt to support all netlink protocols, and also introduced a new netlink service to listen to hotplug events. Tang Chen (4): Improve netlink to support all protocol. Introduce virNetlinkEventServiceStopAll() to stop all netlink services in libvirt. Add uevent netlink service. DEBUG: print out netlink message. daemon/libvirtd.c | 12 +- src/libvirt_private.syms | 1 + src/util/virnetdev.c | 6 +- src/util/virnetdevmacvlan.c | 12 +- src/util/virnetdevvportprofile.c | 7 +- src/util/virnetlink.c | 230 +++++++++++++++++++++++++++++++------- src/util/virnetlink.h | 22 ++-- 7 files changed, 229 insertions(+), 61 deletions(-) -- 1.7.10.1

This patch improve all the API in virnetlink.c to support all kinds of netlink protocols, and make all netlink sockets be able to join in groups. SOL_NETLINK is not defined on every system, so this patch defines SOL_NETLINK as 270. Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> --- daemon/libvirtd.c | 6 +- src/util/virnetdev.c | 6 +- src/util/virnetdevmacvlan.c | 12 +-- src/util/virnetdevvportprofile.c | 7 +- src/util/virnetlink.c | 178 +++++++++++++++++++++++++++++--------- src/util/virnetlink.h | 17 ++-- 6 files changed, 165 insertions(+), 61 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index f0b0a3c..e2e4fbd 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1310,8 +1310,8 @@ int main(int argc, char **argv) { goto cleanup; } - /* Register the netlink event service */ - if (virNetlinkEventServiceStart() < 0) { + /* Register the netlink event service for NETLINK_ROUTE */ + if (virNetlinkEventServiceStart(NETLINK_ROUTE, 0) < 0) { ret = VIR_DAEMON_ERR_NETWORK; goto cleanup; } @@ -1325,7 +1325,7 @@ int main(int argc, char **argv) { 0, "shutdown", NULL, NULL); cleanup: - virNetlinkEventServiceStop(); + virNetlinkEventServiceStop(NETLINK_ROUTE); virObjectUnref(remoteProgram); virObjectUnref(qemuProgram); virNetServerClose(srv); diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index f9eba1a..d97820e 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1277,7 +1277,8 @@ virNetDevLinkDump(const char *ifname, int ifindex, goto buffer_too_small; } - if (virNetlinkCommand(nl_msg, recvbuf, &recvbuflen, src_pid, dst_pid) < 0) + if (virNetlinkCommand(nl_msg, recvbuf, &recvbuflen, + src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) goto cleanup; if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL) @@ -1405,7 +1406,8 @@ virNetDevSetVfConfig(const char *ifname, int ifindex, int vf, } } - if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, pid) < 0) + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, pid, + NETLINK_ROUTE, 0) < 0) goto cleanup; if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL) diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index cfad2de..74c56e0 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -149,7 +149,8 @@ virNetDevMacVLanCreate(const char *ifname, nla_nest_end(nl_msg, linkinfo); - if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0) < 0) { + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0, + NETLINK_ROUTE, 0) < 0) { goto cleanup; } @@ -237,7 +238,8 @@ int virNetDevMacVLanDelete(const char *ifname) if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) goto buffer_too_small; - if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0) < 0) { + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0, + NETLINK_ROUTE, 0) < 0) { goto cleanup; } @@ -757,7 +759,7 @@ virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname, { virNetlinkCallbackDataPtr calld = NULL; - if (virtPortProfile && virNetlinkEventServiceIsRunning()) { + if (virtPortProfile && virNetlinkEventServiceIsRunning(NETLINK_ROUTE)) { if (VIR_ALLOC(calld) < 0) goto memory_error; if ((calld->cr_ifname = strdup(ifname)) == NULL) @@ -774,7 +776,7 @@ virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname, if (virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback, virNetDevMacVLanVPortProfileDestroyCallback, - calld, macaddress) < 0) + calld, macaddress, NETLINK_ROUTE) < 0) goto error; } @@ -1000,7 +1002,7 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname, ret = -1; } - virNetlinkEventRemoveClient(0, macaddr); + virNetlinkEventRemoveClient(0, macaddr, NETLINK_ROUTE); return ret; } diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index f3f53c9..5213378 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -705,13 +705,14 @@ virNetDevVPortProfileOpSetLink(const char *ifname, int ifindex, } if (!nltarget_kernel) { - if ((src_pid = virNetlinkEventServiceLocalPid()) < 0) + if ((src_pid = virNetlinkEventServiceLocalPid(NETLINK_ROUTE)) < 0) goto cleanup; if ((dst_pid = virNetDevVPortProfileGetLldpadPid()) == 0) goto cleanup; } - if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, src_pid, dst_pid) < 0) + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, + src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) goto cleanup; if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL) @@ -868,7 +869,7 @@ virNetDevVPortProfileOpCommon(const char *ifname, int ifindex, return 0; if (!nltarget_kernel && - (((src_pid = virNetlinkEventServiceLocalPid()) < 0) || + (((src_pid = virNetlinkEventServiceLocalPid(NETLINK_ROUTE)) < 0) || ((dst_pid = virNetDevVPortProfileGetLldpadPid()) == 0))) { rc = -1; goto cleanup; diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 4a31b1c..8a227df 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -33,6 +33,7 @@ #include <errno.h> #include <unistd.h> #include <sys/types.h> +#include <sys/socket.h> #include "virnetlink.h" #include "logging.h" @@ -41,6 +42,10 @@ #include "virmacaddr.h" #include "virterror_internal.h" +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + #define VIR_FROM_THIS VIR_FROM_NET #define NETLINK_ACK_TIMEOUT_S 2 @@ -93,7 +98,7 @@ static int nextWatch = 1; records in this multiple */ # define NETLINK_EVENT_ALLOC_EXTENT 10 -static virNetlinkEventSrvPrivatePtr server = NULL; +static virNetlinkEventSrvPrivatePtr server[MAX_LINKS] = {NULL}; static virNetlinkHandle *placeholder_nlhandle = NULL; /* Function definitions */ @@ -158,6 +163,7 @@ virNetlinkShutdown(void) * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel + * @protocol: netlink protocol * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response @@ -165,7 +171,8 @@ virNetlinkShutdown(void) */ int virNetlinkCommand(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, - uint32_t src_pid, uint32_t dst_pid) + uint32_t src_pid, uint32_t dst_pid, + unsigned int protocol, unsigned int groups) { int rc = 0; struct sockaddr_nl nladdr = { @@ -181,17 +188,46 @@ int virNetlinkCommand(struct nl_msg *nl_msg, int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); - virNetlinkHandle *nlhandle = virNetlinkAlloc(); + virNetlinkHandle *nlhandle = NULL; + + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return -EINVAL; + } + + if (groups >= 32) { + virReportSystemError(EINVAL, + _("invalid group argument: %d"), groups); + return -EINVAL; + } + nlhandle = virNetlinkAlloc(); if (!nlhandle) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for netlink")); return -1; } - if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { + if (nl_connect(nlhandle, protocol) < 0) { virReportSystemError(errno, - "%s", _("cannot connect to netlink socket")); + _("cannot connect to netlink socket with protocol %d"), protocol); + rc = -1; + goto error; + } + + fd = nl_socket_get_fd(nlhandle); + if (fd < 0) { + virReportSystemError(errno, + "%s", _("cannot get netlink socket fd")); + rc = -1; + goto error; + } + + if (groups && setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &groups, sizeof(groups)) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); rc = -1; goto error; } @@ -208,8 +244,6 @@ int virNetlinkCommand(struct nl_msg *nl_msg, goto error; } - fd = nl_socket_get_fd(nlhandle); - FD_ZERO(&readfds); FD_SET(fd, &readfds); @@ -258,6 +292,7 @@ virNetlinkEventServerUnlock(virNetlinkEventSrvPrivatePtr driver) * virNetlinkEventRemoveClientPrimitive: * * @i: index of the client to remove from the table + * @protocol: netlink protocol * * This static function does the low level removal of a client from * the table once its index is known, including calling the remove @@ -267,17 +302,21 @@ virNetlinkEventServerUnlock(virNetlinkEventSrvPrivatePtr driver) * * assumes success, returns nothing. */ -static void -virNetlinkEventRemoveClientPrimitive(size_t i) +static int +virNetlinkEventRemoveClientPrimitive(size_t i, unsigned int protocol) { - virNetlinkEventRemoveCallback removeCB = server->handles[i].removeCB; + if (protocol >= MAX_LINKS) + return -EINVAL; + + virNetlinkEventRemoveCallback removeCB = server[protocol]->handles[i].removeCB; if (removeCB) { - (removeCB)(server->handles[i].watch, - &server->handles[i].macaddr, - server->handles[i].opaque); + (removeCB)(server[protocol]->handles[i].watch, + &server[protocol]->handles[i].macaddr, + server[protocol]->handles[i].opaque); } - server->handles[i].deleted = VIR_NETLINK_HANDLE_DELETED; + server[protocol]->handles[i].deleted = VIR_NETLINK_HANDLE_DELETED; + return 0; } static void @@ -330,17 +369,22 @@ virNetlinkEventCallback(int watch, * stop the monitor to receive netlink messages for libvirtd. * This removes the netlink socket fd from the event handler. * + * @protocol: netlink protocol + * * Returns -1 if the monitor cannot be unregistered, 0 upon success */ int -virNetlinkEventServiceStop(void) +virNetlinkEventServiceStop(unsigned int protocol) { - virNetlinkEventSrvPrivatePtr srv = server; + if (protocol >= MAX_LINKS) + return -EINVAL; + + virNetlinkEventSrvPrivatePtr srv = server[protocol]; int i; VIR_INFO("stopping netlink event service"); - if (!server) + if (!server[protocol]) return 0; virNetlinkEventServerLock(srv); @@ -351,10 +395,10 @@ virNetlinkEventServiceStop(void) /* free any remaining clients on the list */ for (i = 0; i < srv->handlesCount; i++) { if (srv->handles[i].deleted == VIR_NETLINK_HANDLE_VALID) - virNetlinkEventRemoveClientPrimitive(i); + virNetlinkEventRemoveClientPrimitive(i, protocol); } - server = 0; + server[protocol] = NULL; virNetlinkEventServerUnlock(srv); virMutexDestroy(&srv->lock); @@ -367,29 +411,42 @@ virNetlinkEventServiceStop(void) * * Returns if the netlink event service is running. * + * @protocol: netlink protocol + * * Returns 'true' if the service is running, 'false' if stopped. */ bool -virNetlinkEventServiceIsRunning(void) +virNetlinkEventServiceIsRunning(unsigned int protocol) { - return server != NULL; + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return false; + } + + return server[protocol] != NULL; } /** * virNetlinkEventServiceLocalPid: * + * @protocol: netlink protocol + * * Returns the nl_pid value that was used to bind() the netlink socket * used by the netlink event service, or -1 on error (netlink * guarantees that this value will always be > 0). */ -int virNetlinkEventServiceLocalPid(void) +int virNetlinkEventServiceLocalPid(unsigned int protocol) { - if (!(server && server->netlinknh)) { + if (protocol >= MAX_LINKS) + return -EINVAL; + + if (!(server[protocol] && server[protocol]->netlinknh)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("netlink event service not running")); return -1; } - return (int)nl_socket_get_local_port(server->netlinknh); + return (int)nl_socket_get_local_port(server[protocol]->netlinknh); } @@ -399,19 +456,33 @@ int virNetlinkEventServiceLocalPid(void) * start a monitor to receive netlink messages for libvirtd. * This registers a netlink socket with the event interface. * + * @protocol: netlink protocol + * @groups: broadcast groups to join in * Returns -1 if the monitor cannot be registered, 0 upon success */ int -virNetlinkEventServiceStart(void) +virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups) { virNetlinkEventSrvPrivatePtr srv; int fd; int ret = -1; - if (server) + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return -EINVAL; + } + + if (groups >= 32) { + virReportSystemError(EINVAL, + _("invalid group argument: %d"), groups); + return -EINVAL; + } + + if (server[protocol]) return 0; - VIR_INFO("starting netlink event service"); + VIR_INFO("starting netlink event service with protocol %d", protocol); if (VIR_ALLOC(srv) < 0) { virReportOOMError(); @@ -434,20 +505,26 @@ virNetlinkEventServiceStart(void) goto error_locked; } - if (nl_connect(srv->netlinknh, NETLINK_ROUTE) < 0) { + if (nl_connect(srv->netlinknh, protocol) < 0) { virReportSystemError(errno, - "%s", _("cannot connect to netlink socket")); + _("cannot connect to netlink socket with protocol %d"), protocol); goto error_server; } fd = nl_socket_get_fd(srv->netlinknh); - if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); goto error_server; } + if (groups && setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &groups, sizeof(groups)) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); + goto error_server; + } + if (nl_socket_set_nonblocking(srv->netlinknh)) { virReportSystemError(errno, "%s", _("cannot set netlink socket nonblocking")); @@ -467,7 +544,7 @@ virNetlinkEventServiceStart(void) VIR_DEBUG("netlink event listener on fd: %i running", fd); ret = 0; - server = srv; + server[protocol] = srv; error_server: if (ret < 0) { @@ -491,6 +568,7 @@ error_locked: * @opaque: user data to pass to callback * @macaddr: macaddr to store with the data. Used to identify callers. * May be null. + * @protocol: netlink protocol * * register a callback for handling of netlink messages. The * registered function receives the entire netlink message and @@ -502,10 +580,16 @@ error_locked: int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB, virNetlinkEventRemoveCallback removeCB, - void *opaque, const virMacAddrPtr macaddr) + void *opaque, const virMacAddrPtr macaddr, + unsigned int protocol) { int i, r, ret = -1; - virNetlinkEventSrvPrivatePtr srv = server; + virNetlinkEventSrvPrivatePtr srv = NULL; + + if (protocol >= MAX_LINKS) + return -EINVAL; + + srv = server[protocol]; if (handleCB == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -562,6 +646,7 @@ error: * * @watch: watch whose handle to remove * @macaddr: macaddr whose handle to remove + * @protocol: netlink protocol * * Unregister a callback from a netlink monitor. * The handler function referenced will no longer receive netlink messages. @@ -570,11 +655,17 @@ error: * Returns -1 if the file handle was not registered, 0 upon success */ int -virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr) +virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr, + unsigned int protocol) { int i; int ret = -1; - virNetlinkEventSrvPrivatePtr srv = server; + virNetlinkEventSrvPrivatePtr srv = NULL; + + if (protocol >= MAX_LINKS) + return -EINVAL; + + srv = server[protocol]; VIR_DEBUG("removing client watch=%d, mac=%p.", watch, macaddr); @@ -595,7 +686,7 @@ virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr) VIR_DEBUG("removed client: %d by %s.", srv->handles[i].watch, watch ? "index" : "mac"); - virNetlinkEventRemoveClientPrimitive(i); + virNetlinkEventRemoveClientPrimitive(i, protocol); ret = 0; goto cleanup; } @@ -631,7 +722,9 @@ int virNetlinkCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, unsigned char **respbuf ATTRIBUTE_UNUSED, unsigned int *respbuflen ATTRIBUTE_UNUSED, uint32_t src_pid ATTRIBUTE_UNUSED, - uint32_t dst_pid ATTRIBUTE_UNUSED) + uint32_t dst_pid ATTRIBUTE_UNUSED, + unsigned int protocol ATTRIBUTE_UNUSED, + unsigned int groups ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; @@ -641,7 +734,7 @@ int virNetlinkCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, * stopNetlinkEventServer: stop the monitor to receive netlink * messages for libvirtd */ -int virNetlinkEventServiceStop(void) +int virNetlinkEventServiceStop(unsigned int protocol ATTRIBUTE_UNUSED) { VIR_DEBUG("%s", _(unsupported)); return 0; @@ -651,7 +744,8 @@ int virNetlinkEventServiceStop(void) * startNetlinkEventServer: start a monitor to receive netlink * messages for libvirtd */ -int virNetlinkEventServiceStart(void) +int virNetlinkEventServiceStart(unsigned int protocol ATTRIBUTE_UNUSED, + unsigned int groups ATTRIBUTE_UNUSED) { VIR_DEBUG("%s", _(unsupported)); return 0; @@ -661,13 +755,13 @@ int virNetlinkEventServiceStart(void) * virNetlinkEventServiceIsRunning: returns if the netlink event * service is running. */ -bool virNetlinkEventServiceIsRunning(void) +bool virNetlinkEventServiceIsRunning(unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return 0; } -int virNetlinkEventServiceLocalPid(void) +int virNetlinkEventServiceLocalPid(unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; @@ -681,6 +775,7 @@ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB ATTRIBUTE_UN virNetlinkEventRemoveCallback removeCB ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED, const virMacAddrPtr macaddr ATTRIBUTE_UNUSED) + unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; @@ -691,6 +786,7 @@ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB ATTRIBUTE_UN */ int virNetlinkEventRemoveClient(int watch ATTRIBUTE_UNUSED, const virMacAddrPtr macaddr ATTRIBUTE_UNUSED) + unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index 5d8337d..2e18af4 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -41,7 +41,8 @@ void virNetlinkShutdown(void); int virNetlinkCommand(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, - uint32_t src_port, uint32_t dst_port); + uint32_t src_pid, uint32_t dst_pid, + unsigned int protocol, unsigned int groups); typedef void (*virNetlinkEventHandleCallback)(unsigned char *msg, int length, struct sockaddr_nl *peer, bool *handled, void *opaque); @@ -50,33 +51,35 @@ typedef void (*virNetlinkEventRemoveCallback)(int watch, const virMacAddrPtr mac /** * stopNetlinkEventServer: stop the monitor to receive netlink messages for libvirtd */ -int virNetlinkEventServiceStop(void); +int virNetlinkEventServiceStop(unsigned int protocol); /** * startNetlinkEventServer: start a monitor to receive netlink messages for libvirtd */ -int virNetlinkEventServiceStart(void); +int virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups); /** * virNetlinkEventServiceIsRunning: returns if the netlink event service is running. */ -bool virNetlinkEventServiceIsRunning(void); +bool virNetlinkEventServiceIsRunning(unsigned int protocol); /** * virNetlinkEventServiceLocalPid: returns nl_pid used to bind() netlink socket */ -int virNetlinkEventServiceLocalPid(void); +int virNetlinkEventServiceLocalPid(unsigned int protocol); /** * virNetlinkEventAddClient: register a callback for handling of netlink messages */ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB, virNetlinkEventRemoveCallback removeCB, - void *opaque, const virMacAddrPtr macaddr); + void *opaque, const virMacAddrPtr macaddr, + unsigned int protocol); /** * virNetlinkEventRemoveClient: unregister a callback from a netlink monitor */ -int virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr); +int virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr, + unsigned int protocol); #endif /* __VIR_NETLINK_H__ */ -- 1.7.10.1

On Tue, Aug 21, 2012 at 5:12 AM, Tang Chen <tangchen@cn.fujitsu.com> wrote:
This patch improve all the API in virnetlink.c to support all kinds of netlink protocols, and make all netlink sockets be able to join in groups.
SOL_NETLINK is not defined on every system, so this patch defines SOL_NETLINK as 270.
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> ---
The commit message is a bit weak on what exactly is being added. The most details are about a 3 line change.
daemon/libvirtd.c | 6 +- src/util/virnetdev.c | 6 +- src/util/virnetdevmacvlan.c | 12 +-- src/util/virnetdevvportprofile.c | 7 +- src/util/virnetlink.c | 178 +++++++++++++++++++++++++++++--------- src/util/virnetlink.h | 17 ++-- 6 files changed, 165 insertions(+), 61 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index f0b0a3c..e2e4fbd 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1310,8 +1310,8 @@ int main(int argc, char **argv) { goto cleanup; }
- /* Register the netlink event service */ - if (virNetlinkEventServiceStart() < 0) { + /* Register the netlink event service for NETLINK_ROUTE */ + if (virNetlinkEventServiceStart(NETLINK_ROUTE, 0) < 0) { ret = VIR_DAEMON_ERR_NETWORK; goto cleanup; } @@ -1325,7 +1325,7 @@ int main(int argc, char **argv) { 0, "shutdown", NULL, NULL);
cleanup: - virNetlinkEventServiceStop(); + virNetlinkEventServiceStop(NETLINK_ROUTE); virObjectUnref(remoteProgram); virObjectUnref(qemuProgram); virNetServerClose(srv); diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index f9eba1a..d97820e 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1277,7 +1277,8 @@ virNetDevLinkDump(const char *ifname, int ifindex, goto buffer_too_small; }
- if (virNetlinkCommand(nl_msg, recvbuf, &recvbuflen, src_pid, dst_pid) < 0) + if (virNetlinkCommand(nl_msg, recvbuf, &recvbuflen, + src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) goto cleanup;
if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL) @@ -1405,7 +1406,8 @@ virNetDevSetVfConfig(const char *ifname, int ifindex, int vf, } }
- if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, pid) < 0) + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, pid, + NETLINK_ROUTE, 0) < 0) goto cleanup;
if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL) diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index cfad2de..74c56e0 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -149,7 +149,8 @@ virNetDevMacVLanCreate(const char *ifname,
nla_nest_end(nl_msg, linkinfo);
- if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0) < 0) { + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0, + NETLINK_ROUTE, 0) < 0) { goto cleanup; }
@@ -237,7 +238,8 @@ int virNetDevMacVLanDelete(const char *ifname) if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0) goto buffer_too_small;
- if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0) < 0) { + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, 0, 0, + NETLINK_ROUTE, 0) < 0) { goto cleanup; }
@@ -757,7 +759,7 @@ virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname, { virNetlinkCallbackDataPtr calld = NULL;
- if (virtPortProfile && virNetlinkEventServiceIsRunning()) { + if (virtPortProfile && virNetlinkEventServiceIsRunning(NETLINK_ROUTE)) { if (VIR_ALLOC(calld) < 0) goto memory_error; if ((calld->cr_ifname = strdup(ifname)) == NULL) @@ -774,7 +776,7 @@ virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname,
if (virNetlinkEventAddClient(virNetDevMacVLanVPortProfileCallback, virNetDevMacVLanVPortProfileDestroyCallback, - calld, macaddress) < 0) + calld, macaddress, NETLINK_ROUTE) < 0) goto error; }
@@ -1000,7 +1002,7 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname, ret = -1; }
- virNetlinkEventRemoveClient(0, macaddr); + virNetlinkEventRemoveClient(0, macaddr, NETLINK_ROUTE);
return ret; } diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index f3f53c9..5213378 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -705,13 +705,14 @@ virNetDevVPortProfileOpSetLink(const char *ifname, int ifindex, }
if (!nltarget_kernel) { - if ((src_pid = virNetlinkEventServiceLocalPid()) < 0) + if ((src_pid = virNetlinkEventServiceLocalPid(NETLINK_ROUTE)) < 0) goto cleanup; if ((dst_pid = virNetDevVPortProfileGetLldpadPid()) == 0) goto cleanup; }
- if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, src_pid, dst_pid) < 0) + if (virNetlinkCommand(nl_msg, &recvbuf, &recvbuflen, + src_pid, dst_pid, NETLINK_ROUTE, 0) < 0) goto cleanup;
if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL) @@ -868,7 +869,7 @@ virNetDevVPortProfileOpCommon(const char *ifname, int ifindex, return 0;
if (!nltarget_kernel && - (((src_pid = virNetlinkEventServiceLocalPid()) < 0) || + (((src_pid = virNetlinkEventServiceLocalPid(NETLINK_ROUTE)) < 0) || ((dst_pid = virNetDevVPortProfileGetLldpadPid()) == 0))) { rc = -1; goto cleanup; diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 4a31b1c..8a227df 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -33,6 +33,7 @@ #include <errno.h> #include <unistd.h> #include <sys/types.h> +#include <sys/socket.h>
#include "virnetlink.h" #include "logging.h" @@ -41,6 +42,10 @@ #include "virmacaddr.h" #include "virterror_internal.h"
+#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + #define VIR_FROM_THIS VIR_FROM_NET
#define NETLINK_ACK_TIMEOUT_S 2 @@ -93,7 +98,7 @@ static int nextWatch = 1; records in this multiple */ # define NETLINK_EVENT_ALLOC_EXTENT 10
-static virNetlinkEventSrvPrivatePtr server = NULL; +static virNetlinkEventSrvPrivatePtr server[MAX_LINKS] = {NULL}; static virNetlinkHandle *placeholder_nlhandle = NULL;
Maybe a little code comment as to why MAX_LINKS. e.g. The Linux kernel supports up to MAX_LINKS (32 at the time) individual netlink protocols.
/* Function definitions */ @@ -158,6 +163,7 @@ virNetlinkShutdown(void) * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel + * @protocol: netlink protocol * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response
Function documentation doesn't match your implementation below.
@@ -165,7 +171,8 @@ virNetlinkShutdown(void) */ int virNetlinkCommand(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, - uint32_t src_pid, uint32_t dst_pid) + uint32_t src_pid, uint32_t dst_pid, + unsigned int protocol, unsigned int groups) { int rc = 0; struct sockaddr_nl nladdr = { @@ -181,17 +188,46 @@ int virNetlinkCommand(struct nl_msg *nl_msg, int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); - virNetlinkHandle *nlhandle = virNetlinkAlloc(); + virNetlinkHandle *nlhandle = NULL; + + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return -EINVAL; + } + + if (groups >= 32) {
I believe there is a define for this in the headers so it would be better to use that then hardcoding a number without any code comments to what it means. If there's not a define, I would at least document what the 32 is and where it derives from the kernel code so that if things change in the future it will be easier to fix.
+ virReportSystemError(EINVAL, + _("invalid group argument: %d"), groups); + return -EINVAL; + }
+ nlhandle = virNetlinkAlloc(); if (!nlhandle) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for netlink")); return -1; }
- if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) { + if (nl_connect(nlhandle, protocol) < 0) { virReportSystemError(errno, - "%s", _("cannot connect to netlink socket")); + _("cannot connect to netlink socket with protocol %d"), protocol); + rc = -1; + goto error; + } + + fd = nl_socket_get_fd(nlhandle); + if (fd < 0) { + virReportSystemError(errno, + "%s", _("cannot get netlink socket fd")); + rc = -1; + goto error; + } + + if (groups && setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &groups, sizeof(groups)) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); rc = -1; goto error; } @@ -208,8 +244,6 @@ int virNetlinkCommand(struct nl_msg *nl_msg, goto error; }
- fd = nl_socket_get_fd(nlhandle); - FD_ZERO(&readfds); FD_SET(fd, &readfds);
@@ -258,6 +292,7 @@ virNetlinkEventServerUnlock(virNetlinkEventSrvPrivatePtr driver) * virNetlinkEventRemoveClientPrimitive: * * @i: index of the client to remove from the table + * @protocol: netlink protocol * * This static function does the low level removal of a client from * the table once its index is known, including calling the remove @@ -267,17 +302,21 @@ virNetlinkEventServerUnlock(virNetlinkEventSrvPrivatePtr driver) * * assumes success, returns nothing. */ -static void -virNetlinkEventRemoveClientPrimitive(size_t i) +static int +virNetlinkEventRemoveClientPrimitive(size_t i, unsigned int protocol) { - virNetlinkEventRemoveCallback removeCB = server->handles[i].removeCB; + if (protocol >= MAX_LINKS) + return -EINVAL; + + virNetlinkEventRemoveCallback removeCB = server[protocol]->handles[i].removeCB;
if (removeCB) { - (removeCB)(server->handles[i].watch, - &server->handles[i].macaddr, - server->handles[i].opaque); + (removeCB)(server[protocol]->handles[i].watch, + &server[protocol]->handles[i].macaddr, + server[protocol]->handles[i].opaque); } - server->handles[i].deleted = VIR_NETLINK_HANDLE_DELETED; + server[protocol]->handles[i].deleted = VIR_NETLINK_HANDLE_DELETED; + return 0; }
static void @@ -330,17 +369,22 @@ virNetlinkEventCallback(int watch, * stop the monitor to receive netlink messages for libvirtd. * This removes the netlink socket fd from the event handler. * + * @protocol: netlink protocol + * * Returns -1 if the monitor cannot be unregistered, 0 upon success */ int -virNetlinkEventServiceStop(void) +virNetlinkEventServiceStop(unsigned int protocol) { - virNetlinkEventSrvPrivatePtr srv = server; + if (protocol >= MAX_LINKS) + return -EINVAL; + + virNetlinkEventSrvPrivatePtr srv = server[protocol]; int i;
VIR_INFO("stopping netlink event service");
- if (!server) + if (!server[protocol]) return 0;
virNetlinkEventServerLock(srv); @@ -351,10 +395,10 @@ virNetlinkEventServiceStop(void) /* free any remaining clients on the list */ for (i = 0; i < srv->handlesCount; i++) { if (srv->handles[i].deleted == VIR_NETLINK_HANDLE_VALID) - virNetlinkEventRemoveClientPrimitive(i); + virNetlinkEventRemoveClientPrimitive(i, protocol); }
- server = 0; + server[protocol] = NULL; virNetlinkEventServerUnlock(srv);
virMutexDestroy(&srv->lock); @@ -367,29 +411,42 @@ virNetlinkEventServiceStop(void) * * Returns if the netlink event service is running. * + * @protocol: netlink protocol + * * Returns 'true' if the service is running, 'false' if stopped. */ bool -virNetlinkEventServiceIsRunning(void) +virNetlinkEventServiceIsRunning(unsigned int protocol) { - return server != NULL; + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return false; + } + + return server[protocol] != NULL; }
/** * virNetlinkEventServiceLocalPid: * + * @protocol: netlink protocol + * * Returns the nl_pid value that was used to bind() the netlink socket * used by the netlink event service, or -1 on error (netlink * guarantees that this value will always be > 0). */ -int virNetlinkEventServiceLocalPid(void) +int virNetlinkEventServiceLocalPid(unsigned int protocol) { - if (!(server && server->netlinknh)) { + if (protocol >= MAX_LINKS) + return -EINVAL; + + if (!(server[protocol] && server[protocol]->netlinknh)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("netlink event service not running")); return -1; } - return (int)nl_socket_get_local_port(server->netlinknh); + return (int)nl_socket_get_local_port(server[protocol]->netlinknh); }
@@ -399,19 +456,33 @@ int virNetlinkEventServiceLocalPid(void) * start a monitor to receive netlink messages for libvirtd. * This registers a netlink socket with the event interface. * + * @protocol: netlink protocol + * @groups: broadcast groups to join in * Returns -1 if the monitor cannot be registered, 0 upon success */ int -virNetlinkEventServiceStart(void) +virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups) { virNetlinkEventSrvPrivatePtr srv; int fd; int ret = -1;
- if (server) + if (protocol >= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return -EINVAL; + } + + if (groups >= 32) { + virReportSystemError(EINVAL, + _("invalid group argument: %d"), groups); + return -EINVAL; + } + + if (server[protocol]) return 0;
- VIR_INFO("starting netlink event service"); + VIR_INFO("starting netlink event service with protocol %d", protocol);
if (VIR_ALLOC(srv) < 0) { virReportOOMError(); @@ -434,20 +505,26 @@ virNetlinkEventServiceStart(void) goto error_locked; }
- if (nl_connect(srv->netlinknh, NETLINK_ROUTE) < 0) { + if (nl_connect(srv->netlinknh, protocol) < 0) { virReportSystemError(errno, - "%s", _("cannot connect to netlink socket")); + _("cannot connect to netlink socket with protocol %d"), protocol); goto error_server; }
fd = nl_socket_get_fd(srv->netlinknh); - if (fd < 0) { virReportSystemError(errno, "%s", _("cannot get netlink socket fd")); goto error_server; }
+ if (groups && setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &groups, sizeof(groups)) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); + goto error_server; + } + if (nl_socket_set_nonblocking(srv->netlinknh)) { virReportSystemError(errno, "%s", _("cannot set netlink socket nonblocking")); @@ -467,7 +544,7 @@ virNetlinkEventServiceStart(void) VIR_DEBUG("netlink event listener on fd: %i running", fd);
ret = 0; - server = srv; + server[protocol] = srv;
error_server: if (ret < 0) { @@ -491,6 +568,7 @@ error_locked: * @opaque: user data to pass to callback * @macaddr: macaddr to store with the data. Used to identify callers. * May be null. + * @protocol: netlink protocol * * register a callback for handling of netlink messages. The * registered function receives the entire netlink message and @@ -502,10 +580,16 @@ error_locked: int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB, virNetlinkEventRemoveCallback removeCB, - void *opaque, const virMacAddrPtr macaddr) + void *opaque, const virMacAddrPtr macaddr, + unsigned int protocol) { int i, r, ret = -1; - virNetlinkEventSrvPrivatePtr srv = server; + virNetlinkEventSrvPrivatePtr srv = NULL; + + if (protocol >= MAX_LINKS) + return -EINVAL; + + srv = server[protocol];
if (handleCB == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -562,6 +646,7 @@ error: * * @watch: watch whose handle to remove * @macaddr: macaddr whose handle to remove + * @protocol: netlink protocol * * Unregister a callback from a netlink monitor. * The handler function referenced will no longer receive netlink messages. @@ -570,11 +655,17 @@ error: * Returns -1 if the file handle was not registered, 0 upon success */ int -virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr) +virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr, + unsigned int protocol) { int i; int ret = -1; - virNetlinkEventSrvPrivatePtr srv = server; + virNetlinkEventSrvPrivatePtr srv = NULL; + + if (protocol >= MAX_LINKS) + return -EINVAL; + + srv = server[protocol];
VIR_DEBUG("removing client watch=%d, mac=%p.", watch, macaddr);
@@ -595,7 +686,7 @@ virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr)
VIR_DEBUG("removed client: %d by %s.", srv->handles[i].watch, watch ? "index" : "mac"); - virNetlinkEventRemoveClientPrimitive(i); + virNetlinkEventRemoveClientPrimitive(i, protocol); ret = 0; goto cleanup; } @@ -631,7 +722,9 @@ int virNetlinkCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, unsigned char **respbuf ATTRIBUTE_UNUSED, unsigned int *respbuflen ATTRIBUTE_UNUSED, uint32_t src_pid ATTRIBUTE_UNUSED, - uint32_t dst_pid ATTRIBUTE_UNUSED) + uint32_t dst_pid ATTRIBUTE_UNUSED, + unsigned int protocol ATTRIBUTE_UNUSED, + unsigned int groups ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; @@ -641,7 +734,7 @@ int virNetlinkCommand(struct nl_msg *nl_msg ATTRIBUTE_UNUSED, * stopNetlinkEventServer: stop the monitor to receive netlink * messages for libvirtd */ -int virNetlinkEventServiceStop(void) +int virNetlinkEventServiceStop(unsigned int protocol ATTRIBUTE_UNUSED) { VIR_DEBUG("%s", _(unsupported)); return 0; @@ -651,7 +744,8 @@ int virNetlinkEventServiceStop(void) * startNetlinkEventServer: start a monitor to receive netlink * messages for libvirtd */ -int virNetlinkEventServiceStart(void) +int virNetlinkEventServiceStart(unsigned int protocol ATTRIBUTE_UNUSED, + unsigned int groups ATTRIBUTE_UNUSED) { VIR_DEBUG("%s", _(unsupported)); return 0; @@ -661,13 +755,13 @@ int virNetlinkEventServiceStart(void) * virNetlinkEventServiceIsRunning: returns if the netlink event * service is running. */ -bool virNetlinkEventServiceIsRunning(void) +bool virNetlinkEventServiceIsRunning(unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return 0; }
-int virNetlinkEventServiceLocalPid(void) +int virNetlinkEventServiceLocalPid(unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; @@ -681,6 +775,7 @@ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB ATTRIBUTE_UN virNetlinkEventRemoveCallback removeCB ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED, const virMacAddrPtr macaddr ATTRIBUTE_UNUSED) + unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; @@ -691,6 +786,7 @@ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB ATTRIBUTE_UN */ int virNetlinkEventRemoveClient(int watch ATTRIBUTE_UNUSED, const virMacAddrPtr macaddr ATTRIBUTE_UNUSED) + unsigned int protocol ATTRIBUTE_UNUSED) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); return -1; diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index 5d8337d..2e18af4 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -41,7 +41,8 @@ void virNetlinkShutdown(void);
int virNetlinkCommand(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, - uint32_t src_port, uint32_t dst_port); + uint32_t src_pid, uint32_t dst_pid, + unsigned int protocol, unsigned int groups);
typedef void (*virNetlinkEventHandleCallback)(unsigned char *msg, int length, struct sockaddr_nl *peer, bool *handled, void *opaque);
@@ -50,33 +51,35 @@ typedef void (*virNetlinkEventRemoveCallback)(int watch, const virMacAddrPtr mac /** * stopNetlinkEventServer: stop the monitor to receive netlink messages for libvirtd */ -int virNetlinkEventServiceStop(void); +int virNetlinkEventServiceStop(unsigned int protocol);
/** * startNetlinkEventServer: start a monitor to receive netlink messages for libvirtd */ -int virNetlinkEventServiceStart(void); +int virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups);
/** * virNetlinkEventServiceIsRunning: returns if the netlink event service is running. */ -bool virNetlinkEventServiceIsRunning(void); +bool virNetlinkEventServiceIsRunning(unsigned int protocol);
/** * virNetlinkEventServiceLocalPid: returns nl_pid used to bind() netlink socket */ -int virNetlinkEventServiceLocalPid(void); +int virNetlinkEventServiceLocalPid(unsigned int protocol);
/** * virNetlinkEventAddClient: register a callback for handling of netlink messages */ int virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB, virNetlinkEventRemoveCallback removeCB, - void *opaque, const virMacAddrPtr macaddr); + void *opaque, const virMacAddrPtr macaddr, + unsigned int protocol);
/** * virNetlinkEventRemoveClient: unregister a callback from a netlink monitor */ -int virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr); +int virNetlinkEventRemoveClient(int watch, const virMacAddrPtr macaddr, + unsigned int protocol);
#endif /* __VIR_NETLINK_H__ */ -- 1.7.10.1
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Doug Goldstein

Hi~ On 08/21/2012 11:04 PM, Doug Goldstein wrote:
This patch improve all the API in virnetlink.c to support all kinds of netlink protocols, and make all netlink sockets be able to join in groups.
SOL_NETLINK is not defined on every system, so this patch defines SOL_NETLINK as 270.
Signed-off-by: Tang Chen<tangchen@cn.fujitsu.com> --- The commit message is a bit weak on what exactly is being added. The most details are about a 3 line change. OK, I will fix this. :) -static virNetlinkEventSrvPrivatePtr server = NULL; +static virNetlinkEventSrvPrivatePtr server[MAX_LINKS] = {NULL}; static virNetlinkHandle *placeholder_nlhandle = NULL; Maybe a little code comment as to why MAX_LINKS. e.g. The Linux kernel supports up to MAX_LINKS (32 at the time) individual netlink
On Tue, Aug 21, 2012 at 5:12 AM, Tang Chen<tangchen@cn.fujitsu.com> wrote: protocols. Sure, I will add some comments. :)
/* Function definitions */ @@ -158,6 +163,7 @@ virNetlinkShutdown(void) * @respbuflen: pointer to integer holding the size of the response buffer * on return of the function. * @nl_pid: the pid of the process to talk to, i.e., pid = 0 for kernel + * @protocol: netlink protocol * * Send the given message to the netlink layer and receive response. * Returns 0 on success, -1 on error. In case of error, no response Function documentation doesn't match your implementation below. I will fix it. :)
@@ -165,7 +171,8 @@ virNetlinkShutdown(void) */ int virNetlinkCommand(struct nl_msg *nl_msg, unsigned char **respbuf, unsigned int *respbuflen, - uint32_t src_pid, uint32_t dst_pid) + uint32_t src_pid, uint32_t dst_pid, + unsigned int protocol, unsigned int groups) { int rc = 0; struct sockaddr_nl nladdr = { @@ -181,17 +188,46 @@ int virNetlinkCommand(struct nl_msg *nl_msg, int fd; int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); - virNetlinkHandle *nlhandle = virNetlinkAlloc(); + virNetlinkHandle *nlhandle = NULL; + + if (protocol>= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return -EINVAL; + } + + if (groups>= 32) { I believe there is a define for this in the headers so it would be better to use that then hardcoding a number without any code comments to what it means. If there's not a define, I would at least document what the 32 is and where it derives from the kernel code so that if things change in the future it will be easier to fix. I found that the document of nl_socket_add_membership() said the following:
"Joins the specified group using the modern socket option which is available since kernel version 2.6.14. It allows joining an almost arbitary number of groups without limitation." So maybe a check for "groups" is not necessary. Can we just replace setsockopt() with nl_socket_add_membership() and leave the checking and error handling in nl_socket_add_membership() ?
+ virReportSystemError(EINVAL, + _("invalid group argument: %d"), groups); + return -EINVAL; + }
+ nlhandle = virNetlinkAlloc(); if (!nlhandle) { virReportSystemError(errno, "%s", _("cannot allocate nlhandle for netlink")); return -1; }
- if (nl_connect(nlhandle, NETLINK_ROUTE)< 0) { + if (nl_connect(nlhandle, protocol)< 0) { virReportSystemError(errno, - "%s", _("cannot connect to netlink socket")); + _("cannot connect to netlink socket with protocol %d"), protocol); + rc = -1; + goto error; + } + + fd = nl_socket_get_fd(nlhandle); + if (fd< 0) { + virReportSystemError(errno, + "%s", _("cannot get netlink socket fd")); + rc = -1; + goto error; + } + + if (groups&& setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, +&groups, sizeof(groups))< 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); rc = -1; goto error; } @@ -208,8 +244,6 @@ int virNetlinkCommand(struct nl_msg *nl_msg, goto error; }

Hi ~ On 08/21/2012 11:04 PM, Doug Goldstein wrote:
+ virNetlinkHandle *nlhandle = NULL; + + if (protocol>= MAX_LINKS) { + virReportSystemError(EINVAL, + _("invalid protocol argument: %d"), protocol); + return -EINVAL; + } + + if (groups>= 32) { I believe there is a define for this in the headers so it would be better to use that then hardcoding a number without any code comments to what it means. If there's not a define, I would at least document what the 32 is and where it derives from the kernel code so that if things change in the future it will be easier to fix. And also, it was my mistake to have a little misunderstanding about this argument. "groups" should be a mask representing the groups to join in. So this check is obviously wrong.
Thanks for the comments. :)

This patch introduce virNetlinkEventServiceStopAll() to stop all the monitors to receive netlink messages for libvirtd. Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> --- daemon/libvirtd.c | 2 +- src/libvirt_private.syms | 1 + src/util/virnetlink.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virnetlink.h | 5 +++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index e2e4fbd..922c5b5 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1325,7 +1325,7 @@ int main(int argc, char **argv) { 0, "shutdown", NULL, NULL); cleanup: - virNetlinkEventServiceStop(NETLINK_ROUTE); + virNetlinkEventServiceStopAll(); virObjectUnref(remoteProgram); virObjectUnref(qemuProgram); virNetServerClose(srv); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a55fb73..af1a22a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1470,6 +1470,7 @@ virNetlinkEventRemoveClient; virNetlinkEventServiceIsRunning; virNetlinkEventServiceLocalPid; virNetlinkEventServiceStop; +virNetlinkEventServiceStopAll; virNetlinkEventServiceStart; virNetlinkShutdown; virNetlinkStartup; diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 8a227df..fff98f1 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -407,6 +407,46 @@ virNetlinkEventServiceStop(unsigned int protocol) } /** + * virNetlinkEventServiceStopAll: + * + * Stop all the monitors to receive netlink messages for libvirtd. + * + * Returns -1 if any monitor cannot be unregistered, 0 upon success + */ +int +virNetlinkEventServiceStopAll(void) +{ + unsigned int i, j; + + VIR_INFO("stopping all netlink event services"); + + virNetlinkEventSrvPrivatePtr srv = NULL; + for (i = 0; i < MAX_LINKS; i++) { + srv = server[i]; + if (!srv) + continue; + + virNetlinkEventServerLock(srv); + nl_close(srv->netlinknh); + virNetlinkFree(srv->netlinknh); + virEventRemoveHandle(srv->eventwatch); + + for (j = 0; j < srv->handlesCount; j++) { + if (srv->handles[j].deleted == VIR_NETLINK_HANDLE_VALID) + virNetlinkEventRemoveClientPrimitive(j, i); + } + + server[i] = NULL; + virNetlinkEventServerUnlock(srv); + + virMutexDestroy(&srv->lock); + VIR_FREE(srv); + } + + return 0; +} + +/** * virNetlinkEventServiceIsRunning: * * Returns if the netlink event service is running. @@ -741,6 +781,16 @@ int virNetlinkEventServiceStop(unsigned int protocol ATTRIBUTE_UNUSED) } /** + * stopNetlinkEventServerAll: stop all the monitors to receive netlink + * messages for libvirtd + */ +int virNetlinkEventServiceStopAll(void) +{ + VIR_DEBUG("%s", _(unsupported)); + return 0; +} + +/** * startNetlinkEventServer: start a monitor to receive netlink * messages for libvirtd */ diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h index 2e18af4..1982dae 100644 --- a/src/util/virnetlink.h +++ b/src/util/virnetlink.h @@ -54,6 +54,11 @@ typedef void (*virNetlinkEventRemoveCallback)(int watch, const virMacAddrPtr mac int virNetlinkEventServiceStop(unsigned int protocol); /** + * stopNetlinkEventServerAll: stop all the monitors to receive netlink messages for libvirtd + */ +int virNetlinkEventServiceStopAll(void); + +/** * startNetlinkEventServer: start a monitor to receive netlink messages for libvirtd */ int virNetlinkEventServiceStart(unsigned int protocol, unsigned int groups); -- 1.7.10.1

This patch adds a new netlink service with NETLINK_KOBJECT_UEVENT protocol hotplug event. Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> --- daemon/libvirtd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 922c5b5..c0a2f03 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1316,6 +1316,12 @@ int main(int argc, char **argv) { goto cleanup; } + /* Register the netlink event service for NETLINK_KOBJECT_UEVENT */ + if (virNetlinkEventServiceStart(NETLINK_KOBJECT_UEVENT, 1) < 0) { + ret = VIR_DAEMON_ERR_NETWORK; + goto cleanup; + } + /* Run event loop. */ virNetServerRun(srv); -- 1.7.10.1

Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> --- src/util/virnetlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index fff98f1..3e6f26a 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -342,6 +342,8 @@ virNetlinkEventCallback(int watch, return; } + VIR_DEBUG("Netlink msg: %s", msg); + virNetlinkEventServerLock(srv); VIR_DEBUG("dispatching to max %d clients, called from event watch %d", -- 1.7.10.1

On Tue, Aug 21, 2012 at 5:12 AM, Tang Chen <tangchen@cn.fujitsu.com> wrote:
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com> --- src/util/virnetlink.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index fff98f1..3e6f26a 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -342,6 +342,8 @@ virNetlinkEventCallback(int watch, return; }
+ VIR_DEBUG("Netlink msg: %s", msg);
Netlink messages aren't guaranteed to be printable characters or NULL terminated strings. A lot of times they are binary structures tossed from the kernel to user space and printing them like this could lead to bad things.
+ virNetlinkEventServerLock(srv);
VIR_DEBUG("dispatching to max %d clients, called from event watch %d", -- 1.7.10.1
-- Doug Goldstein

On 08/21/2012 11:11 PM, Doug Goldstein wrote:
On Tue, Aug 21, 2012 at 5:12 AM, Tang Chen<tangchen@cn.fujitsu.com> wrote:
Signed-off-by: Tang Chen<tangchen@cn.fujitsu.com> --- src/util/virnetlink.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index fff98f1..3e6f26a 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -342,6 +342,8 @@ virNetlinkEventCallback(int watch, return; }
+ VIR_DEBUG("Netlink msg: %s", msg); Netlink messages aren't guaranteed to be printable characters or NULL terminated strings. A lot of times they are binary structures tossed from the kernel to user space and printing them like this could lead to bad things. OK, I see. I will remove this and try to find out a better idea. Thanks. :)
+ virNetlinkEventServerLock(srv);
VIR_DEBUG("dispatching to max %d clients, called from event watch %d", -- 1.7.10.1
participants (2)
-
Doug Goldstein
-
Tang Chen