* @OVS_PACKET_ATTR_LEN: Packet size before truncation.
  * %OVS_PACKET_ATTR_USERSPACE action specify the Maximum received fragment
  * size.
+ * @OVS_PACKET_ATTR_HASH: Packet hash info (e.g. hash, sw_hash and l4_hash in skb).
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
  * payload for %OVS_PACKET_* commands.
        OVS_PACKET_ATTR_PROBE,      /* Packet operation is a feature probe,
                                       error logging should be suppressed. */
        OVS_PACKET_ATTR_MRU,        /* Maximum received IP fragment size. */
-       OVS_PACKET_ATTR_LEN,            /* Packet size before truncation. */
+       OVS_PACKET_ATTR_LEN,        /* Packet size before truncation. */
+       OVS_PACKET_ATTR_HASH,       /* Packet hash. */
        __OVS_PACKET_ATTR_MAX
 };
 
 
        size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
                + nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
                + nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */
-               + nla_total_size(sizeof(unsigned int)); /* OVS_PACKET_ATTR_LEN */
+               + nla_total_size(sizeof(unsigned int)) /* OVS_PACKET_ATTR_LEN */
+               + nla_total_size(sizeof(u64)); /* OVS_PACKET_ATTR_HASH */
 
        /* OVS_PACKET_ATTR_USERDATA */
        if (upcall_info->userdata)
        size_t len;
        unsigned int hlen;
        int err, dp_ifindex;
+       u64 hash;
 
        dp_ifindex = get_dpifindex(dp);
        if (!dp_ifindex)
                pad_packet(dp, user_skb);
        }
 
+       /* Add OVS_PACKET_ATTR_HASH */
+       hash = skb_get_hash_raw(skb);
+       if (skb->sw_hash)
+               hash |= OVS_PACKET_HASH_SW_BIT;
+
+       if (skb->l4_hash)
+               hash |= OVS_PACKET_HASH_L4_BIT;
+
+       if (nla_put(user_skb, OVS_PACKET_ATTR_HASH, sizeof (u64), &hash)) {
+               err = -ENOBUFS;
+               goto out;
+       }
+
        /* 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 datapath *dp;
        struct vport *input_vport;
        u16 mru = 0;
+       u64 hash;
        int len;
        int err;
        bool log = !a[OVS_PACKET_ATTR_PROBE];
        }
        OVS_CB(packet)->mru = mru;
 
+       if (a[OVS_PACKET_ATTR_HASH]) {
+               hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
+
+               __skb_set_hash(packet, hash & 0xFFFFFFFFULL,
+                              !!(hash & OVS_PACKET_HASH_SW_BIT),
+                              !!(hash & OVS_PACKET_HASH_L4_BIT));
+       }
+
        /* Build an sw_flow for sending this packet. */
        flow = ovs_flow_alloc();
        err = PTR_ERR(flow);
 
        bool xt_label;
 };
 
+/**
+ * enum ovs_pkt_hash_types - hash info to include with a packet
+ * to send to userspace.
+ * @OVS_PACKET_HASH_SW_BIT: indicates hash was computed in software stack.
+ * @OVS_PACKET_HASH_L4_BIT: indicates hash is a canonical 4-tuple hash
+ * over transport ports.
+ */
+enum ovs_pkt_hash_types {
+       OVS_PACKET_HASH_SW_BIT = (1ULL << 32),
+       OVS_PACKET_HASH_L4_BIT = (1ULL << 33),
+};
+
 extern unsigned int ovs_net_id;
 void ovs_lock(void);
 void ovs_unlock(void);