diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-11-28 00:24:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-28 19:09:28 -0500 |
commit | 6bd2a9af17cc3b153de45390b54c7d64a773beee (patch) | |
tree | 08ca6fafec7181b54bfc2c50ca4706dd7400ccbb /net/sched/cls_flow.c | |
parent | 4504b8613b6c65d7787a434f8dcf7901bfe3983d (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.c | 180 |
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 | ||
69 | static u32 flow_get_src(const struct sk_buff *skb, int nhoff) | 71 | static 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 | ||
93 | static u32 flow_get_dst(const struct sk_buff *skb, int nhoff) | 78 | static 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 | ||
117 | static u32 flow_get_proto(const struct sk_buff *skb, int nhoff) | 85 | static 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 */ | 90 | static u32 flow_get_proto_src(const struct sk_buff *skb, const struct flow_keys *flow) |
141 | static __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 | |||
181 | static 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 | ||
191 | static u32 flow_get_proto_dst(const struct sk_buff *skb, int nhoff) | 98 | static 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 | ||
242 | static u32 flow_get_nfct_src(const struct sk_buff *skb, int nhoff) | 147 | static 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 | } |
250 | fallback: | 155 | fallback: |
251 | return flow_get_src(skb, nhoff); | 156 | return flow_get_src(skb, flow); |
252 | } | 157 | } |
253 | 158 | ||
254 | static u32 flow_get_nfct_dst(const struct sk_buff *skb, int nhoff) | 159 | static 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 | } |
262 | fallback: | 167 | fallback: |
263 | return flow_get_dst(skb, nhoff); | 168 | return flow_get_dst(skb, flow); |
264 | } | 169 | } |
265 | 170 | ||
266 | static u32 flow_get_nfct_proto_src(const struct sk_buff *skb, int nhoff) | 171 | static 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)); |
269 | fallback: | 174 | fallback: |
270 | return flow_get_proto_src(skb, nhoff); | 175 | return flow_get_proto_src(skb, flow); |
271 | } | 176 | } |
272 | 177 | ||
273 | static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb, int nhoff) | 178 | static 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)); |
276 | fallback: | 181 | fallback: |
277 | return flow_get_proto_dst(skb, nhoff); | 182 | return flow_get_proto_dst(skb, flow); |
278 | } | 183 | } |
279 | 184 | ||
280 | static u32 flow_get_rtclassid(const struct sk_buff *skb) | 185 | static 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 | ||
317 | static u32 flow_key_get(struct sk_buff *skb, int key) | 222 | static 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 | |||
364 | static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp, | 277 | static 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) |