/* 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;
}
Beispiel #2
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;
}
Beispiel #6
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);
}