* @xmit_more: More SKBs are pending for this queue
* @ndisc_nodetype: router type (from link layer)
* @ooo_okay: allow the mapping of a socket to a queue to be changed
- * @l4_hash: indicate hash is a canonical 4-tuple hash over transport
- * ports.
+ * @hash_type: indicates type of hash (see enum pkt_hash_types below)
* @sw_hash: indicates hash was computed in software stack
* @wifi_acked_valid: wifi_acked was set
* @wifi_acked: whether frame was acked on wifi or not
__u8 nf_trace:1;
__u8 ip_summed:2;
__u8 ooo_okay:1;
- __u8 l4_hash:1;
__u8 sw_hash:1;
__u8 wifi_acked_valid:1;
__u8 wifi_acked:1;
+ /* 1 bit hole */
__u8 no_fcs:1;
/* Indicates the inner headers are valid in the skbuff. */
__u8 ipvs_property:1;
__u8 inner_protocol_type:1;
__u8 remcsum_offload:1;
- /* 3 or 5 bit hole */
+ __u8 hash_type:2;
+ /* 1 or 3 bit hole */
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
{
skb->hash = 0;
skb->sw_hash = 0;
- skb->l4_hash = 0;
+ skb->hash_type = 0;
+}
+
+static inline enum pkt_hash_types skb_hash_type(struct sk_buff *skb)
+{
+ return skb->hash_type;
+}
+
+static inline bool skb_has_l4_hash(struct sk_buff *skb)
+{
+ return skb_hash_type(skb) == PKT_HASH_TYPE_L4;
+}
+
+static inline bool skb_has_sw_hash(struct sk_buff *skb)
+{
+ return !!skb->sw_hash;
}
static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
{
- if (!skb->l4_hash)
+ if (!skb_has_l4_hash(skb))
skb_clear_hash(skb);
}
static inline void
-__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4)
+__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw,
+ enum pkt_hash_types type)
{
- skb->l4_hash = is_l4;
+ skb->hash_type = type;
skb->sw_hash = is_sw;
skb->hash = hash;
}
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
{
/* Used by drivers to set hash from HW */
- __skb_set_hash(skb, hash, false, type == PKT_HASH_TYPE_L4);
+ __skb_set_hash(skb, hash, false, type);
}
static inline void
-__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4)
+__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
{
- __skb_set_hash(skb, hash, true, is_l4);
+ __skb_set_hash(skb, hash, true, type);
}
void __skb_get_hash(struct sk_buff *skb);
data, proto, nhoff, hlen, flags);
}
+
static inline __u32 skb_get_hash(struct sk_buff *skb)
{
- if (!skb->l4_hash && !skb->sw_hash)
+ if (!skb_has_l4_hash(skb) && !skb_has_sw_hash(skb))
__skb_get_hash(skb);
return skb->hash;
static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6)
{
- if (!skb->l4_hash && !skb->sw_hash) {
+ if (!skb_has_l4_hash(skb) && !skb_has_sw_hash(skb)) {
struct flow_keys keys;
__u32 hash = __get_hash_from_flowi6(fl6, &keys);
- __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
+ __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
return skb->hash;
static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl4)
{
- if (!skb->l4_hash && !skb->sw_hash) {
+ if (!skb_has_l4_hash(skb) && !skb_has_sw_hash(skb)) {
struct flow_keys keys;
__u32 hash = __get_hash_from_flowi4(fl4, &keys);
- __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
+ __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
}
return skb->hash;
{
to->hash = from->hash;
to->sw_hash = from->sw_hash;
- to->l4_hash = from->l4_hash;
+ to->hash_type = from->hash_type;
};
static inline void skb_sender_cpu_clear(struct sk_buff *skb)
*
* This function calculates a flow hash based on src/dst addresses
* and src/dst port numbers. Sets hash in skb to non-zero hash value
- * on success, zero indicates no valid hash. Also, sets l4_hash in skb
- * if hash is a canonical 4-tuple hash over transport ports.
+ * on success, zero indicates no valid hash in which case the hash type
+ * is set to NONE. If the hash is a canonical 4-tuple hash over transport
+ * ports then type is set to L4. If the hash did not include transport
+ * then type is set to L3, otherwise it is assumed to be L2 only.
*/
void __skb_get_hash(struct sk_buff *skb)
{
struct flow_keys keys;
+ u32 hash;
+ enum pkt_hash_types type;
__flow_hash_secret_init();
- __skb_set_sw_hash(skb, ___skb_get_hash(skb, &keys, hashrnd),
- flow_keys_have_l4(&keys));
+ hash = ___skb_get_hash(skb, &keys, hashrnd);
+ if (hash == 0)
+ type = PKT_HASH_TYPE_NONE;
+ else if (flow_keys_have_l4(&keys))
+ type = PKT_HASH_TYPE_L4;
+ else if (flow_keys_have_l3(&keys))
+ type = PKT_HASH_TYPE_L3;
+ else
+ type = PKT_HASH_TYPE_L2;
+
+ __skb_set_sw_hash(skb, hash, type);
}
EXPORT_SYMBOL(__skb_get_hash);
keys.basic.ip_proto = fl6->flowi6_proto;
__skb_set_sw_hash(skb, flow_hash_from_keys(&keys),
- flow_keys_have_l4(&keys));
+ flow_keys_have_l4(&keys) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
return skb->hash;
}
keys.basic.ip_proto = fl4->flowi4_proto;
__skb_set_sw_hash(skb, flow_hash_from_keys(&keys),
- flow_keys_have_l4(&keys));
+ flow_keys_have_l4(&keys) ?
+ PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
return skb->hash;
}