[libvirt] [PATCH V3 0/3] 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 (3): Improve netlink to support all protocol. Introduce virNetlinkEventServiceStopAll() to stop all netlink services. Add uevent netlink service. 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 | 220 ++++++++++++++++++++++++++++++-------- src/util/virnetlink.h | 22 ++-- 7 files changed, 218 insertions(+), 62 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. 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 | 170 ++++++++++++++++++++++++++++---------- src/util/virnetlink.h | 17 ++-- 6 files changed, 156 insertions(+), 62 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..64bd47d 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,9 @@ static int nextWatch = 1; records in this multiple */ # define NETLINK_EVENT_ALLOC_EXTENT 10 -static virNetlinkEventSrvPrivatePtr server = NULL; +/* Linux kernel supports up to MAX_LINKS (32 at the time) individual + * netlink protocols. */ +static virNetlinkEventSrvPrivatePtr server[MAX_LINKS] = {NULL}; static virNetlinkHandle *placeholder_nlhandle = NULL; /* Function definitions */ @@ -157,7 +164,10 @@ virNetlinkShutdown(void) * @respbuf: pointer to pointer where response buffer will be allocated * @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 + * @src_pid: the pid of the process to send a message + * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel + * @protocol: netlink protocol + * @groups: the group identifier * * 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 +175,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 +192,39 @@ 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; + } + 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, + _("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 connect to netlink socket")); + "%s", _("cannot get netlink socket fd")); + rc = -1; + goto error; + } + + if (groups && nl_socket_add_membership(nlhandle, groups) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); rc = -1; goto error; } @@ -208,8 +241,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 +289,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 +299,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 +366,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 +392,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 +408,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 +453,27 @@ 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 (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 +496,25 @@ 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 && nl_socket_add_membership(srv->netlinknh, 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 +534,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 +558,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 +570,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 +636,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 +645,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 +676,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 +712,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 +724,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 +734,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 +745,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 +765,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 +776,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 Wed, Aug 22, 2012 at 12:10:23PM +0800, Tang Chen 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.
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 | 170 ++++++++++++++++++++++++++++---------- src/util/virnetlink.h | 17 ++-- 6 files changed, 156 insertions(+), 62 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..64bd47d 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 +
This needed some indetation otherwise "make syntax-check" would complain. I wonder if MAX_LINKS shouldn't be checked too #ifdef MAX_LINKS # define MAX_LINKS 32 #endif
#define VIR_FROM_THIS VIR_FROM_NET
#define NETLINK_ACK_TIMEOUT_S 2 @@ -93,7 +98,9 @@ static int nextWatch = 1; records in this multiple */ # define NETLINK_EVENT_ALLOC_EXTENT 10
-static virNetlinkEventSrvPrivatePtr server = NULL; +/* Linux kernel supports up to MAX_LINKS (32 at the time) individual + * netlink protocols. */ +static virNetlinkEventSrvPrivatePtr server[MAX_LINKS] = {NULL}; static virNetlinkHandle *placeholder_nlhandle = NULL;
/* Function definitions */ @@ -157,7 +164,10 @@ virNetlinkShutdown(void) * @respbuf: pointer to pointer where response buffer will be allocated * @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 + * @src_pid: the pid of the process to send a message + * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel + * @protocol: netlink protocol + * @groups: the group identifier * * 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 +175,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 +192,39 @@ 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; + }
+ 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, + _("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 connect to netlink socket")); + "%s", _("cannot get netlink socket fd")); + rc = -1; + goto error; + } + + if (groups && nl_socket_add_membership(nlhandle, groups) < 0) { + virReportSystemError(errno, + "%s", _("cannot add netlink membership")); rc = -1; goto error; } @@ -208,8 +241,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 +289,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 +299,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 +366,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 +392,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 +408,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 +453,27 @@ 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 (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 +496,25 @@ 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 && nl_socket_add_membership(srv->netlinknh, 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 +534,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 +558,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 +570,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 +636,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 +645,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 +676,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 +712,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 +724,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 +734,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 +745,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 +765,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 +776,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__ */
Overall looks fine, though i had to apply the following patch for cleanup, ACK Daniel diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 64bd47d..1ec9976 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -43,7 +43,7 @@ #include "virterror_internal.h" #ifndef SOL_NETLINK -#define SOL_NETLINK 270 +# define SOL_NETLINK 270 #endif #define VIR_FROM_THIS VIR_FROM_NET @@ -193,7 +193,7 @@ int virNetlinkCommand(struct nl_msg *nl_msg, int n; struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg); virNetlinkHandle *nlhandle = NULL; - + if (protocol >= MAX_LINKS) { virReportSystemError(EINVAL, _("invalid protocol argument: %d"), protocol); @@ -209,7 +209,8 @@ int virNetlinkCommand(struct nl_msg *nl_msg, if (nl_connect(nlhandle, protocol) < 0) { virReportSystemError(errno, - _("cannot connect to netlink socket with protocol %d"), protocol); + _("cannot connect to netlink socket with protocol %d"), + protocol); rc = -1; goto error; } @@ -575,7 +576,7 @@ virNetlinkEventAddClient(virNetlinkEventHandleCallback handleCB, { int i, r, ret = -1; virNetlinkEventSrvPrivatePtr srv = NULL; - + if (protocol >= MAX_LINKS) return -EINVAL; -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

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 64bd47d..944ebe1 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -404,6 +404,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. @@ -731,6 +771,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

On Wed, Aug 22, 2012 at 12:10:24PM +0800, Tang Chen wrote:
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;
that's not kept in order but not really your fault ;-)
virNetlinkShutdown; virNetlinkStartup; diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 64bd47d..944ebe1 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -404,6 +404,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;
aestetic, we usually define variables before code in the function block
+ 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. @@ -731,6 +771,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); --
Okay, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

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

On Wed, Aug 22, 2012 at 12:10:25PM +0800, Tang Chen wrote:
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);
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel Veillard
-
Tang Chen