OVS用户态进程与内核模块是通过netlink进行通信的,本篇分析下用户态向内核态发送netlink消息的方法,发送消息入口有两个函数nl_transact和nl_transact_multiple,本篇以nl_transact_multiple为例进行分析。
1、nl_transact_multiple函数
void
nl_transact_multiple(int protocol,
struct nl_transaction **transactions, size_t n)
{
struct nl_sock *sock;
int error;
error = nl_pool_alloc(protocol, &sock); //创建socket
if (!error) {
nl_sock_transact_multiple(sock, transactions, n); //通过socket发送消息
nl_pool_release(sock);
} else {
nl_sock_record_errors__(transactions, n, error);
}
}
2、nl_pool_alloc函数
static int
nl_pool_alloc(int protocol, struct nl_sock **sockp)
{
struct nl_sock *sock = NULL;
struct nl_pool *pool;
ovs_assert(protocol >= 0 && protocol < ARRAY_SIZE(pools));
ovs_mutex_lock(&pool_mutex);
pool = &pools[protocol];<span style="white-space:pre"> </span>//根据协议检索,OVS2.5.0未看到初始化,所以不会进此流程
if (pool->n > 0) {
sock = pool->socks[--pool->n];
}
ovs_mutex_unlock(&pool_mutex);
if (sock) {
*sockp = sock;
return 0;
} else {
return nl_sock_create(protocol, sockp); //创建socket
}
}
3、nl_sock_create函数
/* Creates a new netlink socket for the given netlink 'protocol'
* (NETLINK_ROUTE, NETLINK_GENERIC, ...). Returns 0 and sets '*sockp' to the
* new socket if successful, otherwise returns a positive errno value. */
int
nl_sock_create(int protocol, struct nl_sock **sockp)
{
static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
struct nl_sock *sock;
#ifndef _WIN32
struct sockaddr_nl local, remote;
#endif
socklen_t local_size;
int rcvbuf;
int retval = 0;
if (ovsthread_once_start(&once)) {
int save_errno = errno;
errno = 0;
max_iovs = sysconf(_SC_UIO_MAXIOV);
if (max_iovs < _XOPEN_IOV_MAX) {
if (max_iovs == -1 && errno) {
VLOG_WARN("sysconf(_SC_UIO_MAXIOV): %s", ovs_strerror(errno));
}
max_iovs = _XOPEN_IOV_MAX;
} else if (max_iovs > MAX_IOVS) {
max_iovs = MAX_IOVS;
}
errno = save_errno;
ovsthread_once_done(&once);
}
*sockp = NULL;
sock = xmalloc(sizeof *sock);
#ifdef _WIN32
sock->handle = CreateFile(OVS_DEVICE_NAME_USER,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (sock->handle == INVALID_HANDLE_VALUE) {
VLOG_ERR("fcntl: %s", ovs_lasterror_to_string());
goto error;
}
memset(&sock->overlapped, 0, sizeof sock->overlapped);
sock->overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (sock->overlapped.hEvent == NULL) {
VLOG_ERR("fcntl: %s", ovs_lasterror_to_string());
goto error;
}
/* Initialize the type/ioctl to Generic */
sock->read_ioctl = OVS_IOCTL_READ;
#else
sock->fd = socket(AF_NETLINK, SOCK_RAW, protocol); //创建socket
if (sock->fd < 0) {
VLOG_ERR("fcntl: %s", ovs_strerror(errno));
goto error;
}
#endif
sock->protocol = protocol;
sock->next_seq = 1;
rcvbuf = 1024 * 1024;
#ifdef _WIN32
sock->rcvbuf = rcvbuf;
retval = get_sock_pid_from_kernel(sock);
if (retval != 0) {
goto error;
}
#else
if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE,
&rcvbuf, sizeof rcvbuf)) {
/* Only ro