]>
Commit | Line | Data |
---|---|---|
97bb1c57 AF |
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() | |
4 | ||
5 | commit 0744dd00c1b1be99a25b62b1b48df440e82e57e0 upstream. | |
6 | ||
7 | We use at least two flow dissectors in network stack, with known | |
8 | limitations and code duplication. | |
9 | ||
10 | Introduce skb_flow_dissect() to factorize this, highly inspired from | |
11 | existing dissector from __skb_get_rxhash() | |
12 | ||
13 | Note : We extensively use skb_header_pointer(), this permits us to not | |
14 | touch skb at all. | |
15 | ||
16 | Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> | |
17 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
18 | ||
19 | diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h | |
20 | new file mode 100644 | |
21 | index 0000000..e4cb285 | |
22 | --- /dev/null | |
23 | +++ b/include/net/flow_keys.h | |
24 | @@ -0,0 +1,15 @@ | |
25 | +#ifndef _NET_FLOW_KEYS_H | |
26 | +#define _NET_FLOW_KEYS_H | |
27 | + | |
28 | +struct flow_keys { | |
29 | + __be32 src; | |
30 | + __be32 dst; | |
31 | + union { | |
32 | + __be32 ports; | |
33 | + __be16 port16[2]; | |
34 | + }; | |
35 | + u8 ip_proto; | |
36 | +}; | |
37 | + | |
38 | +extern bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow); | |
39 | +#endif | |
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 | |
44 | @@ -3,7 +3,7 @@ | |
45 | # | |
46 | ||
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 | |
50 | ||
51 | obj-$(CONFIG_SYSCTL) += sysctl_net_core.o | |
52 | ||
53 | diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c | |
54 | new file mode 100644 | |
55 | index 0000000..f0516d9 | |
56 | --- /dev/null | |
57 | +++ b/net/core/flow_dissector.c | |
58 | @@ -0,0 +1,134 @@ | |
59 | +#include <linux/skbuff.h> | |
60 | +#include <linux/ip.h> | |
61 | +#include <linux/ipv6.h> | |
62 | +#include <linux/if_vlan.h> | |
63 | +#include <net/ip.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> | |
68 | + | |
69 | + | |
70 | +bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) | |
71 | +{ | |
72 | + int poff, nhoff = skb_network_offset(skb); | |
73 | + u8 ip_proto; | |
74 | + __be16 proto = skb->protocol; | |
75 | + | |
76 | + memset(flow, 0, sizeof(*flow)); | |
77 | + | |
78 | +again: | |
79 | + switch (proto) { | |
80 | + case __constant_htons(ETH_P_IP): { | |
81 | + const struct iphdr *iph; | |
82 | + struct iphdr _iph; | |
83 | +ip: | |
84 | + iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); | |
85 | + if (!iph) | |
86 | + return false; | |
87 | + | |
88 | + if (ip_is_fragment(iph)) | |
89 | + ip_proto = 0; | |
90 | + else | |
91 | + ip_proto = iph->protocol; | |
92 | + flow->src = iph->saddr; | |
93 | + flow->dst = iph->daddr; | |
94 | + nhoff += iph->ihl * 4; | |
95 | + break; | |
96 | + } | |
97 | + case __constant_htons(ETH_P_IPV6): { | |
98 | + const struct ipv6hdr *iph; | |
99 | + struct ipv6hdr _iph; | |
100 | +ipv6: | |
101 | + iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); | |
102 | + if (!iph) | |
103 | + return false; | |
104 | + | |
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); | |
109 | + break; | |
110 | + } | |
111 | + case __constant_htons(ETH_P_8021Q): { | |
112 | + const struct vlan_hdr *vlan; | |
113 | + struct vlan_hdr _vlan; | |
114 | + | |
115 | + vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan); | |
116 | + if (!vlan) | |
117 | + return false; | |
118 | + | |
119 | + proto = vlan->h_vlan_encapsulated_proto; | |
120 | + nhoff += sizeof(*vlan); | |
121 | + goto again; | |
122 | + } | |
123 | + case __constant_htons(ETH_P_PPP_SES): { | |
124 | + struct { | |
125 | + struct pppoe_hdr hdr; | |
126 | + __be16 proto; | |
127 | + } *hdr, _hdr; | |
128 | + hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr); | |
129 | + if (!hdr) | |
130 | + return false; | |
131 | + proto = hdr->proto; | |
132 | + nhoff += PPPOE_SES_HLEN; | |
133 | + switch (proto) { | |
134 | + case __constant_htons(PPP_IP): | |
135 | + goto ip; | |
136 | + case __constant_htons(PPP_IPV6): | |
137 | + goto ipv6; | |
138 | + default: | |
139 | + return false; | |
140 | + } | |
141 | + } | |
142 | + default: | |
143 | + return false; | |
144 | + } | |
145 | + | |
146 | + switch (ip_proto) { | |
147 | + case IPPROTO_GRE: { | |
148 | + struct gre_hdr { | |
149 | + __be16 flags; | |
150 | + __be16 proto; | |
151 | + } *hdr, _hdr; | |
152 | + | |
153 | + hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr); | |
154 | + if (!hdr) | |
155 | + return false; | |
156 | + /* | |
157 | + * Only look inside GRE if version zero and no | |
158 | + * routing | |
159 | + */ | |
160 | + if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) { | |
161 | + proto = hdr->proto; | |
162 | + nhoff += 4; | |
163 | + if (hdr->flags & GRE_CSUM) | |
164 | + nhoff += 4; | |
165 | + if (hdr->flags & GRE_KEY) | |
166 | + nhoff += 4; | |
167 | + if (hdr->flags & GRE_SEQ) | |
168 | + nhoff += 4; | |
169 | + goto again; | |
170 | + } | |
171 | + break; | |
172 | + } | |
173 | + case IPPROTO_IPIP: | |
174 | + goto again; | |
175 | + default: | |
176 | + break; | |
177 | + } | |
178 | + | |
179 | + flow->ip_proto = ip_proto; | |
180 | + poff = proto_ports_offset(ip_proto); | |
181 | + if (poff >= 0) { | |
182 | + __be32 *ports, _ports; | |
183 | + | |
184 | + nhoff += poff; | |
185 | + ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports); | |
186 | + if (ports) | |
187 | + flow->ports = *ports; | |
188 | + } | |
189 | + | |
190 | + return true; | |
191 | +} | |
192 | +EXPORT_SYMBOL(skb_flow_dissect); | |
193 | -- | |
194 | 1.7.10 | |
195 |