Skip to content

Commit

Permalink
Merge branch 'skb_hash'
Browse files Browse the repository at this point in the history
Tom Herbert says:

====================
net: Add rxhash utility hash functions

v3:

There's really nothing specific about rxhash that constrains
it to be a value just for these receive path. Drop the 'rx'
part in utility functions, including skb_get_rxhash. In subsequent
patches, we can change the rxhash and l4_rxhash names also, as
well as abstracting out the interface to the hash.

Added comments about hash types per feedback.

In this version I'm omitting the changes to drivers to make the
patch set manageable. Will add those changes in followup pathes.

-----
This patch series introduce skb_set_rxhash and skb_clear_rxhash
which are called to set the rxhash (from network drivers) and
to clear the rxhash. This API should be used instead of updating
fields in the skbuff directly.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 17, 2013
2 parents 1aee6cc + 3df7a74 commit f66fd2d
Show file tree
Hide file tree
Showing 15 changed files with 86 additions and 31 deletions.
2 changes: 1 addition & 1 deletion drivers/net/macvtap.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
goto out;

/* Check if we can use flow to select a queue */
rxq = skb_get_rxhash(skb);
rxq = skb_get_hash(skb);
if (rxq) {
tap = rcu_dereference(vlan->taps[rxq % numvtaps]);
goto out;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/tun.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb)
rcu_read_lock();
numqueues = ACCESS_ONCE(tun->numqueues);

txq = skb_get_rxhash(skb);
txq = skb_get_hash(skb);
if (txq) {
e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq);
if (e)
Expand Down Expand Up @@ -1146,7 +1146,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb_reset_network_header(skb);
skb_probe_transport_header(skb, 0);

rxhash = skb_get_rxhash(skb);
rxhash = skb_get_hash(skb);
netif_rx_ni(skb);

tun->dev->stats.rx_packets++;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb)
unsigned int range = (port_max - port_min) + 1;
u32 hash;

hash = skb_get_rxhash(skb);
hash = skb_get_hash(skb);
if (!hash)
hash = jhash(skb->data, 2 * ETH_ALEN,
(__force u32) skb->protocol);
Expand Down
64 changes: 61 additions & 3 deletions include/linux/skbuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,15 +703,73 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
unsigned int to, struct ts_config *config,
struct ts_state *state);

void __skb_get_rxhash(struct sk_buff *skb);
static inline __u32 skb_get_rxhash(struct sk_buff *skb)
/*
* Packet hash types specify the type of hash in skb_set_hash.
*
* Hash types refer to the protocol layer addresses which are used to
* construct a packet's hash. The hashes are used to differentiate or identify
* flows of the protocol layer for the hash type. Hash types are either
* layer-2 (L2), layer-3 (L3), or layer-4 (L4).
*
* Properties of hashes:
*
* 1) Two packets in different flows have different hash values
* 2) Two packets in the same flow should have the same hash value
*
* A hash at a higher layer is considered to be more specific. A driver should
* set the most specific hash possible.
*
* A driver cannot indicate a more specific hash than the layer at which a hash
* was computed. For instance an L3 hash cannot be set as an L4 hash.
*
* A driver may indicate a hash level which is less specific than the
* actual layer the hash was computed on. For instance, a hash computed
* at L4 may be considered an L3 hash. This should only be done if the
* driver can't unambiguously determine that the HW computed the hash at
* the higher layer. Note that the "should" in the second property above
* permits this.
*/
enum pkt_hash_types {
PKT_HASH_TYPE_NONE, /* Undefined type */
PKT_HASH_TYPE_L2, /* Input: src_MAC, dest_MAC */
PKT_HASH_TYPE_L3, /* Input: src_IP, dst_IP */
PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */
};

static inline void
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
{
skb->l4_rxhash = (type == PKT_HASH_TYPE_L4);
skb->rxhash = hash;
}

void __skb_get_hash(struct sk_buff *skb);
static inline __u32 skb_get_hash(struct sk_buff *skb)
{
if (!skb->l4_rxhash)
__skb_get_rxhash(skb);
__skb_get_hash(skb);

return skb->rxhash;
}

static inline void skb_clear_hash(struct sk_buff *skb)
{
skb->rxhash = 0;
skb->l4_rxhash = 0;
}

static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
{
if (!skb->l4_rxhash)
skb_clear_hash(skb);
}

static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
{
to->rxhash = from->rxhash;
to->l4_rxhash = from->l4_rxhash;
};

#ifdef NET_SKBUFF_DATA_USES_OFFSET
static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
{
Expand Down
5 changes: 2 additions & 3 deletions include/net/dst.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,11 @@ static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev,
skb->dev = dev;

/*
* Clear rxhash so that we can recalulate the hash for the
* Clear hash so that we can recalulate the hash for the
* encapsulated packet, unless we have already determine the hash
* over the L4 4-tuple.
*/
if (!skb->l4_rxhash)
skb->rxhash = 0;
skb_clear_hash_if_not_l4(skb);
skb_set_queue_mapping(skb, 0);
skb_scrub_packet(skb, !net_eq(net, dev_net(dev)));
}
Expand Down
4 changes: 2 additions & 2 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -3006,7 +3006,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
}

skb_reset_network_header(skb);
if (!skb_get_rxhash(skb))
if (!skb_get_hash(skb))
goto done;

flow_table = rcu_dereference(rxqueue->rps_flow_table);
Expand Down Expand Up @@ -3151,7 +3151,7 @@ static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen)
rcu_read_lock();
fl = rcu_dereference(sd->flow_limit);
if (fl) {
new_flow = skb_get_rxhash(skb) & (fl->num_buckets - 1);
new_flow = skb_get_hash(skb) & (fl->num_buckets - 1);
old_flow = fl->history[fl->history_head];
fl->history[fl->history_head] = new_flow;

Expand Down
6 changes: 3 additions & 3 deletions net/core/flow_dissector.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,12 @@ static __always_inline u32 __flow_hash_1word(u32 a)
}

