diff options
Diffstat (limited to 'datapath')
-rw-r--r-- | datapath/datapath.c | 33 | ||||
-rw-r--r-- | datapath/datapath.h | 12 | ||||
-rw-r--r-- | datapath/linux/compat/include/linux/skbuff.h | 31 |
3 files changed, 75 insertions, 1 deletions
diff --git a/datapath/datapath.c b/datapath/datapath.c index a7af7849a..05c1e4274 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -371,7 +371,8 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, 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) @@ -414,6 +415,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, size_t len; unsigned int hlen; int err, dp_ifindex; + u64 hash; dp_ifindex = get_dpifindex(dp); if (!dp_ifindex) @@ -523,6 +525,25 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, pad_packet(dp, user_skb); } + /* Add OVS_PACKET_ATTR_HASH */ + hash = skb_get_hash_raw(skb); +#ifdef HAVE_SW_HASH + if (skb->sw_hash) + hash |= OVS_PACKET_HASH_SW_BIT; +#endif + +#ifdef HAVE_L4_RXHASH + if (skb->l4_rxhash) +#else + if (skb->l4_hash) +#endif + 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() */ @@ -563,6 +584,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct vport *input_vport; u16 mru = 0; + u64 hash; int len; int err; bool log = !a[OVS_PACKET_ATTR_PROBE]; @@ -588,6 +610,14 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) } 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); @@ -649,6 +679,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG }, [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 }, + [OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 }, }; static struct genl_ops dp_packet_genl_ops[] = { diff --git a/datapath/datapath.h b/datapath/datapath.h index 3bffa1dcb..f99db1fde 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -159,6 +159,18 @@ struct ovs_net { #endif }; +/** + * 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); diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 63972891b..6d248b3ed 100644 --- a/datapath/linux/compat/include/linux/skbuff.h +++ b/datapath/linux/compat/include/linux/skbuff.h @@ -456,4 +456,35 @@ static inline void skb_set_inner_ipproto(struct sk_buff *skb, #define nf_reset_ct nf_reset #endif +#ifndef HAVE___SKB_SET_HASH +static inline void +__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4) +{ +#ifdef HAVE_RXHASH + skb->rxhash = hash; +#else + skb->hash = hash; +#endif +#if defined(HAVE_L4_RXHASH) + skb->l4_rxhash = is_l4; +#else + skb->l4_hash = is_l4; +#endif +#ifdef HAVE_SW_HASH + skb->sw_hash = is_sw; +#endif +} +#endif + +#ifndef HAVE_SKB_GET_HASH_RAW +static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) +{ +#ifdef HAVE_RXHASH + return skb->rxhash; +#else + return skb->hash; +#endif +} +#endif + #endif |