]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/linux-3.2-codel/0000-net-introduce-skb_flow_dissect.patch
codel: Enable fq_codel on all devices.
[people/teissler/ipfire-2.x.git] / src / patches / linux-3.2-codel / 0000-net-introduce-skb_flow_dissect.patch
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