aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_flow.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-11-28 00:24:18 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-28 19:09:28 -0500
commit6bd2a9af17cc3b153de45390b54c7d64a773beee (patch)
tree08ca6fafec7181b54bfc2c50ca4706dd7400ccbb /net/sched/cls_flow.c
parent4504b8613b6c65d7787a434f8dcf7901bfe3983d (diff)
cls_flow: use skb_flow_dissect()
Instead of using a custom flow dissector, use skb_flow_dissect() and benefit from tunnelling support. This lack of tunnelling support was mentioned by Dan Siemon. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/cls_flow.c')
-rw-r--r--net/sched/cls_flow.c180
1 files changed, 48 insertions, 132 deletions
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 7b582300d051..51ff19485e12 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -26,6 +26,8 @@
26#include <net/pkt_cls.h> 26#include <net/pkt_cls.h>
27#include <net/ip.h> 27#include <net/ip.h>
28#include <net/route.h> 28#include <net/route.h>
29#include <net/flow_keys.h>
30
29#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 31#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
30#include <net/netfilter/nf_conntrack.h> 32#include <net/netfilter/nf_conntrack.h>
31#endif 33#endif
@@ -66,134 +68,37 @@ static inline u32 addr_fold(void *addr)
66 return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); 68 return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
67} 69}
68 70
69static u32 flow_get_src(const struct sk_buff *skb, int nhoff) 71static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow)
70{ 72{
71 __be32 *data = NULL, hdata; 73 if (flow->src)
72 74 return ntohl(flow->src);
73 switch (skb->protocol) {
74 case htons(ETH_P_IP):
75 data = skb_header_pointer(skb,
76 nhoff + offsetof(struct iphdr,
77 saddr),
78 4, &hdata);
79 break;
80 case htons(ETH_P_IPV6):
81 data = skb_header_pointer(skb,
82 nhoff + offsetof(struct ipv6hdr,
83 saddr.s6_addr32[3]),
84 4, &hdata);
85 break;
86 }
87
88 if (data)
89 return ntohl(*data);
90 return addr_fold(skb->sk); 75 return addr_fold(skb->sk);
91} 76}
92 77
93static u32 flow_get_dst(const struct sk_buff *skb, int nhoff) 78static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow)
94{ 79{
95 __be32 *data = NULL, hdata; 80 if (flow->dst)
96 81 return ntohl(flow->dst);
97 switch (skb->protocol) {
98 case htons(ETH_P_IP):
99 data = skb_header_pointer(skb,
100 nhoff + offsetof(struct iphdr,
101 daddr),
102 4, &hdata);
103 break;
104 case htons(ETH_P_IPV6):
105 data = skb_header_pointer(skb,
106 nhoff + offsetof(struct ipv6hdr,
107 daddr.s6_addr32[3]),
108 4, &hdata);
109 break;
110 }
111
112 if (data)
113 return ntohl(*data);
114 return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; 82 return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
115} 83}
116 84
117static u32 flow_get_proto(const struct sk_buff *skb, int nhoff) 85static u32 flow_get_proto(const struct sk_buff *skb, const struct flow_keys *flow)
118{ 86{
119 __u8 *data = NULL, hdata; 87 return flow->ip_proto;
120
121 switch (skb->protocol) {
122 case htons(ETH_P_IP):
123 data = skb_header_pointer(skb,
124 nhoff + offsetof(struct iphdr,
125 protocol),
126 1, &hdata);
127 break;
128 case htons(ETH_P_IPV6):
129 data = skb_header_pointer(skb,
130 nhoff + offsetof(struct ipv6hdr,
131 nexthdr),
132 1, &hdata);
133 break;
134 }
135 if (data)
136 return *data;
137 return 0;
138} 88}
139 89
140/* helper function to get either src or dst port */ 90static u32 flow_get_proto_src(const struct sk_buff *skb, const struct flow_keys *flow)
141static __be16 *flow_get_proto_common(const struct sk_buff *skb, int nhoff,
142 __be16 *_port, int dst)
143{ 91{
144 __be16 *port = NULL; 92 if (flow->ports)
145 int poff; 93 return ntohs(flow->port16[0]);
146
147 switch (skb->protocol) {
148 case htons(ETH_P_IP): {
149 struct iphdr *iph, _iph;
150
151 iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
152 if (!iph)
153 break;
154 if (ip_is_fragment(iph))
155 break;
156 poff = proto_ports_offset(iph->protocol);
157 if (poff >= 0)
158 port = skb_header_pointer(skb,
159 nhoff + iph->ihl * 4 + poff + dst,
160 sizeof(*_port), _port);
161 break;
162 }
163 case htons(ETH_P_IPV6): {
164 struct ipv6hdr *iph, _iph;
165
166 iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
167 if (!iph)
168 break;
169 poff = proto_ports_offset(iph->nexthdr);
170 if (poff >= 0)
171 port = skb_header_pointer(skb,
172 nhoff + sizeof(*iph) + poff + dst,
173 sizeof(*_port), _port);
174 break;
175 }
176 }
177
178 return port;
179}
180
181static u32 flow_get_proto_src(const struct sk_buff *skb, int nhoff)
182{
183 __be16 _port, *port = flow_get_proto_common(skb, nhoff, &_port, 0);
184
185 if (port)
186 return ntohs(*port);
187 94
188 return addr_fold(skb->sk); 95 return addr_fold(skb->sk);
189} 96}
190 97
191static u32 flow_get_proto_dst(const struct sk_buff *skb, int nhoff) 98static u32 flow_get_proto_dst(const struct sk_buff *skb, const struct flow_keys *flow)
192{ 99{
193 __be16 _port, *port = flow_get_proto_common(skb, nhoff, &_port, 2); 100 if (flow->ports)
194 101 return ntohs(flow->port16[1]);
195 if (port)
196 return ntohs(*port);
197 102
198 return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; 103 return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
199} 104}
@@ -239,7 +144,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb)
239}) 144})
240#endif 145#endif
241 146
242static u32 flow_get_nfct_src(const struct sk_buff *skb, int nhoff) 147static u32 flow_get_nfct_src(const struct sk_buff *skb, const struct flow_keys *flow)
243{ 148{
244 switch (skb->protocol) { 149 switch (skb->protocol) {
245 case htons(ETH_P_IP): 150 case htons(ETH_P_IP):
@@ -248,10 +153,10 @@ static u32 flow_get_nfct_src(const struct sk_buff *skb, int nhoff)
248 return ntohl(CTTUPLE(skb, src.u3.ip6[3])); 153 return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
249 } 154 }
250fallback: 155fallback:
251 return flow_get_src(skb, nhoff); 156 return flow_get_src(skb, flow);
252} 157}
253 158
254static u32 flow_get_nfct_dst(const struct sk_buff *skb, int nhoff) 159static u32 flow_get_nfct_dst(const struct sk_buff *skb, const struct flow_keys *flow)
255{ 160{
256 switch (skb->protocol) { 161 switch (skb->protocol) {
257 case htons(ETH_P_IP): 162 case htons(ETH_P_IP):
@@ -260,21 +165,21 @@ static u32 flow_get_nfct_dst(const struct sk_buff *skb, int nhoff)
260 return ntohl(CTTUPLE(skb, dst.u3.ip6[3])); 165 return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
261 } 166 }
262fallback: 167fallback:
263 return flow_get_dst(skb, nhoff); 168 return flow_get_dst(skb, flow);
264} 169}
265 170
266static u32 flow_get_nfct_proto_src(const struct sk_buff *skb, int nhoff) 171static u32 flow_get_nfct_proto_src(const struct sk_buff *skb, const struct flow_keys *flow)
267{ 172{
268 return ntohs(CTTUPLE(skb, src.u.all)); 173 return ntohs(CTTUPLE(skb, src.u.all));
269fallback: 174fallback:
270 return flow_get_proto_src(skb, nhoff); 175 return flow_get_proto_src(skb, flow);
271} 176}
272 177
273static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb, int nhoff) 178static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb, const struct flow_keys *flow)
274{ 179{
275 return ntohs(CTTUPLE(skb, dst.u.all)); 180 return ntohs(CTTUPLE(skb, dst.u.all));
276fallback: 181fallback:
277 return flow_get_proto_dst(skb, nhoff); 182 return flow_get_proto_dst(skb, flow);
278} 183}
279 184
280static u32 flow_get_rtclassid(const struct sk_buff *skb) 185static u32 flow_get_rtclassid(const struct sk_buff *skb)
@@ -314,21 +219,19 @@ static u32 flow_get_rxhash(struct sk_buff *skb)
314 return skb_get_rxhash(skb); 219 return skb_get_rxhash(skb);
315} 220}
316 221
317static u32 flow_key_get(struct sk_buff *skb, int key) 222static u32 flow_key_get(struct sk_buff *skb, int key, struct flow_keys *flow)
318{ 223{
319 int nhoff = skb_network_offset(skb);
320
321 switch (key) { 224 switch (key) {
322 case FLOW_KEY_SRC: 225 case FLOW_KEY_SRC:
323 return flow_get_src(skb, nhoff); 226 return flow_get_src(skb, flow);
324 case FLOW_KEY_DST: 227 case FLOW_KEY_DST:
325 return flow_get_dst(skb, nhoff); 228 return flow_get_dst(skb, flow);
326 case FLOW_KEY_PROTO: 229 case FLOW_KEY_PROTO:
327 return flow_get_proto(skb, nhoff); 230 return flow_get_proto(skb, flow);
328 case FLOW_KEY_PROTO_SRC: 231 case FLOW_KEY_PROTO_SRC:
329 return flow_get_proto_src(skb, nhoff); 232 return flow_get_proto_src(skb, flow);
330 case FLOW_KEY_PROTO_DST: 233 case FLOW_KEY_PROTO_DST:
331 return flow_get_proto_dst(skb, nhoff); 234 return flow_get_proto_dst(skb, flow);
332 case FLOW_KEY_IIF: 235 case FLOW_KEY_IIF:
333 return flow_get_iif(skb); 236 return flow_get_iif(skb);
334 case FLOW_KEY_PRIORITY: 237 case FLOW_KEY_PRIORITY:
@@ -338,13 +241,13 @@ static u32 flow_key_get(struct sk_buff *skb, int key)
338 case FLOW_KEY_NFCT: 241 case FLOW_KEY_NFCT:
339 return flow_get_nfct(skb); 242 return flow_get_nfct(skb);
340 case FLOW_KEY_NFCT_SRC: 243 case FLOW_KEY_NFCT_SRC:
341 return flow_get_nfct_src(skb, nhoff); 244 return flow_get_nfct_src(skb, flow);
342 case FLOW_KEY_NFCT_DST: 245 case FLOW_KEY_NFCT_DST:
343 return flow_get_nfct_dst(skb, nhoff); 246 return flow_get_nfct_dst(skb, flow);
344 case FLOW_KEY_NFCT_PROTO_SRC: 247 case FLOW_KEY_NFCT_PROTO_SRC:
345 return flow_get_nfct_proto_src(skb, nhoff); 248 return flow_get_nfct_proto_src(skb, flow);
346 case FLOW_KEY_NFCT_PROTO_DST: 249 case FLOW_KEY_NFCT_PROTO_DST:
347 return flow_get_nfct_proto_dst(skb, nhoff); 250 return flow_get_nfct_proto_dst(skb, flow);
348 case FLOW_KEY_RTCLASSID: 251 case FLOW_KEY_RTCLASSID:
349 return flow_get_rtclassid(skb); 252 return flow_get_rtclassid(skb);
350 case FLOW_KEY_SKUID: 253 case FLOW_KEY_SKUID:
@@ -361,6 +264,16 @@ static u32 flow_key_get(struct sk_buff *skb, int key)
361 } 264 }
362} 265}
363 266
267#define FLOW_KEYS_NEEDED ((1 << FLOW_KEY_SRC) | \
268 (1 << FLOW_KEY_DST) | \
269 (1 << FLOW_KEY_PROTO) | \
270 (1 << FLOW_KEY_PROTO_SRC) | \
271 (1 << FLOW_KEY_PROTO_DST) | \
272 (1 << FLOW_KEY_NFCT_SRC) | \
273 (1 << FLOW_KEY_NFCT_DST) | \
274 (1 << FLOW_KEY_NFCT_PROTO_SRC) | \
275 (1 << FLOW_KEY_NFCT_PROTO_DST))
276
364static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp, 277static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp,
365 struct tcf_result *res) 278 struct tcf_result *res)
366{ 279{
@@ -373,16 +286,19 @@ static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp,
373 286
374 list_for_each_entry(f, &head->filters, list) { 287 list_for_each_entry(f, &head->filters, list) {
375 u32 keys[f->nkeys]; 288 u32 keys[f->nkeys];
289 struct flow_keys flow_keys;
376 290
377 if (!tcf_em_tree_match(skb, &f->ematches, NULL)) 291 if (!tcf_em_tree_match(skb, &f->ematches, NULL))
378 continue; 292 continue;
379 293
380 keymask = f->keymask; 294 keymask = f->keymask;
295 if (keymask & FLOW_KEYS_NEEDED)
296 skb_flow_dissect(skb, &flow_keys);
381 297
382 for (n = 0; n < f->nkeys; n++) { 298 for (n = 0; n < f->nkeys; n++) {
383 key = ffs(keymask) - 1; 299 key = ffs(keymask) - 1;
384 keymask &= ~(1 << key); 300 keymask &= ~(1 << key);
385 keys[n] = flow_key_get(skb, key); 301 keys[n] = flow_key_get(skb, key, &flow_keys);
386 } 302 }
387 303
388 if (f->mode == FLOW_MODE_HASH) 304 if (f->mode == FLOW_MODE_HASH)