aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-10-23 13:59:41 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-24 18:40:14 -0400
commit859c20123a6f4bac3fad6506f224908834fe3f68 (patch)
tree61c166abfc00e492e94a0e877c819c8b91fdc846 /net/sched
parent59445b6b1f90b97c4e28062b96306bacfa4fb170 (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')
-rw-r--r--net/sched/cls_flow.c188
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
68static u32 flow_get_src(struct sk_buff *skb) 68static 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
84static u32 flow_get_dst(struct sk_buff *skb) 92static 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
100static u32 flow_get_proto(struct sk_buff *skb) 116static 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
114static u32 flow_get_proto_src(struct sk_buff *skb) 139/* helper function to get either src or dst port */
140static __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
156static u32 flow_get_proto_dst(struct sk_buff *skb) 180static 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); 190static 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
239static u32 flow_get_nfct_src(struct sk_buff *skb) 241static 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 }
247fallback: 249fallback:
248 return flow_get_src(skb); 250 return flow_get_src(skb, nhoff);
249} 251}
250 252
251static u32 flow_get_nfct_dst(struct sk_buff *skb) 253static 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 }
259fallback: 261fallback:
260 return flow_get_dst(skb); 262 return flow_get_dst(skb, nhoff);
261} 263}
262 264
263static u32 flow_get_nfct_proto_src(struct sk_buff *skb) 265static 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));
266fallback: 268fallback:
267 return flow_get_proto_src(skb); 269 return flow_get_proto_src(skb, nhoff);
268} 270}
269 271
270static u32 flow_get_nfct_proto_dst(struct sk_buff *skb) 272static 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));
273fallback: 275fallback:
274 return flow_get_proto_dst(skb); 276 return flow_get_proto_dst(skb, nhoff);
275} 277}
276 278
277static u32 flow_get_rtclassid(const struct sk_buff *skb) 279static u32 flow_get_rtclassid(const struct sk_buff *skb)
@@ -313,17 +315,19 @@ static u32 flow_get_rxhash(struct sk_buff *skb)
313 315
314static u32 flow_key_get(struct sk_buff *skb, int key) 316static 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: