* flow key against the kernel's.
  * @OVS_PACKET_ATTR_ACTIONS: Contains actions for the packet.  Used
  * for %OVS_PACKET_CMD_EXECUTE.  It has nested %OVS_ACTION_ATTR_* attributes.
+ * Also used in upcall when %OVS_ACTION_ATTR_USERSPACE has optional
+ * %OVS_USERSPACE_ATTR_ACTIONS attribute.
  * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
  * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
  * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
  * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
  * @OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: If present, u32 output port to get
  * tunnel info.
+ * @OVS_USERSPACE_ATTR_ACTIONS: If present, send actions with upcall.
  */
 enum ovs_userspace_attr {
        OVS_USERSPACE_ATTR_UNSPEC,
        OVS_USERSPACE_ATTR_USERDATA,  /* Optional user-specified cookie. */
        OVS_USERSPACE_ATTR_EGRESS_TUN_PORT,  /* Optional, u32 output port
                                              * to get tunnel info. */
+       OVS_USERSPACE_ATTR_ACTIONS,   /* Optional flag to get actions. */
        __OVS_USERSPACE_ATTR_MAX
 };
 
 
 }
 
 static int output_userspace(struct datapath *dp, struct sk_buff *skb,
-                           struct sw_flow_key *key, const struct nlattr *attr)
+                           struct sw_flow_key *key, const struct nlattr *attr,
+                           const struct nlattr *actions, int actions_len)
 {
        struct ovs_tunnel_info info;
        struct dp_upcall_info upcall;
        const struct nlattr *a;
        int rem;
 
+       memset(&upcall, 0, sizeof(upcall));
        upcall.cmd = OVS_PACKET_CMD_ACTION;
-       upcall.userdata = NULL;
-       upcall.portid = 0;
-       upcall.egress_tun_info = NULL;
 
        for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
                 a = nla_next(a, &rem)) {
                        break;
                }
 
+               case OVS_USERSPACE_ATTR_ACTIONS: {
+                       /* Include actions. */
+                       upcall.actions = actions;
+                       upcall.actions_len = actions_len;
+                       break;
+               }
+
                } /* End of switch. */
        }
 
 }
 
 static int sample(struct datapath *dp, struct sk_buff *skb,
-                 struct sw_flow_key *key, const struct nlattr *attr)
+                 struct sw_flow_key *key, const struct nlattr *attr,
+                 const struct nlattr *actions, int actions_len)
 {
        const struct nlattr *acts_list = NULL;
        const struct nlattr *a;
         */
        if (likely(nla_type(a) == OVS_ACTION_ATTR_USERSPACE &&
                   nla_is_last(a, rem)))
-               return output_userspace(dp, skb, key, a);
+               return output_userspace(dp, skb, key, a, actions, actions_len);
 
        skb = skb_clone(skb, GFP_ATOMIC);
        if (!skb)
                        break;
 
                case OVS_ACTION_ATTR_USERSPACE:
-                       output_userspace(dp, skb, key, a);
+                       output_userspace(dp, skb, key, a, attr, len);
                        break;
 
                case OVS_ACTION_ATTR_HASH:
                        break;
 
                case OVS_ACTION_ATTR_SAMPLE:
-                       err = sample(dp, skb, key, a);
+                       err = sample(dp, skb, key, a, attr, len);
                        break;
                }
 
 
                struct dp_upcall_info upcall;
                int error;
 
+               memset(&upcall, 0, sizeof(upcall));
                upcall.cmd = OVS_PACKET_CMD_MISS;
-               upcall.userdata = NULL;
                upcall.portid = ovs_vport_find_upcall_portid(p, skb);
-               upcall.egress_tun_info = NULL;
                error = ovs_dp_upcall(dp, skb, key, &upcall);
                if (unlikely(error))
                        kfree_skb(skb);
        if (upcall_info->egress_tun_info)
                size += nla_total_size(ovs_tun_key_attr_size());
 
+       /* OVS_PACKET_ATTR_ACTIONS */
+       if (upcall_info->actions_len)
+               size += nla_total_size(upcall_info->actions_len);
+
        return size;
 }
 
                nla_nest_end(user_skb, nla);
        }
 
+       if (upcall_info->actions_len) {
+               nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_ACTIONS);
+               err = ovs_nla_put_actions(upcall_info->actions,
+                                         upcall_info->actions_len,
+                                         user_skb);
+               if (!err)
+                       nla_nest_end(user_skb, nla);
+               else
+                       nla_nest_cancel(user_skb, nla);
+       }
+
        /* Only reserve room for attribute header, packet data is added
         * in skb_zerocopy() */
        if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
 
 struct dp_upcall_info {
        const struct ovs_tunnel_info *egress_tun_info;
        const struct nlattr *userdata;
+       const struct nlattr *actions;
+       int actions_len;
        u32 portid;
        u8 cmd;
 };