X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fnetlink-socket.c;h=1aa76aebfc75e104f15fe87ede3a580a17101455;hb=ff8debff85f864767ed5cd61c231f6d97d95d680;hp=a6be1861e4e239cb4b7945fc435858545300f2cd;hpb=fd972eb87a888242fb1a8ec2394fa7b3030fbd7d;p=cascardo%2Fovs.git diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c index a6be1861e..1aa76aebf 100644 --- a/lib/netlink-socket.c +++ b/lib/netlink-socket.c @@ -80,6 +80,8 @@ static int get_sock_pid_from_kernel(struct nl_sock *sock); struct nl_sock { #ifdef _WIN32 HANDLE handle; + OVERLAPPED overlapped; + DWORD read_ioctl; #else int fd; #endif @@ -139,18 +141,25 @@ nl_sock_create(int protocol, struct nl_sock **sockp) 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(); + 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_strerror(last_error)); + 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); if (sock->fd < 0) { @@ -221,6 +230,9 @@ error: } } #ifdef _WIN32 + if (sock->overlapped.hEvent) { + CloseHandle(sock->overlapped.hEvent); + } if (sock->handle != INVALID_HANDLE_VALUE) { CloseHandle(sock->handle); } @@ -248,6 +260,9 @@ nl_sock_destroy(struct nl_sock *sock) { if (sock) { #ifdef _WIN32 + if (sock->overlapped.hEvent) { + CloseHandle(sock->overlapped.hEvent); + } CloseHandle(sock->handle); #else close(sock->fd); @@ -319,6 +334,33 @@ done: } #endif /* _WIN32 */ +#ifdef _WIN32 +static int __inline +nl_sock_mcgroup(struct nl_sock *sock, unsigned int multicast_group, bool join) +{ + struct ofpbuf request; + uint64_t request_stub[128]; + struct ovs_header *ovs_header; + struct nlmsghdr *nlmsg; + int error; + + ofpbuf_use_stub(&request, request_stub, sizeof request_stub); + + nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0, + OVS_CTRL_CMD_MC_SUBSCRIBE_REQ, + OVS_WIN_CONTROL_VERSION); + + ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header); + ovs_header->dp_ifindex = 0; + + nl_msg_put_u32(&request, OVS_NL_ATTR_MCAST_GRP, multicast_group); + nl_msg_put_u8(&request, OVS_NL_ATTR_MCAST_JOIN, join ? 1 : 0); + + error = nl_sock_send(sock, &request, true); + ofpbuf_uninit(&request); + return error; +} +#endif /* Tries to add 'sock' as a listener for 'multicast_group'. Returns 0 if * successful, otherwise a positive errno value. * @@ -334,31 +376,15 @@ int nl_sock_join_mcgroup(struct nl_sock *sock, unsigned int multicast_group) { #ifdef _WIN32 -#define OVS_VPORT_MCGROUP_FALLBACK_ID 33 - struct ofpbuf msg_buf; - struct message_multicast - { - struct nlmsghdr; - /* if true, join; if else, leave */ - unsigned char join; - unsigned int groupId; - }; - - struct message_multicast msg = { 0 }; - - msg.nlmsg_len = sizeof(struct message_multicast); - msg.nlmsg_type = OVS_VPORT_MCGROUP_FALLBACK_ID; - msg.nlmsg_flags = 0; - msg.nlmsg_seq = 0; - msg.nlmsg_pid = sock->pid; - - msg.join = 1; - msg.groupId = multicast_group; - msg_buf.base_ = &msg; - msg_buf.data_ = &msg; - msg_buf.size_ = msg.nlmsg_len; - - nl_sock_send__(sock, &msg_buf, msg.nlmsg_seq, 0); + /* Set the socket type as a "multicast" socket */ + sock->read_ioctl = OVS_IOCTL_READ_EVENT; + int error = nl_sock_mcgroup(sock, multicast_group, true); + if (error) { + sock->read_ioctl = OVS_IOCTL_READ; + VLOG_WARN("could not join multicast group %u (%s)", + multicast_group, ovs_strerror(errno)); + return errno; + } #else if (setsockopt(sock->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &multicast_group, sizeof multicast_group) < 0) { @@ -384,24 +410,13 @@ int nl_sock_leave_mcgroup(struct nl_sock *sock, unsigned int multicast_group) { #ifdef _WIN32 - struct ofpbuf msg_buf; - struct message_multicast - { - struct nlmsghdr; - /* if true, join; if else, leave*/ - unsigned char join; - }; - - struct message_multicast msg = { 0 }; - nl_msg_put_nlmsghdr(&msg, sizeof(struct message_multicast), - multicast_group, 0); - msg.join = 0; - - msg_buf.base_ = &msg; - msg_buf.data_ = &msg; - msg_buf.size_ = msg.nlmsg_len; - - nl_sock_send__(sock, &msg_buf, msg.nlmsg_seq, 0); + int error = nl_sock_mcgroup(sock, multicast_group, false); + if (error) { + VLOG_WARN("could not leave multicast group %u (%s)", + multicast_group, ovs_strerror(errno)); + return errno; + } + sock->read_ioctl = OVS_IOCTL_READ; #else if (setsockopt(sock->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &multicast_group, sizeof multicast_group) < 0) { @@ -429,8 +444,8 @@ nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg, DWORD bytes; if (!DeviceIoControl(sock->handle, OVS_IOCTL_WRITE, - ofpbuf_data(msg), ofpbuf_size(msg), NULL, 0, - &bytes, NULL)) { + ofpbuf_data(msg), ofpbuf_size(msg), NULL, 0, + &bytes, NULL)) { retval = -1; /* XXX: Map to a more appropriate error based on GetLastError(). */ errno = EINVAL; @@ -521,7 +536,7 @@ nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait) nlmsghdr->nlmsg_len = UINT32_MAX; #ifdef _WIN32 DWORD bytes; - if (!DeviceIoControl(sock->handle, OVS_IOCTL_READ, + if (!DeviceIoControl(sock->handle, sock->read_ioctl, NULL, 0, tail, sizeof tail, &bytes, NULL)) { retval = -1; errno = EINVAL; @@ -650,34 +665,19 @@ nl_sock_transact_multiple__(struct nl_sock *sock, iovs[i].iov_len = ofpbuf_size(txn->request); } +#ifndef _WIN32 memset(&msg, 0, sizeof msg); msg.msg_iov = iovs; msg.msg_iovlen = n; do { -#ifdef _WIN32 - DWORD last_error = 0; - bool result = FALSE; - for (i = 0; i < n; i++) { - result = WriteFile((HANDLE)sock->handle, iovs[i].iov_base, iovs[i].iov_len, - &error, NULL); - last_error = GetLastError(); - if (last_error != ERROR_SUCCESS && !result) { - error = EAGAIN; - errno = EAGAIN; - } else { - error = 0; - } - } -#else error = sendmsg(sock->fd, &msg, 0) < 0 ? errno : 0; -#endif } while (error == EINTR); for (i = 0; i < n; i++) { struct nl_transaction *txn = transactions[i]; - log_nlmsg(__func__, error, ofpbuf_data(txn->request), ofpbuf_size(txn->request), - sock->protocol); + log_nlmsg(__func__, error, ofpbuf_data(txn->request), + ofpbuf_size(txn->request), sock->protocol); } if (!error) { COVERAGE_ADD(netlink_sent, n); @@ -756,6 +756,82 @@ nl_sock_transact_multiple__(struct nl_sock *sock, base_seq += i + 1; } ofpbuf_uninit(&tmp_reply); +#else + error = 0; + for (i = 0; i < n; i++) { + DWORD reply_len; + uint8_t tail[65536]; + struct nl_transaction *txn = transactions[i]; + struct nlmsghdr *request_nlmsg, *reply_nlmsg; + + if (!DeviceIoControl(sock->handle, OVS_IOCTL_TRANSACT, + ofpbuf_data(txn->request), + ofpbuf_size(txn->request), + txn->reply ? tail : 0, + txn->reply ? sizeof tail : 0, + &reply_len, NULL)) { + /* XXX: Map to a more appropriate error. */ + error = EINVAL; + break; + } + + if (txn->reply) { + if (reply_len < sizeof *reply_nlmsg) { + VLOG_DBG_RL(&rl, "insufficient length of reply %#"PRIu32, + reply_len); + break; + } + + /* Validate the sequence number in the reply. */ + request_nlmsg = nl_msg_nlmsghdr(txn->request); + reply_nlmsg = (struct nlmsghdr *)tail; + + 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; + } + + /* If reply was expected, verify if there was indeed a reply + * received. */ + if (reply_len == 0) { + nl_sock_record_errors__(transactions, n, 0); + VLOG_DBG_RL(&rl, "reply not seen when expected seq %#"PRIx32, + request_nlmsg->nlmsg_seq); + break; + } + + /* Copy the reply to the buffer specified by the caller. */ + if (reply_len > txn->reply->allocated) { + ofpbuf_reinit(txn->reply, reply_len); + } + memcpy(ofpbuf_data(txn->reply), tail, reply_len); + ofpbuf_set_size(txn->reply, reply_len); + + /* Handle errors embedded within the netlink message. */ + if (nl_msg_nlmsgerr(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; + } + } + + /* Count the number of successful transactions. */ + (*done)++; + } + + if (!error) { + COVERAGE_ADD(netlink_sent, n); + } +#endif return error; } @@ -1040,12 +1116,69 @@ nl_dump_done(struct nl_dump *dump) return status == EOF ? 0 : status; } +#ifdef _WIN32 +/* Pend an I/O request in the driver. The driver completes the I/O whenever + * an event or a packet is ready to be read. Once the I/O is completed + * the overlapped structure event associated with the pending I/O will be set + */ +static int +pend_io_request(const struct nl_sock *sock) +{ + struct ofpbuf request; + uint64_t request_stub[128]; + struct ovs_header *ovs_header; + struct nlmsghdr *nlmsg; + uint32_t seq; + int retval; + int error; + DWORD bytes; + OVERLAPPED *overlapped = CONST_CAST(OVERLAPPED *, &sock->overlapped); + + int ovs_msg_size = sizeof (struct nlmsghdr) + sizeof (struct genlmsghdr) + + sizeof (struct ovs_header); + + ofpbuf_use_stub(&request, request_stub, sizeof request_stub); + + 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); + nlmsg = nl_msg_nlmsghdr(&request); + nlmsg->nlmsg_seq = seq; + + ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header); + ovs_header->dp_ifindex = 0; + + if (!DeviceIoControl(sock->handle, OVS_IOCTL_WRITE, + ofpbuf_data(&request), ofpbuf_size(&request), + NULL, 0, &bytes, overlapped)) { + error = GetLastError(); + /* Check if the I/O got pended */ + 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 = 0; + +done: + ofpbuf_uninit(&request); + return retval; +} +#endif /* _WIN32 */ + /* Causes poll_block() to wake up when any of the specified 'events' (which is * a OR'd combination of POLLIN, POLLOUT, etc.) occur on 'sock'. */ void nl_sock_wait(const struct nl_sock *sock, short int events) { #ifdef _WIN32 + if (sock->overlapped.Internal != STATUS_PENDING) { + pend_io_request(sock); + } poll_fd_wait(sock->handle, events); #else poll_fd_wait(sock->fd, events); @@ -1177,7 +1310,6 @@ static int do_lookup_genl_family(const char *name, struct nlattr **attrs, struct ofpbuf **replyp) { - struct nl_sock *sock; struct nlmsghdr *nlmsg; struct ofpbuf *reply; int error; @@ -1219,6 +1351,11 @@ do_lookup_genl_family(const char *name, struct nlattr **attrs, family_name = OVS_FLOW_FAMILY; family_version = OVS_FLOW_VERSION; family_attrmax = OVS_FLOW_ATTR_MAX; + } else if (!strcmp(name, OVS_WIN_NETDEV_FAMILY)) { + family_id = OVS_WIN_NL_NETDEV_FAMILY_ID; + family_name = OVS_WIN_NETDEV_FAMILY; + family_version = OVS_WIN_NETDEV_VERSION; + family_attrmax = OVS_WIN_NETDEV_ATTR_MAX; } else { ofpbuf_delete(reply); return EINVAL; @@ -1251,7 +1388,6 @@ do_lookup_genl_family(const char *name, struct nlattr **attrs, if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, family_policy, attrs, ARRAY_SIZE(family_policy)) || nl_attr_get_u16(attrs[CTRL_ATTR_FAMILY_ID]) == 0) { - nl_sock_destroy(sock); ofpbuf_delete(reply); return EPROTO; }