From: Ben Pfaff Date: Fri, 28 May 2010 23:16:23 +0000 (-0700) Subject: netlink: Improve support for nested Netlink attributes. X-Git-Tag: v1.1.0pre1~266 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;ds=sidebyside;h=38a997566d7faa1e8c4b9c029faed6789e7528ff;p=sliver-openvswitch.git netlink: Improve support for nested Netlink attributes. 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. --- diff --git a/lib/netlink.c b/lib/netlink.c index ce7b66774..d59f65e04 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -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 diff --git a/lib/netlink.h b/lib/netlink.h index 13f145983..9cb1f8103 100644 --- a/lib/netlink.h +++ b/lib/netlink.h @@ -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);