+}
+
+/* Appends to 'buf' (which must initially be empty) a "struct odp_header"
+ * followed by Netlink attributes corresponding to 'vport'. */
+static void
+dpif_linux_vport_to_ofpbuf(const struct dpif_linux_vport *vport,
+ struct ofpbuf *buf)
+{
+ struct odp_header *odp_header;
+
+ nl_msg_put_genlmsghdr(buf, 0, odp_vport_family, NLM_F_REQUEST | NLM_F_ECHO,
+ vport->cmd, 1);
+
+ odp_header = ofpbuf_put_uninit(buf, sizeof *odp_header);
+ odp_header->dp_ifindex = vport->dp_ifindex;
+
+ if (vport->port_no != UINT32_MAX) {
+ nl_msg_put_u32(buf, ODP_VPORT_ATTR_PORT_NO, vport->port_no);
+ }
+
+ if (vport->type != ODP_VPORT_TYPE_UNSPEC) {
+ nl_msg_put_u32(buf, ODP_VPORT_ATTR_TYPE, vport->type);
+ }
+
+ if (vport->name) {
+ nl_msg_put_string(buf, ODP_VPORT_ATTR_NAME, vport->name);
+ }
+
+ if (vport->stats) {
+ nl_msg_put_unspec(buf, ODP_VPORT_ATTR_STATS,
+ vport->stats, sizeof *vport->stats);
+ }
+
+ if (vport->address) {
+ nl_msg_put_unspec(buf, ODP_VPORT_ATTR_ADDRESS,
+ vport->address, ETH_ADDR_LEN);
+ }
+
+ if (vport->mtu && vport->mtu != INT_MAX) {
+ nl_msg_put_u32(buf, ODP_VPORT_ATTR_MTU, vport->mtu);
+ }
+
+ if (vport->options) {
+ nl_msg_put_nested(buf, ODP_VPORT_ATTR_OPTIONS,
+ vport->options, vport->options_len);
+ }
+
+ if (vport->ifindex) {
+ nl_msg_put_u32(buf, ODP_VPORT_ATTR_IFINDEX, vport->ifindex);
+ }
+
+ if (vport->iflink) {
+ nl_msg_put_u32(buf, ODP_VPORT_ATTR_IFLINK, vport->iflink);
+ }
+}
+
+/* Clears 'vport' to "empty" values. */
+void
+dpif_linux_vport_init(struct dpif_linux_vport *vport)
+{
+ memset(vport, 0, sizeof *vport);
+ vport->port_no = UINT32_MAX;
+}
+
+/* Executes 'request' in the kernel datapath. If the command fails, returns a
+ * positive errno value. Otherwise, if 'reply' and 'bufp' are null, returns 0
+ * without doing anything else. If 'reply' and 'bufp' are nonnull, then the
+ * result of the command is expected to be an odp_vport also, which is decoded
+ * and stored in '*reply' and '*bufp'. The caller must free '*bufp' when the
+ * reply is no longer needed ('reply' will contain pointers into '*bufp'). */
+int
+dpif_linux_vport_transact(const struct dpif_linux_vport *request,
+ struct dpif_linux_vport *reply,
+ struct ofpbuf **bufp)
+{
+ struct ofpbuf *request_buf;
+ int error;
+
+ assert((reply != NULL) == (bufp != NULL));
+
+ request_buf = ofpbuf_new(1024);
+ dpif_linux_vport_to_ofpbuf(request, request_buf);
+ error = nl_sock_transact(genl_sock, request_buf, bufp);
+ ofpbuf_delete(request_buf);