cleanup: make nlComm commonly available

In a first cleanup step, make nlComm from macvtap.c commonly available
for other code to use. Since nlComm uses Linux-specific structures as
parameters it's prototype is only visible on Linux.
This commit is contained in:
Stefan Berger 2011-06-22 14:17:36 -04:00
parent 50a6a1267a
commit 6a5978833a
6 changed files with 175 additions and 97 deletions

View File

@ -101,6 +101,7 @@ src/util/interface.c
src/util/iptables.c
src/util/json.c
src/util/macvtap.c
src/util/netlink.c
src/util/network.c
src/util/pci.c
src/util/processinfo.c

View File

@ -63,6 +63,7 @@ UTIL_SOURCES = \
util/logging.c util/logging.h \
util/macvtap.c util/macvtap.h \
util/memory.c util/memory.h \
util/netlink.c util/netlink.h \
util/pci.c util/pci.h \
util/processinfo.c util/processinfo.h \
util/hostusb.c util/hostusb.h \

View File

@ -670,6 +670,10 @@ virResizeN;
virShrinkN;
#netlink.h
nlComm;
# network.h
virSocketAddrBroadcast;
virSocketAddrBroadcastByPrefix;

View File

@ -39,12 +39,8 @@
# include <sys/ioctl.h>
# include <linux/if.h>
# include <linux/netlink.h>
# include <linux/rtnetlink.h>
# include <linux/if_tun.h>
# include <netlink/msg.h>
/* Older kernels lacked this enum value. */
# if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
# define MACVLAN_MODE_PASSTHRU 8
@ -69,6 +65,7 @@ VIR_ENUM_IMPL(virMacvtapMode, VIR_MACVTAP_MODE_LAST,
# include "virterror_internal.h"
# include "uuid.h"
# include "files.h"
# include "netlink.h"
# define VIR_FROM_THIS VIR_FROM_NET
@ -84,8 +81,6 @@ VIR_ENUM_IMPL(virMacvtapMode, VIR_MACVTAP_MODE_LAST,
# define NLMSGBUF_SIZE 256
# define RATTBUF_SIZE 64
# define NETLINK_ACK_TIMEOUT_S 2
# define STATUS_POLL_TIMEOUT_USEC (10 * MICROSEC_PER_SEC)
# define STATUS_POLL_INTERVL_USEC (MICROSEC_PER_SEC / 8)
@ -101,97 +96,6 @@ enum virVirtualPortOp {
};
/**
* nlComm:
* @nlmsg: pointer to netlink message
* @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
*
* Send the given message to the netlink layer and receive response.
* Returns 0 on success, -1 on error. In case of error, no response
* buffer will be returned.
*/
static
int nlComm(struct nl_msg *nl_msg,
unsigned char **respbuf, unsigned int *respbuflen,
int nl_pid)
{
int rc = 0;
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK,
.nl_pid = nl_pid,
.nl_groups = 0,
};
ssize_t nbytes;
struct timeval tv = {
.tv_sec = NETLINK_ACK_TIMEOUT_S,
};
fd_set readfds;
int fd;
int n;
struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
struct nl_handle *nlhandle = nl_handle_alloc();
if (!nlhandle) {
virReportSystemError(errno,
"%s", _("cannot allocate nlhandle for netlink"));
return -1;
}
if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
virReportSystemError(errno,
"%s", _("cannot connect to netlink socket"));
rc = -1;
goto err_exit;
}
nlmsg_set_dst(nl_msg, &nladdr);
nlmsg->nlmsg_pid = getpid();
nbytes = nl_send_auto_complete(nlhandle, nl_msg);
if (nbytes < 0) {
virReportSystemError(errno,
"%s", _("cannot send to netlink socket"));
rc = -1;
goto err_exit;
}
fd = nl_socket_get_fd(nlhandle);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
n = select(fd + 1, &readfds, NULL, NULL, &tv);
if (n <= 0) {
if (n < 0)
virReportSystemError(errno, "%s",
_("error in select call"));
if (n == 0)
virReportSystemError(ETIMEDOUT, "%s",
_("no valid netlink response was received"));
rc = -1;
goto err_exit;
}
*respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
if (*respbuflen <= 0) {
virReportSystemError(errno,
"%s", _("nl_recv failed"));
rc = -1;
}
err_exit:
if (rc == -1) {
VIR_FREE(*respbuf);
*respbuf = NULL;
*respbuflen = 0;
}
nl_handle_destroy(nlhandle);
return rc;
}
# if WITH_MACVTAP

