static int nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg, uint32_t nlmsg_seq, bool wait) { struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(msg); int error; nlmsg->nlmsg_len = ofpbuf_size(msg); nlmsg->nlmsg_seq = nlmsg_seq; nlmsg->nlmsg_pid = sock->pid; do { int retval; #ifdef _WIN32 bool result; DWORD last_error = 0; result = WriteFile(sock->handle, ofpbuf_data(msg), ofpbuf_size(msg), &retval, NULL); last_error = GetLastError(); if (last_error != ERROR_SUCCESS && !result) { retval = -1; errno = EAGAIN; } #else retval = send(sock->fd, ofpbuf_data(msg), ofpbuf_size(msg), wait ? 0 : MSG_DONTWAIT); #endif error = retval < 0 ? errno : 0; } while (error == EINTR); log_nlmsg(__func__, error, ofpbuf_data(msg), ofpbuf_size(msg), sock->protocol); if (!error) { COVERAGE_INC(netlink_sent); } return error; }
static int nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg, uint32_t nlmsg_seq, bool wait) { struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(msg); int error; nlmsg->nlmsg_len = msg->size; nlmsg->nlmsg_seq = nlmsg_seq; nlmsg->nlmsg_pid = sock->pid; do { int retval; retval = send(sock->fd, msg->data, msg->size, wait ? 0 : MSG_DONTWAIT); error = retval < 0 ? errno : 0; } while (error == EINTR); log_nlmsg(__func__, error, msg->data, msg->size, sock->protocol); if (!error) { COVERAGE_INC(netlink_sent); } return error; }
static int nl_sock_transact_multiple__(struct nl_sock *sock, struct nl_transaction **transactions, size_t n, size_t *done) { uint64_t tmp_reply_stub[1024 / 8]; struct nl_transaction tmp_txn; struct ofpbuf tmp_reply; uint32_t base_seq; struct iovec iovs[MAX_IOVS]; struct msghdr msg; int error; int i; base_seq = nl_sock_allocate_seq(sock, n); *done = 0; for (i = 0; i < n; i++) { struct nl_transaction *txn = transactions[i]; struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(txn->request); nlmsg->nlmsg_len = txn->request->size; nlmsg->nlmsg_seq = base_seq + i; nlmsg->nlmsg_pid = sock->pid; iovs[i].iov_base = txn->request->data; iovs[i].iov_len = txn->request->size; } memset(&msg, 0, sizeof msg); msg.msg_iov = iovs; msg.msg_iovlen = n; do { error = sendmsg(sock->fd, &msg, 0) < 0 ? errno : 0; } while (error == EINTR); for (i = 0; i < n; i++) { struct nl_transaction *txn = transactions[i]; log_nlmsg(__func__, error, txn->request->data, txn->request->size, sock->protocol); } if (!error) { COVERAGE_ADD(netlink_sent, n); } if (error) { return error; } ofpbuf_use_stub(&tmp_reply, tmp_reply_stub, sizeof tmp_reply_stub); tmp_txn.request = NULL; tmp_txn.reply = &tmp_reply; tmp_txn.error = 0; while (n > 0) { struct nl_transaction *buf_txn, *txn; uint32_t seq; /* Find a transaction whose buffer we can use for receiving a reply. * If no such transaction is left, use tmp_txn. */ buf_txn = &tmp_txn; for (i = 0; i < n; i++) { if (transactions[i]->reply) { buf_txn = transactions[i]; break; } } /* Receive a reply. */ error = nl_sock_recv__(sock, buf_txn->reply, false); if (error) { if (error == EAGAIN) { nl_sock_record_errors__(transactions, n, 0); *done += n; error = 0; } break; } /* Match the reply up with a transaction. */ seq = nl_msg_nlmsghdr(buf_txn->reply)->nlmsg_seq; if (seq < base_seq || seq >= base_seq + n) { VLOG_DBG_RL(&rl, "ignoring unexpected seq %#"PRIx32, seq); continue; } i = seq - base_seq; txn = transactions[i]; /* Fill in the results for 'txn'. */ if (nl_msg_nlmsgerr(buf_txn->reply, &txn->error)) { if (txn->reply) { ofpbuf_clear(txn->reply); } if (txn->error) { VLOG_DBG_RL(&rl, "received NAK error=%d (%s)", error, ovs_strerror(txn->error)); } } else { txn->error = 0; if (txn->reply && txn != buf_txn) { /* Swap buffers. */ struct ofpbuf *reply = buf_txn->reply; buf_txn->reply = txn->reply; txn->reply = reply; } } /* Fill in the results for transactions before 'txn'. (We have to do * this after the results for 'txn' itself because of the buffer swap * above.) */ nl_sock_record_errors__(transactions, i, 0); /* Advance. */ *done += i + 1; transactions += i + 1; n -= i + 1; base_seq += i + 1; } ofpbuf_uninit(&tmp_reply); return error; }
static int nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait) { /* We can't accurately predict the size of the data to be received. The * caller is supposed to have allocated enough space in 'buf' to handle the * "typical" case. To handle exceptions, we make available enough space in * 'tail' to allow Netlink messages to be up to 64 kB long (a reasonable * figure since that's the maximum length of a Netlink attribute). */ struct nlmsghdr *nlmsghdr; uint8_t tail[65536]; struct iovec iov[2]; struct msghdr msg; ssize_t retval; ovs_assert(buf->allocated >= sizeof *nlmsghdr); ofpbuf_clear(buf); iov[0].iov_base = buf->base; iov[0].iov_len = buf->allocated; iov[1].iov_base = tail; iov[1].iov_len = sizeof tail; memset(&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = 2; do { retval = recvmsg(sock->fd, &msg, wait ? 0 : MSG_DONTWAIT); } while (retval < 0 && errno == EINTR); if (retval < 0) { int error = errno; if (error == ENOBUFS) { /* Socket receive buffer overflow dropped one or more messages that * the kernel tried to send to us. */ COVERAGE_INC(netlink_overflow); } return error; } if (msg.msg_flags & MSG_TRUNC) { VLOG_ERR_RL(&rl, "truncated message (longer than %zu bytes)", sizeof tail); return E2BIG; } nlmsghdr = buf->data; if (retval < sizeof *nlmsghdr || nlmsghdr->nlmsg_len < sizeof *nlmsghdr || nlmsghdr->nlmsg_len > retval) { VLOG_ERR_RL(&rl, "received invalid nlmsg (%zd bytes < %zu)", retval, sizeof *nlmsghdr); return EPROTO; } buf->size = MIN(retval, buf->allocated); if (retval > buf->allocated) { COVERAGE_INC(netlink_recv_jumbo); ofpbuf_put(buf, tail, retval - buf->allocated); } log_nlmsg(__func__, 0, buf->data, buf->size, sock->protocol); COVERAGE_INC(netlink_received); return 0; }
static int nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait) { /* We can't accurately predict the size of the data to be received. The * caller is supposed to have allocated enough space in 'buf' to handle the * "typical" case. To handle exceptions, we make available enough space in * 'tail' to allow Netlink messages to be up to 64 kB long (a reasonable * figure since that's the maximum length of a Netlink attribute). */ struct nlmsghdr *nlmsghdr; #ifdef _WIN32 #define MAX_STACK_LENGTH 81920 uint8_t tail[MAX_STACK_LENGTH]; #else uint8_t tail[65536]; #endif struct iovec iov[2]; struct msghdr msg; ssize_t retval; int error; ovs_assert(buf->allocated >= sizeof *nlmsghdr); ofpbuf_clear(buf); iov[0].iov_base = ofpbuf_base(buf); iov[0].iov_len = buf->allocated; iov[1].iov_base = tail; iov[1].iov_len = sizeof tail; memset(&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = 2; /* Receive a Netlink message from the kernel. * * This works around a kernel bug in which the kernel returns an error code * as if it were the number of bytes read. It doesn't actually modify * anything in the receive buffer in that case, so we can initialize the * Netlink header with an impossible message length and then, upon success, * check whether it changed. */ nlmsghdr = ofpbuf_base(buf); do { nlmsghdr->nlmsg_len = UINT32_MAX; #ifdef _WIN32 boolean result = false; DWORD last_error = 0; result = ReadFile(sock->handle, tail, MAX_STACK_LENGTH, &retval, NULL); last_error = GetLastError(); if (last_error != ERROR_SUCCESS && !result) { retval = -1; errno = EAGAIN; } else { ofpbuf_put(buf, tail, retval); } #else retval = recvmsg(sock->fd, &msg, wait ? 0 : MSG_DONTWAIT); #endif error = (retval < 0 ? errno : retval == 0 ? ECONNRESET /* not possible? */ : nlmsghdr->nlmsg_len != UINT32_MAX ? 0 : retval); } while (error == EINTR); if (error) { if (error == ENOBUFS) { /* Socket receive buffer overflow dropped one or more messages that * the kernel tried to send to us. */ COVERAGE_INC(netlink_overflow); } return error; } if (msg.msg_flags & MSG_TRUNC) { VLOG_ERR_RL(&rl, "truncated message (longer than %"PRIuSIZE" bytes)", sizeof tail); return E2BIG; } if (retval < sizeof *nlmsghdr || nlmsghdr->nlmsg_len < sizeof *nlmsghdr || nlmsghdr->nlmsg_len > retval) { VLOG_ERR_RL(&rl, "received invalid nlmsg (%"PRIuSIZE" bytes < %"PRIuSIZE")", retval, sizeof *nlmsghdr); return EPROTO; } #ifndef _WIN32 ofpbuf_set_size(buf, MIN(retval, buf->allocated)); if (retval > buf->allocated) { COVERAGE_INC(netlink_recv_jumbo); ofpbuf_put(buf, tail, retval - buf->allocated); } #endif log_nlmsg(__func__, 0, ofpbuf_data(buf), ofpbuf_size(buf), sock->protocol); COVERAGE_INC(netlink_received); return 0; }