Skip to content

Commit

Permalink
net: Add full IPv6 addresses to flow_keys
Browse files Browse the repository at this point in the history
This patch adds full IPv6 addresses into flow_keys and uses them as
input to the flow hash function. The implementation supports either
IPv4 or IPv6 addresses in a union, and selector is used to determine
how may words to input to jhash2.

We also add flow_get_u32_dst and flow_get_u32_src functions which are
used to get a u32 representation of the source and destination
addresses. For IPv6, ipv6_addr_hash is called. These functions retain
getting the legacy values of src and dst in flow_keys.

With this patch, Ethertype and IP protocol are now included in the
flow hash input.

Signed-off-by: Tom Herbert <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
tomratbert authored and davem330 committed Jun 4, 2015
1 parent 42aecaa commit c3f8324
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 63 deletions.
9 changes: 4 additions & 5 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3059,17 +3059,15 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
return false;
iph = ip_hdr(skb);
fk->addrs.src = iph->saddr;
fk->addrs.dst = iph->daddr;
iph_to_flow_copy_v4addrs(fk, iph);
noff += iph->ihl << 2;
if (!ip_is_fragment(iph))
proto = iph->protocol;
} else if (skb->protocol == htons(ETH_P_IPV6)) {
if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6))))
return false;
iph6 = ipv6_hdr(skb);
fk->addrs.src = (__force __be32)ipv6_addr_hash(&iph6->saddr);
fk->addrs.dst = (__force __be32)ipv6_addr_hash(&iph6->daddr);
iph_to_flow_copy_v6addrs(fk, iph6);
noff += sizeof(*iph6);
proto = iph6->nexthdr;
} else {
Expand Down Expand Up @@ -3103,7 +3101,8 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb)
hash = bond_eth_hash(skb);
else
hash = (__force u32)flow.ports.ports;
hash ^= (__force u32)flow.addrs.dst ^ (__force u32)flow.addrs.src;
hash ^= (__force u32)flow_get_u32_dst(&flow) ^
(__force u32)flow_get_u32_src(&flow);
hash ^= (hash >> 16);
hash ^= (hash >> 8);

Expand Down
8 changes: 4 additions & 4 deletions drivers/net/ethernet/cisco/enic/enic_clsf.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ int enic_addfltr_5t(struct enic *enic, struct flow_keys *keys, u16 rq)
return -EPROTONOSUPPORT;
};
data.type = FILTER_IPV4_5TUPLE;
data.u.ipv4.src_addr = ntohl(keys->addrs.src);
data.u.ipv4.dst_addr = ntohl(keys->addrs.dst);
data.u.ipv4.src_addr = ntohl(keys->addrs.v4addrs.src);
data.u.ipv4.dst_addr = ntohl(keys->addrs.v4addrs.dst);
data.u.ipv4.src_port = ntohs(keys->ports.src);
data.u.ipv4.dst_port = ntohs(keys->ports.dst);
data.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
Expand Down Expand Up @@ -158,8 +158,8 @@ static struct enic_rfs_fltr_node *htbl_key_search(struct hlist_head *h,
struct enic_rfs_fltr_node *tpos;

hlist_for_each_entry(tpos, h, node)
if (tpos->keys.addrs.src == k->addrs.src &&
tpos->keys.addrs.dst == k->addrs.dst &&
if (tpos->keys.addrs.v4addrs.src == k->addrs.v4addrs.src &&
tpos->keys.addrs.v4addrs.dst == k->addrs.v4addrs.dst &&
tpos->keys.ports.ports == k->ports.ports &&
tpos->keys.basic.ip_proto == k->basic.ip_proto &&
tpos->keys.basic.n_proto == k->basic.n_proto)
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/ethernet/cisco/enic/enic_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,10 @@ static int enic_grxclsrule(struct enic *enic, struct ethtool_rxnfc *cmd)
break;
}

fsp->h_u.tcp_ip4_spec.ip4src = n->keys.addrs.src;
fsp->h_u.tcp_ip4_spec.ip4src = flow_get_u32_src(&n->keys);
fsp->m_u.tcp_ip4_spec.ip4src = (__u32)~0;

fsp->h_u.tcp_ip4_spec.ip4dst = n->keys.addrs.dst;
fsp->h_u.tcp_ip4_spec.ip4dst = flow_get_u32_dst(&n->keys);
fsp->m_u.tcp_ip4_spec.ip4dst = (__u32)~0;

fsp->h_u.tcp_ip4_spec.psrc = n->keys.ports.src;
Expand Down
52 changes: 33 additions & 19 deletions include/net/flow_dissector.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
struct flow_dissector_key_control {
u16 thoff;
u16 padding;
u16 addr_type;
};

/**
Expand All @@ -28,18 +28,39 @@ struct flow_dissector_key_basic {
};

/**
* struct flow_dissector_key_addrs:
* @src: source ip address in case of IPv4
* For IPv6 it contains 32bit hash of src address
* @dst: destination ip address in case of IPv4
* For IPv6 it contains 32bit hash of dst address
* struct flow_dissector_key_ipv4_addrs:
* @src: source ip address
* @dst: destination ip address
*/
struct flow_dissector_key_addrs {
struct flow_dissector_key_ipv4_addrs {
/* (src,dst) must be grouped, in the same way than in IP header */
__be32 src;
__be32 dst;
};

/**
* struct flow_dissector_key_ipv6_addrs:
* @src: source ip address
* @dst: destination ip address
*/
struct flow_dissector_key_ipv6_addrs {
/* (src,dst) must be grouped, in the same way than in IP header */
struct in6_addr src;
struct in6_addr dst;
};

/**
* struct flow_dissector_key_addrs:
* @v4addrs: IPv4 addresses
* @v6addrs: IPv6 addresses
*/
struct flow_dissector_key_addrs {
union {
struct flow_dissector_key_ipv4_addrs v4addrs;
struct flow_dissector_key_ipv6_addrs v6addrs;
};
};

/**
* flow_dissector_key_tp_ports:
* @ports: port numbers of Transport header
Expand All @@ -56,16 +77,6 @@ struct flow_dissector_key_ports {
};
};

/**
* struct flow_dissector_key_ipv6_addrs:
* @src: source ip address
* @dst: destination ip address
*/
struct flow_dissector_key_ipv6_addrs {
/* (src,dst) must be grouped, in the same way than in IP header */
struct in6_addr src;
struct in6_addr dst;
};

/**
* struct flow_dissector_key_eth_addrs:
Expand All @@ -81,10 +92,10 @@ struct flow_dissector_key_eth_addrs {
enum flow_dissector_key_id {
FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */
FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */
FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */
FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_ipv4_addrs */
FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */
FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */
FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */
FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */
FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */

FLOW_DISSECTOR_KEY_MAX,
Expand Down Expand Up @@ -129,6 +140,9 @@ struct flow_keys {
#define FLOW_KEYS_HASH_OFFSET \
offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD)

__be32 flow_get_u32_src(const struct flow_keys *flow);
__be32 flow_get_u32_dst(const struct flow_keys *flow);

extern struct flow_dissector flow_keys_dissector;
extern struct flow_dissector flow_keys_buf_dissector;

Expand Down
19 changes: 17 additions & 2 deletions include/net/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,30 @@ static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto)
skb->len, proto, 0);
}

/* copy IPv4 saddr & daddr to flow_keys, possibly using 64bit load/store
* Equivalent to : flow->v4addrs.src = iph->saddr;
* flow->v4addrs.dst = iph->daddr;
*/
static inline void iph_to_flow_copy_v4addrs(struct flow_keys *flow,
const struct iphdr *iph)
{
BUILD_BUG_ON(offsetof(typeof(flow->addrs), v4addrs.dst) !=
offsetof(typeof(flow->addrs), v4addrs.src) +
sizeof(flow->addrs.v4addrs.src));
memcpy(&flow->addrs.v4addrs, &iph->saddr, sizeof(flow->addrs.v4addrs));
flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
}

static inline void inet_set_txhash(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct flow_keys keys;

memset(&keys, 0, sizeof(keys));

keys.addrs.src = inet->inet_saddr;
keys.addrs.dst = inet->inet_daddr;
keys.addrs.v4addrs.src = inet->inet_saddr;
keys.addrs.v4addrs.dst = inet->inet_daddr;
keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
keys.ports.src = inet->inet_sport;
keys.ports.dst = inet->inet_dport;

Expand Down
21 changes: 19 additions & 2 deletions include/net/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,20 @@ static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6,
return hlimit;
}

/* copy IPv6 saddr & daddr to flow_keys, possibly using 64bit load/store
* Equivalent to : flow->v6addrs.src = iph->saddr;
* flow->v6addrs.dst = iph->daddr;
*/
static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow,
const struct ipv6hdr *iph)
{
BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) !=
offsetof(typeof(flow->addrs), v6addrs.src) +
sizeof(flow->addrs.v6addrs.src));
memcpy(&flow->addrs.v6addrs, &iph->saddr, sizeof(flow->addrs.v6addrs));
flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
}

#if IS_ENABLED(CONFIG_IPV6)
static inline void ip6_set_txhash(struct sock *sk)
{
Expand All @@ -701,8 +715,11 @@ static inline void ip6_set_txhash(struct sock *sk)

memset(&keys, 0, sizeof(keys));

keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr);
keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr);
memcpy(&keys.addrs.v6addrs.src, &np->saddr,
sizeof(keys.addrs.v6addrs.src));
memcpy(&keys.addrs.v6addrs.dst, &sk->sk_v6_daddr,
sizeof(keys.addrs.v6addrs.dst));
keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
keys.ports.src = inet->inet_sport;
keys.ports.dst = inet->inet_dport;

Expand Down
Loading

0 comments on commit c3f8324

Please sign in to comment.