/* Tries to make 'sock' stop listening to 'multicast_group'. Returns 0 if * successful, otherwise a positive errno value. * * Multicast group numbers are always positive. * * It is not an error to attempt to leave a multicast group to which a socket * does not belong. * * On success, reading from 'sock' will still return any messages that were * received on 'multicast_group' before the group was left. */ 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); #else if (setsockopt(sock->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &multicast_group, sizeof multicast_group) < 0) { VLOG_WARN("could not leave multicast group %u (%s)", multicast_group, ovs_strerror(errno)); return errno; } #endif return 0; }
/* Tries to send 'msg', which must contain a Netlink message, to the kernel on * 'sock'. nlmsg_len in 'msg' will be finalized to match msg->size, nlmsg_pid * will be set to 'sock''s pid, and nlmsg_seq will be initialized to * 'nlmsg_seq', before the message is sent. * * Returns 0 if successful, otherwise a positive errno value. If * 'wait' is true, then the send will wait until buffer space is ready; * otherwise, returns EAGAIN if the 'sock' send buffer is full. * * This function is suitable for sending a reply to a request that was received * with sequence number 'nlmsg_seq'. Otherwise, use nl_sock_send() instead. */ int nl_sock_send_seq(struct nl_sock *sock, const struct ofpbuf *msg, uint32_t nlmsg_seq, bool wait) { int error = nl_sock_cow__(sock); if (error) { return error; } return nl_sock_send__(sock, msg, nlmsg_seq, wait); }
/* Starts a Netlink "dump" operation, by sending 'request' to the kernel on a * Netlink socket created with the given 'protocol', and initializes 'dump' to * reflect the state of the operation. * * nlmsg_len in 'msg' will be finalized to match msg->size, and nlmsg_pid will * be set to the Netlink socket's pid, before the message is sent. NLM_F_DUMP * and NLM_F_ACK will be set in nlmsg_flags. * * The design of this Netlink socket library ensures that the dump is reliable. * * This function provides no status indication. An error status for the entire * dump operation is provided when it is completed by calling nl_dump_done(). * * The caller is responsible for destroying 'request'. */ void nl_dump_start(struct nl_dump *dump, int protocol, const struct ofpbuf *request) { ofpbuf_init(&dump->buffer, 4096); dump->status = nl_pool_alloc(protocol, &dump->sock); if (dump->status) { return; } nl_msg_nlmsghdr(request)->nlmsg_flags |= NLM_F_DUMP | NLM_F_ACK; dump->status = nl_sock_send__(dump->sock, request, nl_sock_allocate_seq(dump->sock, 1), true); dump->seq = nl_msg_nlmsghdr(request)->nlmsg_seq; }
/* Starts a Netlink "dump" operation, by sending 'request' to the kernel on a * Netlink socket created with the given 'protocol', and initializes 'dump' to * reflect the state of the operation. * * 'request' must contain a Netlink message. Before sending the message, * nlmsg_len will be finalized to match request->size, and nlmsg_pid will be * set to the Netlink socket's pid. NLM_F_DUMP and NLM_F_ACK will be set in * nlmsg_flags. * * The design of this Netlink socket library ensures that the dump is reliable. * * This function provides no status indication. nl_dump_done() provides an * error status for the entire dump operation. * * The caller must eventually destroy 'request'. */ void nl_dump_start(struct nl_dump *dump, int protocol, const struct ofpbuf *request) { nl_msg_nlmsghdr(request)->nlmsg_flags |= NLM_F_DUMP | NLM_F_ACK; ovs_mutex_init(&dump->mutex); ovs_mutex_lock(&dump->mutex); dump->status = nl_pool_alloc(protocol, &dump->sock); if (!dump->status) { dump->status = nl_sock_send__(dump->sock, request, nl_sock_allocate_seq(dump->sock, 1), true); } dump->nl_seq = nl_msg_nlmsghdr(request)->nlmsg_seq; ovs_mutex_unlock(&dump->mutex); }
/* Tries to add 'sock' as a listener for 'multicast_group'. Returns 0 if * successful, otherwise a positive errno value. * * A socket that is subscribed to a multicast group that receives asynchronous * notifications must not be used for Netlink transactions or dumps, because * transactions and dumps can cause notifications to be lost. * * Multicast group numbers are always positive. * * It is not an error to attempt to join a multicast group to which a socket * already belongs. */ 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); #else if (setsockopt(sock->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &multicast_group, sizeof multicast_group) < 0) { VLOG_WARN("could not join multicast group %u (%s)", multicast_group, ovs_strerror(errno)); return errno; } #endif return 0; }
/* Starts a Netlink "dump" operation, by sending 'request' to the kernel via * 'sock', and initializes 'dump' to reflect the state of the operation. * * nlmsg_len in 'msg' will be finalized to match msg->size, and nlmsg_pid will * be set to 'sock''s pid, before the message is sent. NLM_F_DUMP and * NLM_F_ACK will be set in nlmsg_flags. * * This Netlink socket library is designed to ensure that the dump is reliable * and that it will not interfere with other operations on 'sock', including * destroying or sending and receiving messages on 'sock'. One corner case is * not handled: * * - If 'sock' has been used to send a request (e.g. with nl_sock_send()) * whose response has not yet been received (e.g. with nl_sock_recv()). * This is unusual: usually nl_sock_transact() is used to send a message * and receive its reply all in one go. * * This function provides no status indication. An error status for the entire * dump operation is provided when it is completed by calling nl_dump_done(). * * The caller is responsible for destroying 'request'. * * The new 'dump' is independent of 'sock'. 'sock' and 'dump' may be destroyed * in either order. */ void nl_dump_start(struct nl_dump *dump, struct nl_sock *sock, const struct ofpbuf *request) { ofpbuf_init(&dump->buffer, 4096); if (sock->dump) { /* 'sock' already has an ongoing dump. Clone the socket because * Netlink only allows one dump at a time. */ dump->status = nl_sock_clone(sock, &dump->sock); if (dump->status) { return; } } else { sock->dump = dump; dump->sock = sock; dump->status = 0; } nl_msg_nlmsghdr(request)->nlmsg_flags |= NLM_F_DUMP | NLM_F_ACK; dump->status = nl_sock_send__(sock, request, nl_sock_allocate_seq(sock, 1), true); dump->seq = nl_msg_nlmsghdr(request)->nlmsg_seq; }
/* Tries to send 'msg', which must contain a Netlink message, to the kernel on * 'sock'. nlmsg_len in 'msg' will be finalized to match msg->size, nlmsg_pid * will be set to 'sock''s pid, and nlmsg_seq will be initialized to * 'nlmsg_seq', before the message is sent. * * Returns 0 if successful, otherwise a positive errno value. If * 'wait' is true, then the send will wait until buffer space is ready; * otherwise, returns EAGAIN if the 'sock' send buffer is full. * * This function is suitable for sending a reply to a request that was received * with sequence number 'nlmsg_seq'. Otherwise, use nl_sock_send() instead. */ int nl_sock_send_seq(struct nl_sock *sock, const struct ofpbuf *msg, uint32_t nlmsg_seq, bool wait) { return nl_sock_send__(sock, msg, nlmsg_seq, wait); }