+static struct udpif_key *
+ukey_create_from_upcall(struct upcall *upcall, struct flow_wildcards *wc)
+{
+ struct odputil_keybuf keystub, maskstub;
+ struct ofpbuf keybuf, maskbuf;
+ bool megaflow;
+ struct odp_flow_key_parms odp_parms = {
+ .flow = upcall->flow,
+ .mask = &wc->masks,
+ };
+
+ odp_parms.support = ofproto_dpif_get_support(upcall->ofproto)->odp;
+ if (upcall->key_len) {
+ ofpbuf_use_const(&keybuf, upcall->key, upcall->key_len);
+ } else {
+ /* dpif-netdev doesn't provide a netlink-formatted flow key in the
+ * upcall, so convert the upcall's flow here. */
+ ofpbuf_use_stack(&keybuf, &keystub, sizeof keystub);
+ odp_parms.odp_in_port = upcall->flow->in_port.odp_port;
+ odp_flow_key_from_flow(&odp_parms, &keybuf);
+ }
+
+ atomic_read_relaxed(&enable_megaflows, &megaflow);
+ ofpbuf_use_stack(&maskbuf, &maskstub, sizeof maskstub);
+ if (megaflow) {
+ odp_parms.odp_in_port = ODPP_NONE;
+ odp_parms.key_buf = &keybuf;
+
+ odp_flow_key_from_mask(&odp_parms, &maskbuf);
+ }
+
+ return ukey_create__(keybuf.data, keybuf.size, maskbuf.data, maskbuf.size,
+ true, upcall->ufid, upcall->pmd_id,
+ &upcall->put_actions, upcall->dump_seq,
+ upcall->reval_seq, 0,
+ upcall->have_recirc_ref ? upcall->recirc->id : 0,
+ &upcall->xout);
+}
+
+static int
+ukey_create_from_dpif_flow(const struct udpif *udpif,
+ const struct dpif_flow *flow,
+ struct udpif_key **ukey)
+{
+ struct dpif_flow full_flow;
+ struct ofpbuf actions;
+ uint64_t dump_seq, reval_seq;
+ uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
+ const struct nlattr *a;
+ unsigned int left;
+
+ if (!flow->key_len || !flow->actions_len) {
+ struct ofpbuf buf;
+ int err;
+
+ /* If the key or actions were not provided by the datapath, fetch the
+ * full flow. */
+ ofpbuf_use_stack(&buf, &stub, sizeof stub);
+ err = dpif_flow_get(udpif->dpif, NULL, 0, &flow->ufid,
+ flow->pmd_id, &buf, &full_flow);
+ if (err) {
+ return err;
+ }
+ flow = &full_flow;
+ }
+
+ /* Check the flow actions for recirculation action. As recirculation
+ * relies on OVS userspace internal state, we need to delete all old
+ * datapath flows with either a non-zero recirc_id in the key, or any
+ * recirculation actions upon OVS restart. */
+ NL_ATTR_FOR_EACH_UNSAFE (a, left, flow->key, flow->key_len) {
+ if (nl_attr_type(a) == OVS_KEY_ATTR_RECIRC_ID
+ && nl_attr_get_u32(a) != 0) {
+ return EINVAL;
+ }
+ }
+ NL_ATTR_FOR_EACH_UNSAFE (a, left, flow->actions, flow->actions_len) {
+ if (nl_attr_type(a) == OVS_ACTION_ATTR_RECIRC) {
+ return EINVAL;
+ }
+ }
+
+ dump_seq = seq_read(udpif->dump_seq);
+ reval_seq = seq_read(udpif->reval_seq);
+ ofpbuf_use_const(&actions, &flow->actions, flow->actions_len);
+ *ukey = ukey_create__(flow->key, flow->key_len,
+ flow->mask, flow->mask_len, flow->ufid_present,
+ &flow->ufid, flow->pmd_id, &actions, dump_seq,
+ reval_seq, flow->stats.used, 0, NULL);
+
+ return 0;
+}
+
+/* Attempts to insert a ukey into the shared ukey maps.