+nl_sock_join_mcgroup(struct nl_sock *sock, unsigned int multicast_group)
+{
+ int error = nl_sock_cow__(sock);
+ if (error) {
+ return error;
+ }
+ 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, strerror(errno));
+ return errno;
+ }
+ sock->any_groups = true;
+ return 0;
+}
+
+/* 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)
+{
+ assert(!sock->dump);
+ 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, strerror(errno));
+ return errno;
+ }
+ return 0;
+}
+
+static int
+nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg, bool wait)