/* 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) { struct nl_sock *sock; struct sockaddr_nl local, remote; socklen_t local_size; int rcvbuf; int retval = 0; if (!max_iovs) { 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", strerror(errno)); } max_iovs = _XOPEN_IOV_MAX; } else if (max_iovs > MAX_IOVS) { max_iovs = MAX_IOVS; } errno = save_errno; } *sockp = NULL; sock = malloc(sizeof *sock); if (sock == NULL) { return ENOMEM; } sock->fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (sock->fd < 0) { VLOG_ERR("fcntl: %s", strerror(errno)); goto error; } sock->protocol = protocol; sock->dump = NULL; sock->next_seq = 1; rcvbuf = 1024 * 1024; if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof rcvbuf)) { VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed (%s)", rcvbuf, strerror(errno)); } retval = get_socket_rcvbuf(sock->fd); if (retval < 0) { retval = -retval; goto error; } sock->rcvbuf = retval; /* Connect to kernel (pid 0) as remote address. */ memset(&remote, 0, sizeof remote); remote.nl_family = AF_NETLINK; remote.nl_pid = 0; if (connect(sock->fd, (struct sockaddr *) &remote, sizeof remote) < 0) { VLOG_ERR("connect(0): %s", strerror(errno)); goto error; } /* Obtain pid assigned by kernel. */ local_size = sizeof local; if (getsockname(sock->fd, (struct sockaddr *) &local, &local_size) < 0) { VLOG_ERR("getsockname: %s", strerror(errno)); goto error; } if (local_size < sizeof local || local.nl_family != AF_NETLINK) { VLOG_ERR("getsockname returned bad Netlink name"); retval = EINVAL; goto error; } sock->pid = local.nl_pid; *sockp = sock; return 0; error: if (retval == 0) { retval = errno; if (retval == 0) { retval = EINVAL; } } if (sock->fd >= 0) { close(sock->fd); } free(sock); return retval; }
/* 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; struct sockaddr_nl local, remote; 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); sock->fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (sock->fd < 0) { VLOG_ERR("fcntl: %s", ovs_strerror(errno)); goto error; } sock->protocol = protocol; sock->next_seq = 1; rcvbuf = 1024 * 1024; if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof rcvbuf)) { /* Only root can use SO_RCVBUFFORCE. Everyone else gets EPERM. * Warn only if the failure is therefore unexpected. */ if (errno != EPERM) { VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed " "(%s)", rcvbuf, ovs_strerror(errno)); } } retval = get_socket_rcvbuf(sock->fd); if (retval < 0) { retval = -retval; goto error; } sock->rcvbuf = retval; /* Connect to kernel (pid 0) as remote address. */ memset(&remote, 0, sizeof remote); remote.nl_family = AF_NETLINK; remote.nl_pid = 0; if (connect(sock->fd, (struct sockaddr *) &remote, sizeof remote) < 0) { VLOG_ERR("connect(0): %s", ovs_strerror(errno)); goto error; } /* Obtain pid assigned by kernel. */ local_size = sizeof local; if (getsockname(sock->fd, (struct sockaddr *) &local, &local_size) < 0) { VLOG_ERR("getsockname: %s", ovs_strerror(errno)); goto error; } if (local_size < sizeof local || local.nl_family != AF_NETLINK) { VLOG_ERR("getsockname returned bad Netlink name"); retval = EINVAL; goto error; } sock->pid = local.nl_pid; *sockp = sock; return 0; error: if (retval == 0) { retval = errno; if (retval == 0) { retval = EINVAL; } } if (sock->fd >= 0) { close(sock->fd); } free(sock); return retval; }
/* 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 = CreateFileA("\\\\.\\OpenVSwitchDevice", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); int last_error = GetLastError(); if (sock->handle == INVALID_HANDLE_VALUE) { VLOG_ERR("fcntl: %s", ovs_strerror(last_error)); goto error; } #else sock->fd = socket(AF_NETLINK, SOCK_RAW, protocol); 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; ovs_mutex_lock(&portid_mutex); sock->pid = portid_next(); set_sock_pid_in_kernel(sock->handle, sock->pid); ovs_mutex_unlock(&portid_mutex); #else if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof rcvbuf)) { /* Only root can use SO_RCVBUFFORCE. Everyone else gets EPERM. * Warn only if the failure is therefore unexpected. */ if (errno != EPERM) { VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed " "(%s)", rcvbuf, ovs_strerror(errno)); } } retval = get_socket_rcvbuf(sock->fd); if (retval < 0) { retval = -retval; goto error; } sock->rcvbuf = retval; /* Connect to kernel (pid 0) as remote address. */ memset(&remote, 0, sizeof remote); remote.nl_family = AF_NETLINK; remote.nl_pid = 0; if (connect(sock->fd, (struct sockaddr *) &remote, sizeof remote) < 0) { VLOG_ERR("connect(0): %s", ovs_strerror(errno)); goto error; } /* Obtain pid assigned by kernel. */ local_size = sizeof local; if (getsockname(sock->fd, (struct sockaddr *) &local, &local_size) < 0) { VLOG_ERR("getsockname: %s", ovs_strerror(errno)); goto error; } if (local_size < sizeof local || local.nl_family != AF_NETLINK) { VLOG_ERR("getsockname returned bad Netlink name"); retval = EINVAL; goto error; } sock->pid = local.nl_pid; #endif *sockp = sock; return 0; error: if (retval == 0) { retval = errno; if (retval == 0) { retval = EINVAL; } } #ifdef _WIN32 if (sock->handle != INVALID_HANDLE_VALUE) { CloseHandle(sock->handle); } #else if (sock->fd >= 0) { close(sock->fd); } #endif free(sock); return retval; }