netlink: Improve support for nested Netlink attributes.
authorBen Pfaff <blp@nicira.com>
Fri, 28 May 2010 23:16:23 +0000 (16:16 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 17 Jun 2010 17:30:19 +0000 (10:30 -0700)
Fairly often it happens that nested Netlink attributes must themselves
contain Netlink attributes.  In such a case, nlmsg_put_nested() is not so
convenient, because it requires the contents to be pre-assembled and then
copied into place.  This commit introduces a new interface that instead
allows the nested attributes to be assembled in-place.  As a demonstration,
it updates nl_msg_put_nested() to use this new interface.

lib/netlink.c
lib/netlink.h

index ce7b66774f742c95c6a1778874899315d67b4fc8..d59f65e04371c52d53eb4d42dbe844e2b98c931b 100644 (file)
@@ -813,15 +813,37 @@ nl_msg_put_string(struct ofpbuf *msg, uint16_t type, const char *value)
     nl_msg_put_unspec(msg, type, value, strlen(value) + 1);
 }
 
-/* Appends a Netlink attribute of the given 'type' and the given buffered
- * netlink message in 'nested_msg' to 'msg'.  The nlmsg_len field in
- * 'nested_msg' is finalized to match 'nested_msg->size'. */
+/* Adds the header for nested Netlink attributes to 'msg', with the specified
+ * 'type', and returns the header's offset within 'msg'.  The caller should add
+ * the content for the nested Netlink attribute to 'msg' (e.g. using the other
+ * nl_msg_*() functions), and then pass the returned offset to
+ * nl_msg_end_nested() to finish up the nested attributes. */
+size_t
+nl_msg_start_nested(struct ofpbuf *msg, uint16_t type)
+{
+    size_t offset = msg->size;
+    nl_msg_put_unspec(msg, type, NULL, 0);
+    return offset;
+}
+
+/* Finalizes a nested Netlink attribute in 'msg'.  'offset' should be the value
+ * returned by nl_msg_start_nested(). */
+void
+nl_msg_end_nested(struct ofpbuf *msg, size_t offset)
+{
+    struct nlattr *attr = ofpbuf_at_assert(msg, offset, sizeof *attr);
+    attr->nla_len = msg->size - offset;
+}
+
+/* Appends a nested Netlink attribute of the given 'type', with the 'size'
+ * bytes of content starting at 'data', to 'msg'. */
 void
 nl_msg_put_nested(struct ofpbuf *msg,
-                  uint16_t type, struct ofpbuf *nested_msg)
+                  uint16_t type, const void *data, size_t size)
 {
-    nl_msg_nlmsghdr(nested_msg)->nlmsg_len = nested_msg->size;
-    nl_msg_put_unspec(msg, type, nested_msg->data, nested_msg->size);
+    size_t offset = nl_msg_start_nested(msg, type);
+    nl_msg_put(msg, data, size);
+    nl_msg_end_nested(msg, offset);
 }
 
 /* If 'buffer' begins with a valid "struct nlmsghdr", pulls the header and its
index 13f1459834eb5462aec7adafb80e90286ccc723d..9cb1f81038b9049e77e41eb4610ec732a38aabbd 100644 (file)
@@ -52,10 +52,10 @@ void nl_sock_wait(const struct nl_sock *, short int events);
 
 /* Table dumping. */
 struct nl_dump {
-    uint32_t seq;
-    struct nl_sock *sock;
-    int status;
-    struct ofpbuf *buffer;
+    struct nl_sock *sock;       /* Socket being dumped. */
+    uint32_t seq;               /* Expected nlmsg_seq for replies. */
+    struct ofpbuf *buffer;      /* Receive buffer currently being iterated. */
+    int status;                 /* 0=OK, EOF=done, or positive errno value. */
 };
 
 void nl_dump_start(struct nl_dump *, struct nl_sock *,
@@ -89,7 +89,11 @@ void nl_msg_put_u16(struct ofpbuf *, uint16_t type, uint16_t value);
 void nl_msg_put_u32(struct ofpbuf *, uint16_t type, uint32_t value);
 void nl_msg_put_u64(struct ofpbuf *, uint16_t type, uint64_t value);
 void nl_msg_put_string(struct ofpbuf *, uint16_t type, const char *value);
-void nl_msg_put_nested(struct ofpbuf *, uint16_t type, struct ofpbuf *);
+
+size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type);
+void nl_msg_end_nested(struct ofpbuf *, size_t offset);
+void nl_msg_put_nested(struct ofpbuf *, uint16_t type,
+                       const void *data, size_t size);
 
 /* Separating buffers into individual messages. */
 struct nlmsghdr *nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg);