diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-10-23 13:59:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-24 18:40:14 -0400 |
commit | 859c20123a6f4bac3fad6506f224908834fe3f68 (patch) | |
tree | 61c166abfc00e492e94a0e877c819c8b91fdc846 /net/sched/cls_flow.c | |
parent | 59445b6b1f90b97c4e28062b96306bacfa4fb170 (diff) |
net_sched: cls_flow: use skb_header_pointer()
Dan Siemon would like to add tunnelling support to cls_flow
This preliminary patch introduces use of skb_header_pointer() to help
this task, while avoiding skb head reallocation because of deep packet
inspection.
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 | 188 |
1 files changed, 96 insertions, 92 deletions
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 6994214db8f8..9e087d885675 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
@@ -65,132 +65,134 @@ static inline u32 addr_fold(void *addr) | |||
65 | return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); | 65 | return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); |
66 | } | 66 | } |
67 | 67 | ||
68 | static u32 flow_get_src(struct sk_buff *skb) | 68 | static u32 flow_get_src(const struct sk_buff *skb, int nhoff) |
69 | { | 69 | { |
70 | __be32 *data = NULL, hdata; | ||
71 | |||
70 | switch (skb->protocol) { | 72 | switch (skb->protocol) { |
71 | case htons(ETH_P_IP): | 73 | case htons(ETH_P_IP): |
72 | if (pskb_network_may_pull(skb, sizeof(struct iphdr))) | 74 | data = skb_header_pointer(skb, |
73 | return ntohl(ip_hdr(skb)->saddr); | 75 | nhoff + offsetof(struct iphdr, |
76 | saddr), | ||
77 | 4, &hdata); | ||
74 | break; | 78 | break; |
75 | case htons(ETH_P_IPV6): | 79 | case htons(ETH_P_IPV6): |
76 | if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) | 80 | data = skb_header_pointer(skb, |
77 | return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); | 81 | nhoff + offsetof(struct ipv6hdr, |
82 | saddr.s6_addr32[3]), | ||
83 | 4, &hdata); | ||
78 | break; | 84 | break; |
79 | } | 85 | } |
80 | 86 | ||
87 | if (data) | ||
88 | return ntohl(*data); | ||
81 | return addr_fold(skb->sk); | 89 | return addr_fold(skb->sk); |
82 | } | 90 | } |
83 | 91 | ||
84 | static u32 flow_get_dst(struct sk_buff *skb) | 92 | static u32 flow_get_dst(const struct sk_buff *skb, int nhoff) |
85 | { | 93 | { |
94 | __be32 *data = NULL, hdata; | ||
95 | |||
86 | switch (skb->protocol) { | 96 | switch (skb->protocol) { |
87 | case htons(ETH_P_IP): | 97 | case htons(ETH_P_IP): |
88 | if (pskb_network_may_pull(skb, sizeof(struct iphdr))) | 98 | data = skb_header_pointer(skb, |
89 | return ntohl(ip_hdr(skb)->daddr); | 99 | nhoff + offsetof(struct iphdr, |
100 | daddr), | ||
101 | 4, &hdata); | ||
90 | break; | 102 | break; |
91 | case htons(ETH_P_IPV6): | 103 | case htons(ETH_P_IPV6): |
92 | if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) | 104 | data = skb_header_pointer(skb, |
93 | return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); | 105 | nhoff + offsetof(struct ipv6hdr, |
106 | daddr.s6_addr32[3]), | ||
107 | 4, &hdata); | ||
94 | break; | 108 | break; |
95 | } | 109 | } |
96 | 110 | ||
111 | if (data) | ||
112 | return ntohl(*data); | ||
97 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | 113 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; |
98 | } | 114 | } |
99 | 115 | ||
100 | static u32 flow_get_proto(struct sk_buff *skb) | 116 | static u32 flow_get_proto(const struct sk_buff *skb, int nhoff) |
101 | { | 117 | { |
118 | __u8 *data = NULL, hdata; | ||
119 | |||
102 | switch (skb->protocol) { | 120 | switch (skb->protocol) { |
103 | case htons(ETH_P_IP): | 121 | case htons(ETH_P_IP): |
104 | return pskb_network_may_pull(skb, sizeof(struct iphdr)) ? | 122 | data = skb_header_pointer(skb, |
105 | ip_hdr(skb)->protocol : 0; | 123 | nhoff + offsetof(struct iphdr, |
124 | protocol), | ||
125 | 1, &hdata); | ||
126 | break; | ||
106 | case htons(ETH_P_IPV6): | 127 | case htons(ETH_P_IPV6): |
107 | return pskb_network_may_pull(skb, sizeof(struct ipv6hdr)) ? | 128 | data = skb_header_pointer(skb, |
108 | ipv6_hdr(skb)->nexthdr : 0; | 129 | nhoff + offsetof(struct ipv6hdr, |
109 | default: | 130 | nexthdr), |
110 | return 0; | 131 | 1, &hdata); |
132 | break; | ||
111 | } | 133 | } |
134 | if (data) | ||
135 | return *data; | ||
136 | return 0; | ||
112 | } | 137 | } |
113 | 138 | ||
114 | static u32 flow_get_proto_src(struct sk_buff *skb) | 139 | /* helper function to get either src or dst port */ |
140 | static __be16 *flow_get_proto_common(const struct sk_buff *skb, int nhoff, | ||
141 | __be16 *_port, int dst) | ||
115 | { | 142 | { |
143 | __be16 *port = NULL; | ||
144 | int poff; | ||
145 | |||
116 | switch (skb->protocol) { | 146 | switch (skb->protocol) { |
117 | case htons(ETH_P_IP): { | 147 | case htons(ETH_P_IP): { |
118 | struct iphdr *iph; | 148 | struct iphdr *iph, _iph; |
119 | int poff; | ||
120 | 149 | ||
121 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 150 | iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); |
151 | if (!iph) | ||
122 | break; | 152 | break; |
123 | iph = ip_hdr(skb); | ||
124 | if (ip_is_fragment(iph)) | 153 | if (ip_is_fragment(iph)) |
125 | break; | 154 | break; |
126 | poff = proto_ports_offset(iph->protocol); | 155 | poff = proto_ports_offset(iph->protocol); |
127 | if (poff >= 0 && | 156 | if (poff >= 0) |
128 | pskb_network_may_pull(skb, iph->ihl * 4 + 2 + poff)) { | 157 | port = skb_header_pointer(skb, |
129 | iph = ip_hdr(skb); | 158 | nhoff + iph->ihl * 4 + poff + dst, |
130 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + | 159 | sizeof(*_port), _port); |
131 | poff)); | ||
132 | } | ||
133 | break; | 160 | break; |
134 | } | 161 | } |
135 | case htons(ETH_P_IPV6): { | 162 | case htons(ETH_P_IPV6): { |
136 | struct ipv6hdr *iph; | 163 | struct ipv6hdr *iph, _iph; |
137 | int poff; | ||
138 | 164 | ||
139 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 165 | iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); |
166 | if (!iph) | ||
140 | break; | 167 | break; |
141 | iph = ipv6_hdr(skb); | ||
142 | poff = proto_ports_offset(iph->nexthdr); | 168 | poff = proto_ports_offset(iph->nexthdr); |
143 | if (poff >= 0 && | 169 | if (poff >= 0) |
144 | pskb_network_may_pull(skb, sizeof(*iph) + poff + 2)) { | 170 | port = skb_header_pointer(skb, |
145 | iph = ipv6_hdr(skb); | 171 | nhoff + sizeof(*iph) + poff + dst, |
146 | return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) + | 172 | sizeof(*_port), _port); |
147 | poff)); | ||
148 | } | ||
149 | break; | 173 | break; |
150 | } | 174 | } |
151 | } | 175 | } |
152 | 176 | ||
153 | return addr_fold(skb->sk); | 177 | return port; |
154 | } | 178 | } |
155 | 179 | ||
156 | static u32 flow_get_proto_dst(struct sk_buff *skb) | 180 | static u32 flow_get_proto_src(const struct sk_buff *skb, int nhoff) |
157 | { | 181 | { |
158 | switch (skb->protocol) { | 182 | __be16 _port, *port = flow_get_proto_common(skb, nhoff, &_port, 0); |
159 | case htons(ETH_P_IP): { | ||
160 | struct iphdr *iph; | ||
161 | int poff; | ||
162 | 183 | ||
163 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 184 | if (port) |
164 | break; | 185 | return ntohs(*port); |
165 | iph = ip_hdr(skb); | ||
166 | if (ip_is_fragment(iph)) | ||
167 | break; | ||
168 | poff = proto_ports_offset(iph->protocol); | ||
169 | if (poff >= 0 && | ||
170 | pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) { | ||
171 | iph = ip_hdr(skb); | ||
172 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + | ||
173 | 2 + poff)); | ||
174 | } | ||
175 | break; | ||
176 | } | ||
177 | case htons(ETH_P_IPV6): { | ||
178 | struct ipv6hdr *iph; | ||
179 | int poff; | ||
180 | 186 | ||
181 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 187 | return addr_fold(skb->sk); |
182 | break; | 188 | } |
183 | iph = ipv6_hdr(skb); | 189 | |
184 | poff = proto_ports_offset(iph->nexthdr); | 190 | static u32 flow_get_proto_dst(const struct sk_buff *skb, int nhoff) |
185 | if (poff >= 0 && | 191 | { |
186 | pskb_network_may_pull(skb, sizeof(*iph) + poff + 4)) { | 192 | __be16 _port, *port = flow_get_proto_common(skb, nhoff, &_port, 2); |
187 | iph = ipv6_hdr(skb); | 193 | |
188 | return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) + | 194 | if (port) |
189 | poff + 2)); | 195 | return ntohs(*port); |
190 | } | ||
191 | break; | ||
192 | } | ||
193 | } | ||
194 | 196 | ||
195 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | 197 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; |
196 | } | 198 | } |
@@ -223,7 +225,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb) | |||
223 | #define CTTUPLE(skb, member) \ | 225 | #define CTTUPLE(skb, member) \ |
224 | ({ \ | 226 | ({ \ |
225 | enum ip_conntrack_info ctinfo; \ | 227 | enum ip_conntrack_info ctinfo; \ |
226 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); \ | 228 | const struct nf_conn *ct = nf_ct_get(skb, &ctinfo); \ |
227 | if (ct == NULL) \ | 229 | if (ct == NULL) \ |
228 | goto fallback; \ | 230 | goto fallback; \ |
229 | ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.member; \ | 231 | ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.member; \ |
@@ -236,7 +238,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb) | |||
236 | }) | 238 | }) |
237 | #endif | 239 | #endif |
238 | 240 | ||
239 | static u32 flow_get_nfct_src(struct sk_buff *skb) | 241 | static u32 flow_get_nfct_src(const struct sk_buff *skb, int nhoff) |
240 | { | 242 | { |
241 | switch (skb->protocol) { | 243 | switch (skb->protocol) { |
242 | case htons(ETH_P_IP): | 244 | case htons(ETH_P_IP): |
@@ -245,10 +247,10 @@ static u32 flow_get_nfct_src(struct sk_buff *skb) | |||
245 | return ntohl(CTTUPLE(skb, src.u3.ip6[3])); | 247 | return ntohl(CTTUPLE(skb, src.u3.ip6[3])); |
246 | } | 248 | } |
247 | fallback: | 249 | fallback: |
248 | return flow_get_src(skb); | 250 | return flow_get_src(skb, nhoff); |
249 | } | 251 | } |
250 | 252 | ||
251 | static u32 flow_get_nfct_dst(struct sk_buff *skb) | 253 | static u32 flow_get_nfct_dst(const struct sk_buff *skb, int nhoff) |
252 | { | 254 | { |
253 | switch (skb->protocol) { | 255 | switch (skb->protocol) { |
254 | case htons(ETH_P_IP): | 256 | case htons(ETH_P_IP): |
@@ -257,21 +259,21 @@ static u32 flow_get_nfct_dst(struct sk_buff *skb) | |||
257 | return ntohl(CTTUPLE(skb, dst.u3.ip6[3])); | 259 | return ntohl(CTTUPLE(skb, dst.u3.ip6[3])); |
258 | } | 260 | } |
259 | fallback: | 261 | fallback: |
260 | return flow_get_dst(skb); | 262 | return flow_get_dst(skb, nhoff); |
261 | } | 263 | } |
262 | 264 | ||
263 | static u32 flow_get_nfct_proto_src(struct sk_buff *skb) | 265 | static u32 flow_get_nfct_proto_src(const struct sk_buff *skb, int nhoff) |
264 | { | 266 | { |
265 | return ntohs(CTTUPLE(skb, src.u.all)); | 267 | return ntohs(CTTUPLE(skb, src.u.all)); |
266 | fallback: | 268 | fallback: |
267 | return flow_get_proto_src(skb); | 269 | return flow_get_proto_src(skb, nhoff); |
268 | } | 270 | } |
269 | 271 | ||
270 | static u32 flow_get_nfct_proto_dst(struct sk_buff *skb) | 272 | static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb, int nhoff) |
271 | { | 273 | { |
272 | return ntohs(CTTUPLE(skb, dst.u.all)); | 274 | return ntohs(CTTUPLE(skb, dst.u.all)); |
273 | fallback: | 275 | fallback: |
274 | return flow_get_proto_dst(skb); | 276 | return flow_get_proto_dst(skb, nhoff); |
275 | } | 277 | } |
276 | 278 | ||
277 | static u32 flow_get_rtclassid(const struct sk_buff *skb) | 279 | static u32 flow_get_rtclassid(const struct sk_buff *skb) |
@@ -313,17 +315,19 @@ static u32 flow_get_rxhash(struct sk_buff *skb) | |||
313 | 315 | ||
314 | static u32 flow_key_get(struct sk_buff *skb, int key) | 316 | static u32 flow_key_get(struct sk_buff *skb, int key) |
315 | { | 317 | { |
318 | int nhoff = skb_network_offset(skb); | ||
319 | |||
316 | switch (key) { | 320 | switch (key) { |
317 | case FLOW_KEY_SRC: | 321 | case FLOW_KEY_SRC: |
318 | return flow_get_src(skb); | 322 | return flow_get_src(skb, nhoff); |
319 | case FLOW_KEY_DST: | 323 | case FLOW_KEY_DST: |
320 | return flow_get_dst(skb); | 324 | return flow_get_dst(skb, nhoff); |
321 | case FLOW_KEY_PROTO: | 325 | case FLOW_KEY_PROTO: |
322 | return flow_get_proto(skb); | 326 | return flow_get_proto(skb, nhoff); |
323 | case FLOW_KEY_PROTO_SRC: | 327 | case FLOW_KEY_PROTO_SRC: |
324 | return flow_get_proto_src(skb); | 328 | return flow_get_proto_src(skb, nhoff); |
325 | case FLOW_KEY_PROTO_DST: | 329 | case FLOW_KEY_PROTO_DST: |
326 | return flow_get_proto_dst(skb); | 330 | return flow_get_proto_dst(skb, nhoff); |
327 | case FLOW_KEY_IIF: | 331 | case FLOW_KEY_IIF: |
328 | return flow_get_iif(skb); | 332 | return flow_get_iif(skb); |
329 | case FLOW_KEY_PRIORITY: | 333 | case FLOW_KEY_PRIORITY: |
@@ -333,13 +337,13 @@ static u32 flow_key_get(struct sk_buff *skb, int key) | |||
333 | case FLOW_KEY_NFCT: | 337 | case FLOW_KEY_NFCT: |
334 | return flow_get_nfct(skb); | 338 | return flow_get_nfct(skb); |
335 | case FLOW_KEY_NFCT_SRC: | 339 | case FLOW_KEY_NFCT_SRC: |
336 | return flow_get_nfct_src(skb); | 340 | return flow_get_nfct_src(skb, nhoff); |
337 | case FLOW_KEY_NFCT_DST: | 341 | case FLOW_KEY_NFCT_DST: |
338 | return flow_get_nfct_dst(skb); | 342 | return flow_get_nfct_dst(skb, nhoff); |
339 | case FLOW_KEY_NFCT_PROTO_SRC: | 343 | case FLOW_KEY_NFCT_PROTO_SRC: |
340 | return flow_get_nfct_proto_src(skb); | 344 | return flow_get_nfct_proto_src(skb, nhoff); |
341 | case FLOW_KEY_NFCT_PROTO_DST: | 345 | case FLOW_KEY_NFCT_PROTO_DST: |
342 | return flow_get_nfct_proto_dst(skb); | 346 | return flow_get_nfct_proto_dst(skb, nhoff); |
343 | case FLOW_KEY_RTCLASSID: | 347 | case FLOW_KEY_RTCLASSID: |
344 | return flow_get_rtclassid(skb); | 348 | return flow_get_rtclassid(skb); |
345 | case FLOW_KEY_SKUID: | 349 | case FLOW_KEY_SKUID: |