* information. Also, at high logging levels we log *all* Netlink messages. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 600);
+static uint32_t nl_sock_allocate_seq(struct nl_sock *, unsigned int n);
static void log_nlmsg(const char *function, int error,
const void *message, size_t size, int protocol);
\f
struct nl_sock
{
int fd;
+ uint32_t next_seq;
uint32_t pid;
int protocol;
struct nl_dump *dump;
}
sock->protocol = protocol;
sock->dump = NULL;
+ sock->next_seq = 1;
rcvbuf = 1024 * 1024;
if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE,
int error;
nlmsg->nlmsg_len = msg->size;
+ nlmsg->nlmsg_seq = nl_sock_allocate_seq(sock, 1);
nlmsg->nlmsg_pid = sock->pid;
do {
int retval;
*
* Before sending each message, this function will finalize nlmsg_len in each
* 'request' to match the ofpbuf's size, and set nlmsg_pid to 'sock''s pid.
- * NLM_F_ACK will be added to some requests' nlmsg_flags.
*
* Bare Netlink is an unreliable transport protocol. This function layers
* reliable delivery and reply semantics on top of bare Netlink. See
* on failure '*replyp' is set to NULL. If 'replyp' is null, then the kernel's
* reply, if any, is discarded.
*
- * 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_ACK will be set
- * in nlmsg_flags.
+ * Before the message is sent, nlmsg_len in 'request' will be finalized to
+ * match msg->size, nlmsg_pid will be set to 'sock''s pid, and nlmsg_seq will
+ * be initialized, NLM_F_ACK will be set in nlmsg_flags.
*
* The caller is responsible for destroying 'request'.
*
nl_dump_start(struct nl_dump *dump,
struct nl_sock *sock, const struct ofpbuf *request)
{
- struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(request);
- nlmsghdr->nlmsg_flags |= NLM_F_DUMP | NLM_F_ACK;
- dump->seq = nlmsghdr->nlmsg_seq;
dump->buffer = NULL;
if (sock->dump) {
/* 'sock' already has an ongoing dump. Clone the socket because
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, true);
+ dump->seq = nl_msg_nlmsghdr(request)->nlmsg_seq;
}
/* Helper function for nl_dump_next(). */
return *number > 0 ? 0 : -*number;
}
\f
+static uint32_t
+nl_sock_allocate_seq(struct nl_sock *sock, unsigned int n)
+{
+ uint32_t seq = sock->next_seq;
+
+ sock->next_seq += n;
+
+ /* Make it impossible for the next request for sequence numbers to wrap
+ * around to 0. Start over with 1 to avoid ever using a sequence number of
+ * 0, because the kernel uses sequence number 0 for notifications. */
+ if (sock->next_seq >= UINT32_MAX / 2) {
+ sock->next_seq = 1;
+ }
+
+ return seq;
+}
+
static void
nlmsghdr_to_string(const struct nlmsghdr *h, int protocol, struct ds *ds)
{
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
ofpbuf_prealloc_tailroom(msg, NLMSG_ALIGN(size));
}
-static uint32_t
-get_nlmsg_seq(void)
-{
- /* Next nlmsghdr sequence number.
- *
- * This implementation uses sequence numbers that are unique process-wide,
- * to avoid a hypothetical race: send request, close socket, open new
- * socket that reuses the old socket's PID value, send request on new
- * socket, receive reply from kernel to old socket but with same PID and
- * sequence number. (This race could be avoided other ways, e.g. by
- * preventing PIDs from being quickly reused). */
- static uint32_t next_seq;
-
- if (next_seq == 0) {
- /* Pick initial sequence number. */
- next_seq = getpid() ^ time_wall();
- }
- return next_seq++;
-}
-
/* Puts a nlmsghdr at the beginning of 'msg', which must be initially empty.
* Uses the given 'type' and 'flags'. 'expected_payload' should be
* an estimate of the number of payload bytes to be supplied; if the size of
* is often NLM_F_REQUEST indicating that a request is being made, commonly
* or'd with NLM_F_ACK to request an acknowledgement.
*
- * Sets the new nlmsghdr's nlmsg_pid field to 0 for now. nl_sock_send() will
- * fill it in just before sending the message.
+ * Sets the new nlmsghdr's nlmsg_len, nlmsg_seq, and nlmsg_pid fields to 0 for
+ * now. Functions that send Netlink messages will fill these in just before
+ * sending the message.
*
* nl_msg_put_genlmsghdr() is more convenient for composing a Generic Netlink
* message. */
nlmsghdr->nlmsg_len = 0;
nlmsghdr->nlmsg_type = type;
nlmsghdr->nlmsg_flags = flags;
- nlmsghdr->nlmsg_seq = get_nlmsg_seq();
+ nlmsghdr->nlmsg_seq = 0;
nlmsghdr->nlmsg_pid = 0;
}