Commit d3ffa7ac authored by David S. Miller's avatar David S. Miller

Merge branch 'flow_dissector-fixes-and-improvements'

Alexander Duyck says:

====================
Flow dissector fixes and improvements

This patch series is meant to fix and/or improve a number of items within
the flow dissector code.  The main change out of all of this is that IPv4
and IPv6 fragmentation should now be handled better than it was.  As a
result we should see an improvement when handling things like IP fragment
reassembly as the skbs should now only have header data in the linear
portion of the buffer while the fragments will only hold payload data.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f993604d d975ddd6
...@@ -178,15 +178,16 @@ bool __skb_flow_dissect(const struct sk_buff *skb, ...@@ -178,15 +178,16 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
ip_proto = iph->protocol; ip_proto = iph->protocol;
if (!dissector_uses_key(flow_dissector, if (dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS)) FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
break; key_addrs = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
target_container);
key_addrs = skb_flow_dissector_target(flow_dissector, memcpy(&key_addrs->v4addrs, &iph->saddr,
FLOW_DISSECTOR_KEY_IPV4_ADDRS, target_container); sizeof(key_addrs->v4addrs));
memcpy(&key_addrs->v4addrs, &iph->saddr, key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
sizeof(key_addrs->v4addrs)); }
key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
if (ip_is_fragment(iph)) { if (ip_is_fragment(iph)) {
key_control->flags |= FLOW_DIS_IS_FRAGMENT; key_control->flags |= FLOW_DIS_IS_FRAGMENT;
...@@ -219,13 +220,12 @@ bool __skb_flow_dissect(const struct sk_buff *skb, ...@@ -219,13 +220,12 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
if (dissector_uses_key(flow_dissector, if (dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
struct flow_dissector_key_ipv6_addrs *key_ipv6_addrs; key_addrs = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
key_ipv6_addrs = skb_flow_dissector_target(flow_dissector, target_container);
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
target_container);
memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs)); memcpy(&key_addrs->v6addrs, &iph->saddr,
sizeof(key_addrs->v6addrs));
key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
} }
...@@ -339,8 +339,11 @@ bool __skb_flow_dissect(const struct sk_buff *skb, ...@@ -339,8 +339,11 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
} }
case htons(ETH_P_FCOE): case htons(ETH_P_FCOE):
key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN); if ((hlen - nhoff) < FCOE_HEADER_LEN)
/* fall through */ goto out_bad;
nhoff += FCOE_HEADER_LEN;
goto out_good;
default: default:
goto out_bad; goto out_bad;
} }
...@@ -447,13 +450,12 @@ bool __skb_flow_dissect(const struct sk_buff *skb, ...@@ -447,13 +450,12 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
key_control->flags |= FLOW_DIS_IS_FRAGMENT; key_control->flags |= FLOW_DIS_IS_FRAGMENT;
nhoff += sizeof(_fh); nhoff += sizeof(_fh);
ip_proto = fh->nexthdr;
if (!(fh->frag_off & htons(IP6_OFFSET))) { if (!(fh->frag_off & htons(IP6_OFFSET))) {
key_control->flags |= FLOW_DIS_FIRST_FRAG; key_control->flags |= FLOW_DIS_FIRST_FRAG;
if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) { if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)
ip_proto = fh->nexthdr;
goto ip_proto_again; goto ip_proto_again;
}
} }
goto out_good; goto out_good;
} }
...@@ -740,6 +742,11 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data, ...@@ -740,6 +742,11 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
{ {
u32 poff = keys->control.thoff; u32 poff = keys->control.thoff;
/* skip L4 headers for fragments after the first */
if ((keys->control.flags & FLOW_DIS_IS_FRAGMENT) &&
!(keys->control.flags & FLOW_DIS_FIRST_FRAG))
return poff;
switch (keys->basic.ip_proto) { switch (keys->basic.ip_proto) {
case IPPROTO_TCP: { case IPPROTO_TCP: {
/* access doff as u8 to avoid unaligned access */ /* access doff as u8 to avoid unaligned access */
......
...@@ -125,6 +125,7 @@ EXPORT_SYMBOL(eth_header); ...@@ -125,6 +125,7 @@ EXPORT_SYMBOL(eth_header);
*/ */
u32 eth_get_headlen(void *data, unsigned int len) u32 eth_get_headlen(void *data, unsigned int len)
{ {
const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
const struct ethhdr *eth = (const struct ethhdr *)data; const struct ethhdr *eth = (const struct ethhdr *)data;
struct flow_keys keys; struct flow_keys keys;
...@@ -134,7 +135,7 @@ u32 eth_get_headlen(void *data, unsigned int len) ...@@ -134,7 +135,7 @@ u32 eth_get_headlen(void *data, unsigned int len)
/* parse any remaining L2/L3 headers, check for L4 */ /* parse any remaining L2/L3 headers, check for L4 */
if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto,
sizeof(*eth), len, 0)) sizeof(*eth), len, flags))
return max_t(u32, keys.control.thoff, sizeof(*eth)); return max_t(u32, keys.control.thoff, sizeof(*eth));
/* parse for any L4 headers */ /* parse for any L4 headers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment