/* Reallocates 'b' so that it has exactly 'new_headroom' and 'new_tailroom' * bytes of headroom and tailroom, respectively. */ static void ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom) { void *new_base, *new_data; size_t new_allocated; new_allocated = new_headroom + ofpbuf_size(b) + new_tailroom; switch (b->source) { case OFPBUF_DPDK: OVS_NOT_REACHED(); case OFPBUF_MALLOC: if (new_headroom == ofpbuf_headroom(b)) { new_base = xrealloc(ofpbuf_base(b), new_allocated); } else { new_base = xmalloc(new_allocated); ofpbuf_copy__(b, new_base, new_headroom, new_tailroom); free(ofpbuf_base(b)); } break; case OFPBUF_STACK: OVS_NOT_REACHED(); case OFPBUF_STUB: b->source = OFPBUF_MALLOC; new_base = xmalloc(new_allocated); ofpbuf_copy__(b, new_base, new_headroom, new_tailroom); break; default: OVS_NOT_REACHED(); } b->allocated = new_allocated; ofpbuf_set_base(b, new_base); new_data = (char *) new_base + new_headroom; if (ofpbuf_data(b) != new_data) { if (b->frame) { uintptr_t data_delta = (char *) new_data - (char *) ofpbuf_data(b); b->frame = (char *) b->frame + data_delta; } ofpbuf_set_data(b, new_data); } }
/* Returns the data in 'b' as a block of malloc()'d memory and frees the buffer * within 'b'. (If 'b' itself was dynamically allocated, e.g. with * ofpbuf_new(), then it should still be freed with, e.g., ofpbuf_delete().) */ void * ofpbuf_steal_data(struct ofpbuf *b) { void *p; ovs_assert(b->source != OFPBUF_DPDK); if (b->source == OFPBUF_MALLOC && ofpbuf_data(b) == ofpbuf_base(b)) { p = ofpbuf_data(b); } else { p = xmemdup(ofpbuf_data(b), ofpbuf_size(b)); if (b->source == OFPBUF_MALLOC) { free(ofpbuf_base(b)); } } ofpbuf_set_base(b, NULL); ofpbuf_set_data(b, NULL); return p; }
static void ofpbuf_copy__(struct ofpbuf *b, uint8_t *new_base, size_t new_headroom, size_t new_tailroom) { const uint8_t *old_base = ofpbuf_base(b); size_t old_headroom = ofpbuf_headroom(b); size_t old_tailroom = ofpbuf_tailroom(b); size_t copy_headroom = MIN(old_headroom, new_headroom); size_t copy_tailroom = MIN(old_tailroom, new_tailroom); memcpy(&new_base[new_headroom - copy_headroom], &old_base[old_headroom - copy_headroom], copy_headroom + ofpbuf_size(b) + copy_tailroom); }
/* Frees memory that 'b' points to. */ void ofpbuf_uninit(struct ofpbuf *b) { if (b) { if (b->source == OFPBUF_MALLOC) { free(ofpbuf_base(b)); } else if (b->source == OFPBUF_DPDK) { #ifdef DPDK_NETDEV /* If this ofpbuf was allocated by DPDK it must have been * created as a dpif_packet */ free_dpdk_buf((struct dpif_packet*) b); #else ovs_assert(b->source != OFPBUF_DPDK); #endif } } }
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; }