150
src/util/netlink.c Normal file
View File

@ -0,0 +1,150 @@
/*
* Copyright (C) 2010-2011 Red Hat, Inc.
* Copyright (C) 2010 IBM Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors:
* Stefan Berger <stefanb@us.ibm.com>
*
* Notes:
* netlink: http://lovezutto.googlepages.com/netlink.pdf
* iproute2 package
*
*/
#include <config.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include "netlink.h"
#include "memory.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_NET
#define netlinkError(code, ...) \
virReportErrorHelper(VIR_FROM_NET, code, __FILE__, \
__FUNCTION__, __LINE__, __VA_ARGS__)
#define NETLINK_ACK_TIMEOUT_S 2
/**
* nlComm:
* @nlmsg: pointer to netlink message
* @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
*
* Send the given message to the netlink layer and receive response.
* Returns 0 on success, -1 on error. In case of error, no response
* buffer will be returned.
*/
#if __linux__
int nlComm(struct nl_msg *nl_msg,
unsigned char **respbuf, unsigned int *respbuflen,
int nl_pid)
{
int rc = 0;
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK,
.nl_pid = nl_pid,
.nl_groups = 0,
};
ssize_t nbytes;
struct timeval tv = {
.tv_sec = NETLINK_ACK_TIMEOUT_S,
};
fd_set readfds;
int fd;
int n;
struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
struct nl_handle *nlhandle = nl_handle_alloc();
if (!nlhandle) {
virReportSystemError(errno,
"%s", _("cannot allocate nlhandle for netlink"));
return -1;
}
if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
virReportSystemError(errno,
"%s", _("cannot connect to netlink socket"));
rc = -1;
goto err_exit;
}
nlmsg_set_dst(nl_msg, &nladdr);
nlmsg->nlmsg_pid = getpid();
nbytes = nl_send_auto_complete(nlhandle, nl_msg);
if (nbytes < 0) {
virReportSystemError(errno,
"%s", _("cannot send to netlink socket"));
rc = -1;
goto err_exit;
}
fd = nl_socket_get_fd(nlhandle);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
n = select(fd + 1, &readfds, NULL, NULL, &tv);
if (n <= 0) {
if (n < 0)
virReportSystemError(errno, "%s",
_("error in select call"));
if (n == 0)
virReportSystemError(ETIMEDOUT, "%s",
_("no valid netlink response was received"));
rc = -1;
goto err_exit;
}
*respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
if (*respbuflen <= 0) {
virReportSystemError(errno,
"%s", _("nl_recv failed"));
rc = -1;
}
err_exit:
if (rc == -1) {
VIR_FREE(*respbuf);
*respbuf = NULL;
*respbuflen = 0;
}
nl_handle_destroy(nlhandle);
return rc;
}
#else
int nlComm(struct nl_msg *nl_msg ATTRIBUTE_UNUSED,
unsigned char **respbuf ATTRIBUTE_UNUSED,
unsigned int *respbuflen ATTRIBUTE_UNUSED,
int nl_pid ATTRIBUTE_UNUSED)
{
netlinkError(VIR_ERR_INTERNAL_ERROR, "%s",
_("nlComm is not supported on non-linux platforms"));
return -1;
}
#endif /* __linux__ */

18
src/util/netlink.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __VIR_NETLINK_H__
# define __VIR_NETLINK_H__
# if __linux__
# include <netlink/msg.h>
# else
struct nl_msg;
# endif /* __linux__ */
int nlComm(struct nl_msg *nl_msg,
unsigned char **respbuf, unsigned int *respbuflen,
int nl_pid);
#endif /* __VIR_NETLINK_H__ */