aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_flow.c')
-rw-r--r--net/sched/cls_flow.c189
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
68static u32 flow_get_src(struct sk_buff *skb) 69static 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
84static u32 flow_get_dst(struct sk_buff *skb) 93static 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
100static u32 flow_get_proto(struct sk_buff *skb) 117static 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
114static u32 flow_get_proto_src(struct sk_buff *skb) 140/* helper function to get either src or dst port */
141static __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
156static u32 flow_get_proto_dst(struct sk_buff *skb) 181static 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); 191static 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
239static u32 flow_get_nfct_src(struct sk_buff *skb) 242static 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 }
247fallback: 250fallback:
248 return flow_get_src(skb); 251 return flow_get_src(skb, nhoff);
249} 252}
250 253
251static u32 flow_get_nfct_dst(struct sk_buff *skb) 254static 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 }
259fallback: 262fallback:
260 return flow_get_dst(skb); 263 return flow_get_dst(skb, nhoff);
261} 264}
262 265
263static u32 flow_get_nfct_proto_src(struct sk_buff *skb) 266static 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));
266fallback: 269fallback:
267 return flow_get_proto_src(skb); 270 return flow_get_proto_src(skb, nhoff);
268} 271}
269 272
270static u32 flow_get_nfct_proto_dst(struct sk_buff *skb) 273static 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));
273fallback: 276fallback:
274 return flow_get_proto_dst(skb); 277 return flow_get_proto_dst(skb, nhoff);
275} 278}
276 279
277static u32 flow_get_rtclassid(const struct sk_buff *skb) 280static u32 flow_get_rtclassid(const struct sk_buff *skb)
@@ -313,17 +316,19 @@ static u32 flow_get_rxhash(struct sk_buff *skb)
313 316
314static u32 flow_key_get(struct sk_buff *skb, int key) 317static 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: