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