+/* Send each packet in the 'skb' list to userspace for 'dp' as directed by
+ * 'upcall_info'. There will be only one packet unless we broke up a GSO
+ * packet.
+ */
+static int queue_control_packets(struct datapath *dp, struct sk_buff *skb,
+ const struct dp_upcall_info *upcall_info)
+{
+ u32 group = packet_mc_group(dp, upcall_info->cmd);
+ struct sk_buff *nskb;
+ int port_no;
+ int err;
+
+ if (OVS_CB(skb)->vport)
+ port_no = OVS_CB(skb)->vport->port_no;
+ else
+ port_no = ODPP_LOCAL;
+
+ do {
+ struct odp_header *upcall;
+ struct sk_buff *user_skb; /* to be queued to userspace */
+ struct nlattr *nla;
+ unsigned int len;
+
+ nskb = skb->next;
+ skb->next = NULL;
+
+ err = vlan_deaccel_tag(skb);
+ if (unlikely(err))
+ goto err_kfree_skbs;
+
+ if (nla_attr_size(skb->len) > USHRT_MAX)
+ goto err_kfree_skbs;
+
+ len = sizeof(struct odp_header);
+ len += nla_total_size(skb->len);
+ len += nla_total_size(FLOW_BUFSIZE);
+ if (upcall_info->userdata)
+ len += nla_total_size(8);
+ if (upcall_info->sample_pool)
+ len += nla_total_size(4);
+ if (upcall_info->actions_len)
+ len += nla_total_size(upcall_info->actions_len);
+
+ user_skb = genlmsg_new(len, GFP_ATOMIC);
+ if (!user_skb) {
+ netlink_set_err(INIT_NET_GENL_SOCK, 0, group, -ENOBUFS);
+ goto err_kfree_skbs;
+ }
+
+ upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family, 0, upcall_info->cmd);
+ upcall->dp_ifindex = dp->dp_ifindex;
+
+ nla = nla_nest_start(user_skb, ODP_PACKET_ATTR_KEY);
+ flow_to_nlattrs(upcall_info->key, user_skb);
+ nla_nest_end(user_skb, nla);
+
+ if (upcall_info->userdata)
+ nla_put_u64(user_skb, ODP_PACKET_ATTR_USERDATA, upcall_info->userdata);
+ if (upcall_info->sample_pool)
+ nla_put_u32(user_skb, ODP_PACKET_ATTR_SAMPLE_POOL, upcall_info->sample_pool);
+ if (upcall_info->actions_len) {
+ const struct nlattr *actions = upcall_info->actions;
+ u32 actions_len = upcall_info->actions_len;
+
+ nla = nla_nest_start(user_skb, ODP_PACKET_ATTR_ACTIONS);
+ memcpy(__skb_put(user_skb, actions_len), actions, actions_len);
+ nla_nest_end(user_skb, nla);
+ }
+
+ nla = __nla_reserve(user_skb, ODP_PACKET_ATTR_PACKET, skb->len);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ copy_and_csum_skb(skb, nla_data(nla));
+ else
+ skb_copy_bits(skb, 0, nla_data(nla), skb->len);
+
+ err = genlmsg_multicast(user_skb, 0, group, GFP_ATOMIC);
+ if (err)
+ goto err_kfree_skbs;
+
+ kfree_skb(skb);
+ skb = nskb;
+ } while (skb);
+ return 0;
+
+err_kfree_skbs:
+ kfree_skb(skb);
+ while ((skb = nskb) != NULL) {
+ nskb = skb->next;
+ kfree_skb(skb);
+ }
+ return err;
+}
+
+/* Called with genl_mutex. */
+static int flush_flows(int dp_ifindex)