+ static const struct nl_policy odp_datapath_policy[] = {
+ [ODP_DP_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ },
+ [ODP_DP_ATTR_STATS] = { .type = NL_A_UNSPEC,
+ .min_len = sizeof(struct odp_stats),
+ .max_len = sizeof(struct odp_stats),
+ .optional = true },
+ [ODP_DP_ATTR_IPV4_FRAGS] = { .type = NL_A_U32, .optional = true },
+ [ODP_DP_ATTR_SAMPLING] = { .type = NL_A_U32, .optional = true },
+ [ODP_DP_ATTR_MCGROUPS] = { .type = NL_A_NESTED, .optional = true },
+ };
+
+ struct nlattr *a[ARRAY_SIZE(odp_datapath_policy)];
+ struct odp_header *odp_header;
+ struct nlmsghdr *nlmsg;
+ struct genlmsghdr *genl;
+ struct ofpbuf b;
+
+ dpif_linux_dp_init(dp);
+
+ 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_datapath_family
+ || !nl_policy_parse(&b, 0, odp_datapath_policy, a,
+ ARRAY_SIZE(odp_datapath_policy))) {
+ return EINVAL;
+ }
+
+ dp->cmd = genl->cmd;
+ dp->dp_ifindex = odp_header->dp_ifindex;
+ dp->name = nl_attr_get_string(a[ODP_DP_ATTR_NAME]);
+ if (a[ODP_DP_ATTR_STATS]) {
+ /* Can't use structure assignment because Netlink doesn't ensure
+ * sufficient alignment for 64-bit members. */
+ memcpy(&dp->stats, nl_attr_get(a[ODP_DP_ATTR_STATS]),
+ sizeof dp->stats);
+ }
+ if (a[ODP_DP_ATTR_IPV4_FRAGS]) {
+ dp->ipv4_frags = nl_attr_get_u32(a[ODP_DP_ATTR_IPV4_FRAGS]);
+ }
+ if (a[ODP_DP_ATTR_SAMPLING]) {
+ dp->sampling = nl_attr_get(a[ODP_DP_ATTR_SAMPLING]);
+ }
+
+ if (a[ODP_DP_ATTR_MCGROUPS]) {
+ static const struct nl_policy odp_mcgroup_policy[] = {
+ [ODP_PACKET_CMD_MISS] = { .type = NL_A_U32, .optional = true },
+ [ODP_PACKET_CMD_ACTION] = { .type = NL_A_U32, .optional = true },
+ [ODP_PACKET_CMD_SAMPLE] = { .type = NL_A_U32, .optional = true },
+ };
+
+ struct nlattr *mcgroups[ARRAY_SIZE(odp_mcgroup_policy)];
+
+ if (!nl_parse_nested(a[ODP_DP_ATTR_MCGROUPS], odp_mcgroup_policy,
+ mcgroups, ARRAY_SIZE(odp_mcgroup_policy))) {
+ return EINVAL;
+ }
+
+ if (mcgroups[ODP_PACKET_CMD_MISS]) {
+ dp->mcgroups[DPIF_UC_MISS]
+ = nl_attr_get_u32(mcgroups[ODP_PACKET_CMD_MISS]);
+ }
+ if (mcgroups[ODP_PACKET_CMD_ACTION]) {
+ dp->mcgroups[DPIF_UC_ACTION]
+ = nl_attr_get_u32(mcgroups[ODP_PACKET_CMD_ACTION]);
+ }
+ if (mcgroups[ODP_PACKET_CMD_SAMPLE]) {
+ dp->mcgroups[DPIF_UC_SAMPLE]
+ = nl_attr_get_u32(mcgroups[ODP_PACKET_CMD_SAMPLE]);
+ }