/*
* __skb_get_rxhash: calculate a flow hash based on src/dst addresses
* __skb_get_hash: calculate a flow hash based on src/dst addresses
* and src/dst port numbers. Sets rxhash in skb to non-zero hash value
* on success, zero indicates no valid hash. Also, sets l4_rxhash in skb
* if hash is a canonical 4-tuple hash over transport ports.
*/
void __skb_get_rxhash(struct sk_buff *skb)
void __skb_get_hash(struct sk_buff *skb)
{
struct flow_keys keys;
u32 hash;
Expand All @@ -234,7 +234,7 @@ void __skb_get_rxhash(struct sk_buff *skb)

skb->rxhash = hash;
}
EXPORT_SYMBOL(__skb_get_rxhash);
EXPORT_SYMBOL(__skb_get_hash);

/*
* Returns a Tx hash based on the given packet descriptor a Tx queues' number
Expand Down
3 changes: 1 addition & 2 deletions net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->inner_network_header = old->inner_network_header;
new->inner_mac_header = old->inner_mac_header;
skb_dst_copy(new, old);
new->rxhash = old->rxhash;
skb_copy_hash(new, old);
new->ooo_okay = old->ooo_okay;
new->l4_rxhash = old->l4_rxhash;
new->no_fcs = old->no_fcs;
new->encapsulation = old->encapsulation;
#ifdef CONFIG_XFRM
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/ip_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
if (ip_defrag(skb, user))
return NULL;
skb->rxhash = 0;
skb_clear_hash(skb);
}
}
return skb;
Expand Down
5 changes: 2 additions & 3 deletions net/ipv4/ip_tunnel_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb,

skb_scrub_packet(skb, xnet);

skb->rxhash = 0;
skb_clear_hash(skb);
skb_dst_set(skb, &rt->dst);
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));

Expand Down Expand Up @@ -107,8 +107,7 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)

nf_reset(skb);
secpath_reset(skb);
if (!skb->l4_rxhash)
skb->rxhash = 0;
skb_clear_hash_if_not_l4(skb);
skb_dst_drop(skb);
skb->vlan_tci = 0;
skb_set_queue_mapping(skb, 0);
Expand Down
10 changes: 5 additions & 5 deletions net/openvswitch/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
}

csum_replace4(&nh->check, *addr, new_addr);
skb->rxhash = 0;
skb_clear_hash(skb);
*addr = new_addr;
}

Expand Down Expand Up @@ -199,7 +199,7 @@ static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto,
if (recalculate_csum)
update_ipv6_checksum(skb, l4_proto, addr, new_addr);

skb->rxhash = 0;
skb_clear_hash(skb);
memcpy(addr, new_addr, sizeof(__be32[4]));
}

Expand Down Expand Up @@ -296,7 +296,7 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port,
{
inet_proto_csum_replace2(check, skb, *port, new_port, 0);
*port = new_port;
skb->rxhash = 0;
skb_clear_hash(skb);
}

static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
Expand All @@ -310,7 +310,7 @@ static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
uh->check = CSUM_MANGLED_0;
} else {
*port = new_port;
skb->rxhash = 0;
skb_clear_hash(skb);
}
}

Expand Down Expand Up @@ -381,7 +381,7 @@ static int set_sctp(struct sk_buff *skb,
/* Carry any checksum errors through. */
sh->checksum = old_csum ^ old_correct_csum ^ new_csum;

skb->rxhash = 0;
skb_clear_hash(skb);
}

return 0;
Expand Down
4 changes: 2 additions & 2 deletions net/packet/af_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,7 @@ static void prb_clear_blk_fill_status(struct packet_ring_buffer *rb)
static void prb_fill_rxhash(struct tpacket_kbdq_core *pkc,
struct tpacket3_hdr *ppd)
{
ppd->hv1.tp_rxhash = skb_get_rxhash(pkc->skb);
ppd->hv1.tp_rxhash = skb_get_hash(pkc->skb);
}

static void prb_clear_rxhash(struct tpacket_kbdq_core *pkc,
Expand Down Expand Up @@ -1295,7 +1295,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
if (!skb)
return 0;
}
skb_get_rxhash(skb);
skb_get_hash(skb);
idx = fanout_demux_hash(f, skb, num);
break;
case PACKET_FANOUT_LB:
Expand Down
2 changes: 1 addition & 1 deletion net/sched/cls_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb)

static u32 flow_get_rxhash(struct sk_buff *skb)
{
return skb_get_rxhash(skb);
return skb_get_hash(skb);
}

static u32 flow_key_get(struct sk_buff *skb, int key, struct flow_keys *flow)
Expand Down
2 changes: 1 addition & 1 deletion net/sched/em_meta.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ META_COLLECTOR(int_maclen)

META_COLLECTOR(int_rxhash)
{
dst->value = skb_get_rxhash(skb);
dst->value = skb_get_hash(skb);
}

/**************************************************************************
Expand Down
2 changes: 1 addition & 1 deletion net/sched/sch_fq.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
/* By forcing low order bit to 1, we make sure to not
* collide with a local flow (socket pointers are word aligned)
*/
sk = (struct sock *)(skb_get_rxhash(skb) | 1L);
sk = (struct sock *)(skb_get_hash(skb) | 1L);
}

root = &q->fq_root[hash_32((u32)(long)sk, q->fq_trees_log)];
Expand Down

0 comments on commit f66fd2d

Please sign in to comment.