X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fnetlink-socket.c;h=1a1b5e42a3082f5cae4f119bb8d87f044681d4b7;hb=d71c423edf5d7e9377957dddc0c72d1d0c1375b1;hp=df889d3eb449974c4535ddfbe69c05f6ddd554f8;hpb=bdd0bd2873415838643e42a1e4c08319fe8d3b8b;p=cascardo%2Fovs.git diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c index df889d3eb..1a1b5e42a 100644 --- a/lib/netlink-socket.c +++ b/lib/netlink-socket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,20 +49,6 @@ COVERAGE_DEFINE(netlink_sent); #define SOL_NETLINK 270 #endif -#ifdef _WIN32 -static struct ovs_mutex portid_mutex = OVS_MUTEX_INITIALIZER; -static uint32_t g_last_portid = 0; - -/* Port IDs must be unique! */ -static uint32_t -portid_next(void) - OVS_GUARDED_BY(portid_mutex) -{ - g_last_portid++; - return g_last_portid; -} -#endif /* _WIN32 */ - /* A single (bad) Netlink message can in theory dump out many, many log * messages, so the burst size is set quite high here to avoid missing useful * information. Also, at high logging levels we log *all* Netlink messages. */ @@ -195,6 +181,7 @@ nl_sock_create(int protocol, struct nl_sock **sockp) goto error; } sock->rcvbuf = retval; + retval = 0; /* Connect to kernel (pid 0) as remote address. */ memset(&remote, 0, sizeof remote); @@ -273,63 +260,27 @@ nl_sock_destroy(struct nl_sock *sock) #ifdef _WIN32 /* Reads the pid for 'sock' generated in the kernel datapath. The function - * follows a transaction semantic. Eventually this function should call into - * nl_transact. */ + * uses a separate IOCTL instead of a transaction semantic to avoid unnecessary + * message overhead. */ static int get_sock_pid_from_kernel(struct nl_sock *sock) { - struct nl_transaction txn; - struct ofpbuf request; - uint64_t request_stub[128]; - struct ofpbuf reply; - uint64_t reply_stub[128]; - struct ovs_header *ovs_header; - struct nlmsghdr *nlmsg; - uint32_t seq; - int retval; - DWORD bytes; - int ovs_msg_size = sizeof (struct nlmsghdr) + sizeof (struct genlmsghdr) + - sizeof (struct ovs_header); - - ofpbuf_use_stub(&request, request_stub, sizeof request_stub); - txn.request = &request; - ofpbuf_use_stub(&reply, reply_stub, sizeof reply_stub); - txn.reply = &reply; - - seq = nl_sock_allocate_seq(sock, 1); - nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0, - OVS_CTRL_CMD_WIN_GET_PID, OVS_WIN_CONTROL_VERSION); - nlmsg = nl_msg_nlmsghdr(txn.request); - nlmsg->nlmsg_seq = seq; - - ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header); - ovs_header->dp_ifindex = 0; - ovs_header = ofpbuf_put_uninit(&reply, ovs_msg_size); + uint32_t pid = 0; + int retval = 0; + DWORD bytes = 0; - if (!DeviceIoControl(sock->handle, OVS_IOCTL_TRANSACT, - txn.request->data, txn.request->size, - txn.reply->data, txn.reply->size, + if (!DeviceIoControl(sock->handle, OVS_IOCTL_GET_PID, + NULL, 0, &pid, sizeof(pid), &bytes, NULL)) { retval = EINVAL; - goto done; } else { - if (bytes < ovs_msg_size) { + if (bytes < sizeof(pid)) { retval = EINVAL; - goto done; - } - - nlmsg = nl_msg_nlmsghdr(txn.reply); - if (nlmsg->nlmsg_seq != seq) { - retval = EINVAL; - goto done; + } else { + sock->pid = pid; } - sock->pid = nlmsg->nlmsg_pid; } - retval = 0; -done: - ofpbuf_uninit(&request); - ofpbuf_uninit(&reply); return retval; } #endif /* _WIN32 */ @@ -408,8 +359,8 @@ nl_sock_subscribe_packets(struct nl_sock *sock) error = nl_sock_subscribe_packet__(sock, true); if (error) { - VLOG_WARN("could not unsubscribe packets (%s)", - ovs_strerror(errno)); + VLOG_WARN("could not subscribe packets (%s)", + ovs_strerror(error)); return error; } sock->read_ioctl = OVS_IOCTL_READ_PACKET; @@ -424,8 +375,8 @@ nl_sock_unsubscribe_packets(struct nl_sock *sock) int error = nl_sock_subscribe_packet__(sock, false); if (error) { - VLOG_WARN("could not subscribe to packets (%s)", - ovs_strerror(errno)); + VLOG_WARN("could not unsubscribe to packets (%s)", + ovs_strerror(error)); return error; } @@ -511,6 +462,8 @@ nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg, retval = -1; /* XXX: Map to a more appropriate error based on GetLastError(). */ errno = EINVAL; + VLOG_DBG_RL(&rl, "fatal driver failure in write: %s", + ovs_lasterror_to_string()); } else { retval = msg->size; } @@ -600,7 +553,10 @@ nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait) DWORD bytes; if (!DeviceIoControl(sock->handle, sock->read_ioctl, NULL, 0, tail, sizeof tail, &bytes, NULL)) { + VLOG_DBG_RL(&rl, "fatal driver failure in transact: %s", + ovs_lasterror_to_string()); retval = -1; + /* XXX: Map to a more appropriate error. */ errno = EINVAL; } else { retval = bytes; @@ -825,61 +781,78 @@ nl_sock_transact_multiple__(struct nl_sock *sock, uint8_t reply_buf[65536]; for (i = 0; i < n; i++) { DWORD reply_len; + bool ret; struct nl_transaction *txn = transactions[i]; struct nlmsghdr *request_nlmsg, *reply_nlmsg; - if (!DeviceIoControl(sock->handle, OVS_IOCTL_TRANSACT, - txn->request->data, - txn->request->size, - reply_buf, sizeof reply_buf, - &reply_len, NULL)) { + ret = DeviceIoControl(sock->handle, OVS_IOCTL_TRANSACT, + txn->request->data, + txn->request->size, + reply_buf, sizeof reply_buf, + &reply_len, NULL); + + if (ret && reply_len == 0) { + /* + * The current transaction did not produce any data to read and that + * is not an error as such. Continue with the remainder of the + * transactions. + */ + txn->error = 0; + if (txn->reply) { + ofpbuf_clear(txn->reply); + } + } else if (!ret) { /* XXX: Map to a more appropriate error. */ error = EINVAL; + VLOG_DBG_RL(&rl, "fatal driver failure: %s", + ovs_lasterror_to_string()); break; } - if (reply_len < sizeof *reply_nlmsg) { - nl_sock_record_errors__(transactions, n, 0); - VLOG_DBG_RL(&rl, "insufficient length of reply %#"PRIu32 - " for seq: %#"PRIx32, reply_len, request_nlmsg->nlmsg_seq); - break; - } + if (reply_len != 0) { + if (reply_len < sizeof *reply_nlmsg) { + nl_sock_record_errors__(transactions, n, 0); + VLOG_DBG_RL(&rl, "insufficient length of reply %#"PRIu32 + " for seq: %#"PRIx32, reply_len, request_nlmsg->nlmsg_seq); + break; + } - /* Validate the sequence number in the reply. */ - request_nlmsg = nl_msg_nlmsghdr(txn->request); - reply_nlmsg = (struct nlmsghdr *)reply_buf; + /* Validate the sequence number in the reply. */ + request_nlmsg = nl_msg_nlmsghdr(txn->request); + reply_nlmsg = (struct nlmsghdr *)reply_buf; - if (request_nlmsg->nlmsg_seq != reply_nlmsg->nlmsg_seq) { - ovs_assert(request_nlmsg->nlmsg_seq == reply_nlmsg->nlmsg_seq); - VLOG_DBG_RL(&rl, "mismatched seq request %#"PRIx32 - ", reply %#"PRIx32, request_nlmsg->nlmsg_seq, - reply_nlmsg->nlmsg_seq); - break; - } - - /* Handle errors embedded within the netlink message. */ - ofpbuf_use_stub(&tmp_reply, reply_buf, sizeof reply_buf); - tmp_reply.size = sizeof reply_buf; - if (nl_msg_nlmsgerr(&tmp_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)); + if (request_nlmsg->nlmsg_seq != reply_nlmsg->nlmsg_seq) { + ovs_assert(request_nlmsg->nlmsg_seq == reply_nlmsg->nlmsg_seq); + VLOG_DBG_RL(&rl, "mismatched seq request %#"PRIx32 + ", reply %#"PRIx32, request_nlmsg->nlmsg_seq, + reply_nlmsg->nlmsg_seq); + break; } - } else { - txn->error = 0; - if (txn->reply) { - /* Copy the reply to the buffer specified by the caller. */ - if (reply_len > txn->reply->allocated) { - ofpbuf_reinit(txn->reply, reply_len); + + /* Handle errors embedded within the netlink message. */ + ofpbuf_use_stub(&tmp_reply, reply_buf, sizeof reply_buf); + tmp_reply.size = sizeof reply_buf; + if (nl_msg_nlmsgerr(&tmp_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) { + /* Copy the reply to the buffer specified by the caller. */ + if (reply_len > txn->reply->allocated) { + ofpbuf_reinit(txn->reply, reply_len); + } + memcpy(txn->reply->data, reply_buf, reply_len); + txn->reply->size = reply_len; } - memcpy(txn->reply->data, reply_buf, reply_len); - txn->reply->size = reply_len; } + ofpbuf_uninit(&tmp_reply); } - ofpbuf_uninit(&tmp_reply); /* Count the number of successful transactions. */ (*done)++; @@ -945,6 +918,11 @@ nl_sock_transact_multiple(struct nl_sock *sock, } else if (error) { VLOG_ERR_RL(&rl, "transaction error (%s)", ovs_strerror(error)); nl_sock_record_errors__(transactions, n, error); + if (error != EAGAIN) { + /* A fatal error has occurred. Abort the rest of + * transactions. */ + break; + } } } } @@ -1187,10 +1165,17 @@ pend_io_request(struct nl_sock *sock) struct ovs_header *ovs_header; struct nlmsghdr *nlmsg; uint32_t seq; - int retval; + int retval = 0; int error; DWORD bytes; OVERLAPPED *overlapped = CONST_CAST(OVERLAPPED *, &sock->overlapped); + uint16_t cmd = OVS_CTRL_CMD_WIN_PEND_PACKET_REQ; + + ovs_assert(sock->read_ioctl == OVS_IOCTL_READ_PACKET || + sock->read_ioctl == OVS_IOCTL_READ_EVENT); + if (sock->read_ioctl == OVS_IOCTL_READ_EVENT) { + cmd = OVS_CTRL_CMD_WIN_PEND_REQ; + } int ovs_msg_size = sizeof (struct nlmsghdr) + sizeof (struct genlmsghdr) + sizeof (struct ovs_header); @@ -1199,7 +1184,7 @@ pend_io_request(struct nl_sock *sock) seq = nl_sock_allocate_seq(sock, 1); nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0, - OVS_CTRL_CMD_WIN_PEND_REQ, OVS_WIN_CONTROL_VERSION); + cmd, OVS_WIN_CONTROL_VERSION); nlmsg = nl_msg_nlmsghdr(&request); nlmsg->nlmsg_seq = seq; nlmsg->nlmsg_pid = sock->pid; @@ -1215,13 +1200,10 @@ pend_io_request(struct nl_sock *sock) if (error != ERROR_IO_INCOMPLETE && error != ERROR_IO_PENDING) { VLOG_ERR("nl_sock_wait failed - %s\n", ovs_format_message(error)); retval = EINVAL; - goto done; } } else { - /* The I/O was completed synchronously */ - poll_immediate_wake(); + retval = EAGAIN; } - retval = 0; done: ofpbuf_uninit(&request); @@ -1237,15 +1219,21 @@ nl_sock_wait(const struct nl_sock *sock, short int events) { #ifdef _WIN32 if (sock->overlapped.Internal != STATUS_PENDING) { - pend_io_request(CONST_CAST(struct nl_sock *, sock)); - /* XXX: poll_wevent_wait(sock->overlapped.hEvent); */ + int ret = pend_io_request(CONST_CAST(struct nl_sock *, sock)); + if (ret == 0) { + poll_wevent_wait(sock->overlapped.hEvent); + } else { + poll_immediate_wake(); + } + } else { + poll_wevent_wait(sock->overlapped.hEvent); } - poll_immediate_wake(); /* XXX: temporary. */ #else poll_fd_wait(sock->fd, events); #endif } +#ifndef _WIN32 /* Returns the underlying fd for 'sock', for use in "poll()"-like operations * that can't use nl_sock_wait(). * @@ -1256,13 +1244,9 @@ nl_sock_wait(const struct nl_sock *sock, short int events) int nl_sock_fd(const struct nl_sock *sock) { -#ifdef _WIN32 - BUILD_ASSERT_DECL(sizeof sock->handle == sizeof(int)); - return (int)sock->handle; -#else return sock->fd; -#endif } +#endif /* Returns the PID associated with this socket. */ uint32_t @@ -1803,15 +1787,12 @@ static void log_nlmsg(const char *function, int error, const void *message, size_t size, int protocol) { - struct ofpbuf buffer; - char *nlmsg; - if (!VLOG_IS_DBG_ENABLED()) { return; } - ofpbuf_use_const(&buffer, message, size); - nlmsg = nlmsg_to_string(&buffer, protocol); + struct ofpbuf buffer = ofpbuf_const_initializer(message, size); + char *nlmsg = nlmsg_to_string(&buffer, protocol); VLOG_DBG_RL(&rl, "%s (%s): %s", function, ovs_strerror(error), nlmsg); free(nlmsg); }