1 From: Eric Dumazet <eric.dumazet@gmail.com>
2 Date: Mon, 28 Nov 2011 05:22:18 +0000
3 Subject: [PATCH 1/3] net: introduce skb_flow_dissect()
5 commit 0744dd00c1b1be99a25b62b1b48df440e82e57e0 upstream.
7 We use at least two flow dissectors in network stack, with known
8 limitations and code duplication.
10 Introduce skb_flow_dissect() to factorize this, highly inspired from
11 existing dissector from __skb_get_rxhash()
13 Note : We extensively use skb_header_pointer(), this permits us to not
16 Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
17 Signed-off-by: David S. Miller <davem@davemloft.net>
19 diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h
21 index 0000000..e4cb285
23 +++ b/include/net/flow_keys.h
25 +#ifndef _NET_FLOW_KEYS_H
26 +#define _NET_FLOW_KEYS_H
38 +extern bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow);
40 diff --git a/net/core/Makefile b/net/core/Makefile
41 index 3606d40..c4ecc86 100644
42 --- a/net/core/Makefile
43 +++ b/net/core/Makefile
47 obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
48 - gen_stats.o gen_estimator.o net_namespace.o secure_seq.o
49 + gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o
51 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
53 diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
55 index 0000000..f0516d9
57 +++ b/net/core/flow_dissector.c
59 +#include <linux/skbuff.h>
60 +#include <linux/ip.h>
61 +#include <linux/ipv6.h>
62 +#include <linux/if_vlan.h>
64 +#include <linux/if_tunnel.h>
65 +#include <linux/if_pppox.h>
66 +#include <linux/ppp_defs.h>
67 +#include <net/flow_keys.h>
70 +bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
72 + int poff, nhoff = skb_network_offset(skb);
74 + __be16 proto = skb->protocol;
76 + memset(flow, 0, sizeof(*flow));
80 + case __constant_htons(ETH_P_IP): {
81 + const struct iphdr *iph;
84 + iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
88 + if (ip_is_fragment(iph))
91 + ip_proto = iph->protocol;
92 + flow->src = iph->saddr;
93 + flow->dst = iph->daddr;
94 + nhoff += iph->ihl * 4;
97 + case __constant_htons(ETH_P_IPV6): {
98 + const struct ipv6hdr *iph;
99 + struct ipv6hdr _iph;
101 + iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
105 + ip_proto = iph->nexthdr;
106 + flow->src = iph->saddr.s6_addr32[3];
107 + flow->dst = iph->daddr.s6_addr32[3];
108 + nhoff += sizeof(struct ipv6hdr);
111 + case __constant_htons(ETH_P_8021Q): {
112 + const struct vlan_hdr *vlan;
113 + struct vlan_hdr _vlan;
115 + vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
119 + proto = vlan->h_vlan_encapsulated_proto;
120 + nhoff += sizeof(*vlan);
123 + case __constant_htons(ETH_P_PPP_SES): {
125 + struct pppoe_hdr hdr;
128 + hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
131 + proto = hdr->proto;
132 + nhoff += PPPOE_SES_HLEN;
134 + case __constant_htons(PPP_IP):
136 + case __constant_htons(PPP_IPV6):
146 + switch (ip_proto) {
147 + case IPPROTO_GRE: {
153 + hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
157 + * Only look inside GRE if version zero and no
160 + if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) {
161 + proto = hdr->proto;
163 + if (hdr->flags & GRE_CSUM)
165 + if (hdr->flags & GRE_KEY)
167 + if (hdr->flags & GRE_SEQ)
179 + flow->ip_proto = ip_proto;
180 + poff = proto_ports_offset(ip_proto);
182 + __be32 *ports, _ports;
185 + ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
187 + flow->ports = *ports;
192 +EXPORT_SYMBOL(skb_flow_dissect);