+dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport *vport,
+ const struct ofpbuf *buf)
+{
+ static const struct nl_policy odp_vport_policy[] = {
+ [ODP_VPORT_ATTR_PORT_NO] = { .type = NL_A_U32 },
+ [ODP_VPORT_ATTR_TYPE] = { .type = NL_A_U32 },
+ [ODP_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
+ [ODP_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC,
+ .min_len = sizeof(struct rtnl_link_stats64),
+ .max_len = sizeof(struct rtnl_link_stats64),
+ .optional = true },
+ [ODP_VPORT_ATTR_ADDRESS] = { .type = NL_A_UNSPEC,
+ .min_len = ETH_ADDR_LEN,
+ .max_len = ETH_ADDR_LEN,
+ .optional = true },
+ [ODP_VPORT_ATTR_MTU] = { .type = NL_A_U32, .optional = true },
+ [ODP_VPORT_ATTR_OPTIONS] = { .type = NL_A_NESTED, .optional = true },
+ [ODP_VPORT_ATTR_IFINDEX] = { .type = NL_A_U32, .optional = true },
+ [ODP_VPORT_ATTR_IFLINK] = { .type = NL_A_U32, .optional = true },
+ };
+
+ struct nlattr *a[ARRAY_SIZE(odp_vport_policy)];
+ struct odp_header *odp_header;
+ struct nlmsghdr *nlmsg;
+ struct genlmsghdr *genl;
+ struct ofpbuf b;
+
+ dpif_linux_vport_init(vport);
+
+ ofpbuf_use_const(&b, buf->data, buf->size);
+ nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
+ genl = ofpbuf_try_pull(&b, sizeof *genl);
+ odp_header = ofpbuf_try_pull(&b, sizeof *odp_header);
+ if (!nlmsg || !genl || !odp_header
+ || nlmsg->nlmsg_type != odp_vport_family
+ || !nl_policy_parse(&b, 0, odp_vport_policy, a,
+ ARRAY_SIZE(odp_vport_policy))) {
+ return EINVAL;
+ }
+
+ vport->cmd = genl->cmd;
+ vport->dp_ifindex = odp_header->dp_ifindex;
+ vport->port_no = nl_attr_get_u32(a[ODP_VPORT_ATTR_PORT_NO]);
+ vport->type = nl_attr_get_u32(a[ODP_VPORT_ATTR_TYPE]);
+ vport->name = nl_attr_get_string(a[ODP_VPORT_ATTR_NAME]);
+ if (a[ODP_VPORT_ATTR_STATS]) {
+ vport->stats = nl_attr_get(a[ODP_VPORT_ATTR_STATS]);
+ }
+ if (a[ODP_VPORT_ATTR_ADDRESS]) {
+ vport->address = nl_attr_get(a[ODP_VPORT_ATTR_ADDRESS]);
+ }
+ if (a[ODP_VPORT_ATTR_MTU]) {
+ vport->mtu = nl_attr_get_u32(a[ODP_VPORT_ATTR_MTU]);
+ } else {
+ vport->mtu = INT_MAX;
+ }
+ if (a[ODP_VPORT_ATTR_OPTIONS]) {
+ vport->options = nl_attr_get(a[ODP_VPORT_ATTR_OPTIONS]);
+ vport->options_len = nl_attr_get_size(a[ODP_VPORT_ATTR_OPTIONS]);
+ }
+ if (a[ODP_VPORT_ATTR_IFINDEX]) {
+ vport->ifindex = nl_attr_get_u32(a[ODP_VPORT_ATTR_IFINDEX]);
+ }
+ if (a[ODP_VPORT_ATTR_IFLINK]) {
+ vport->iflink = nl_attr_get_u32(a[ODP_VPORT_ATTR_IFLINK]);
+ }
+ return 0;
+}
+
+/* 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)