Blame view

net/sched/cls_rsvp.h 14.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  /*
   * net/sched/cls_rsvp.h	Template file for RSVPv[46] classifiers.
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   */
  
  /*
     Comparing to general packet classification problem,
     RSVP needs only sevaral relatively simple rules:
  
     * (dst, protocol) are always specified,
       so that we are able to hash them.
     * src may be exact, or may be wildcard, so that
       we can keep a hash table plus one wildcard entry.
     * source port (or flow label) is important only if src is given.
  
     IMPLEMENTATION.
  
     We use a two level hash table: The top level is keyed by
     destination address and protocol ID, every bucket contains a list
     of "rsvp sessions", identified by destination address, protocol and
     DPI(="Destination Port ID"): triple (key, mask, offset).
  
     Every bucket has a smaller hash table keyed by source address
     (cf. RSVP flowspec) and one wildcard entry for wildcard reservations.
     Every bucket is again a list of "RSVP flows", selected by
     source address and SPI(="Source Port ID" here rather than
     "security parameter index"): triple (key, mask, offset).
  
  
     NOTE 1. All the packets with IPv6 extension headers (but AH and ESP)
     and all fragmented packets go to the best-effort traffic class.
  
  
     NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires
     only one "Generalized Port Identifier". So that for classic
     ah, esp (and udp,tcp) both *pi should coincide or one of them
     should be wildcard.
  
     At first sight, this redundancy is just a waste of CPU
     resources. But DPI and SPI add the possibility to assign different
     priorities to GPIs. Look also at note 4 about tunnels below.
  
  
     NOTE 3. One complication is the case of tunneled packets.
     We implement it as following: if the first lookup
     matches a special session with "tunnelhdr" value not zero,
     flowid doesn't contain the true flow ID, but the tunnel ID (1...255).
     In this case, we pull tunnelhdr bytes and restart lookup
     with tunnel ID added to the list of keys. Simple and stupid 8)8)
     It's enough for PIMREG and IPIP.
  
  
     NOTE 4. Two GPIs make it possible to parse even GRE packets.
     F.e. DPI can select ETH_P_IP (and necessary flags to make
     tunnelhdr correct) in GRE protocol field and SPI matches
     GRE key. Is it not nice? 8)8)
  
  
     Well, as result, despite its simplicity, we get a pretty
     powerful classification engine.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

cc7ec456f   Eric Dumazet   net_sched: cleanups
68
  struct rsvp_head {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
  	u32			tmap[256/32];
  	u32			hgenerator;
  	u8			tgenerator;
  	struct rsvp_session	*ht[256];
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
74
  struct rsvp_session {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	struct rsvp_session	*next;
66c6f529c   Al Viro   [NET]: net/sched ...
76
  	__be32			dst[RSVP_DST_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
  	struct tc_rsvp_gpi 	dpi;
  	u8			protocol;
  	u8			tunnelid;
  	/* 16 (src,sport) hash slots, and one wildcard source slot */
cc7ec456f   Eric Dumazet   net_sched: cleanups
81
  	struct rsvp_filter	*ht[16 + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
83
  struct rsvp_filter {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  	struct rsvp_filter	*next;
66c6f529c   Al Viro   [NET]: net/sched ...
85
  	__be32			src[RSVP_DST_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
  	struct tc_rsvp_gpi	spi;
  	u8			tunnelhdr;
  
  	struct tcf_result	res;
  	struct tcf_exts		exts;
  
  	u32			handle;
  	struct rsvp_session	*sess;
  };
cc7ec456f   Eric Dumazet   net_sched: cleanups
95
  static inline unsigned int hash_dst(__be32 *dst, u8 protocol, u8 tunnelid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
97
  	unsigned int h = (__force __u32)dst[RSVP_DST_LEN - 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
  	h ^= h>>16;
  	h ^= h>>8;
  	return (h ^ protocol ^ tunnelid) & 0xFF;
  }
cc7ec456f   Eric Dumazet   net_sched: cleanups
102
  static inline unsigned int hash_src(__be32 *src)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
104
  	unsigned int h = (__force __u32)src[RSVP_DST_LEN-1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  	h ^= h>>16;
  	h ^= h>>8;
  	h ^= h>>4;
  	return h & 0xF;
  }
  
  static struct tcf_ext_map rsvp_ext_map = {
  	.police = TCA_RSVP_POLICE,
  	.action = TCA_RSVP_ACT
  };
  
  #define RSVP_APPLY_RESULT()				\
  {							\
  	int r = tcf_exts_exec(skb, &f->exts, res);	\
  	if (r < 0)					\
  		continue;				\
  	else if (r > 0)					\
  		return r;				\
  }
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
124

dc7f9f6e8   Eric Dumazet   net: sched: const...
125
  static int rsvp_classify(struct sk_buff *skb, const struct tcf_proto *tp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  			 struct tcf_result *res)
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
128
  	struct rsvp_session **sht = ((struct rsvp_head *)tp->root)->ht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  	struct rsvp_session *s;
  	struct rsvp_filter *f;
cc7ec456f   Eric Dumazet   net_sched: cleanups
131
  	unsigned int h1, h2;
66c6f529c   Al Viro   [NET]: net/sched ...
132
  	__be32 *dst, *src;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
  	u8 protocol;
  	u8 tunnelid = 0;
  	u8 *xprt;
  #if RSVP_DST_LEN == 4
12dc96d16   Changli Gao   cls_rsvp: add san...
137
138
139
140
141
  	struct ipv6hdr *nhptr;
  
  	if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
  		return -1;
  	nhptr = ipv6_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  #else
12dc96d16   Changli Gao   cls_rsvp: add san...
143
144
145
146
147
  	struct iphdr *nhptr;
  
  	if (!pskb_network_may_pull(skb, sizeof(*nhptr)))
  		return -1;
  	nhptr = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
153
154
155
  #endif
  
  restart:
  
  #if RSVP_DST_LEN == 4
  	src = &nhptr->saddr.s6_addr32[0];
  	dst = &nhptr->daddr.s6_addr32[0];
  	protocol = nhptr->nexthdr;
cc7ec456f   Eric Dumazet   net_sched: cleanups
156
  	xprt = ((u8 *)nhptr) + sizeof(struct ipv6hdr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
  #else
  	src = &nhptr->saddr;
  	dst = &nhptr->daddr;
  	protocol = nhptr->protocol;
cc7ec456f   Eric Dumazet   net_sched: cleanups
161
  	xprt = ((u8 *)nhptr) + (nhptr->ihl<<2);
56f8a75c1   Paul Gortmaker   ip: introduce ip_...
162
  	if (ip_is_fragment(nhptr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
  		return -1;
  #endif
  
  	h1 = hash_dst(dst, protocol, tunnelid);
  	h2 = hash_src(src);
  
  	for (s = sht[h1]; s; s = s->next) {
cc7ec456f   Eric Dumazet   net_sched: cleanups
170
  		if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN - 1] &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		    protocol == s->protocol &&
f64f9e719   Joe Perches   net: Move && and ...
172
  		    !(s->dpi.mask &
cc7ec456f   Eric Dumazet   net_sched: cleanups
173
  		      (*(u32 *)(xprt + s->dpi.offset) ^ s->dpi.key)) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  #if RSVP_DST_LEN == 4
f64f9e719   Joe Perches   net: Move && and ...
175
176
177
  		    dst[0] == s->dst[0] &&
  		    dst[1] == s->dst[1] &&
  		    dst[2] == s->dst[2] &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  #endif
f64f9e719   Joe Perches   net: Move && and ...
179
  		    tunnelid == s->tunnelid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
  
  			for (f = s->ht[h2]; f; f = f->next) {
cc7ec456f   Eric Dumazet   net_sched: cleanups
182
183
  				if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN - 1] &&
  				    !(f->spi.mask & (*(u32 *)(xprt + f->spi.offset) ^ f->spi.key))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  #if RSVP_DST_LEN == 4
f64f9e719   Joe Perches   net: Move && and ...
185
186
187
188
  				    &&
  				    src[0] == f->src[0] &&
  				    src[1] == f->src[1] &&
  				    src[2] == f->src[2]
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
198
  #endif
  				    ) {
  					*res = f->res;
  					RSVP_APPLY_RESULT();
  
  matched:
  					if (f->tunnelhdr == 0)
  						return 0;
  
  					tunnelid = f->res.classid;
cc7ec456f   Eric Dumazet   net_sched: cleanups
199
  					nhptr = (void *)(xprt + f->tunnelhdr - sizeof(*nhptr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  					goto restart;
  				}
  			}
  
  			/* And wildcard bucket... */
  			for (f = s->ht[16]; f; f = f->next) {
  				*res = f->res;
  				RSVP_APPLY_RESULT();
  				goto matched;
  			}
  			return -1;
  		}
  	}
  	return -1;
  }
  
  static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle)
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
218
  	struct rsvp_session **sht = ((struct rsvp_head *)tp->root)->ht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
  	struct rsvp_session *s;
  	struct rsvp_filter *f;
cc7ec456f   Eric Dumazet   net_sched: cleanups
221
222
  	unsigned int h1 = handle & 0xFF;
  	unsigned int h2 = (handle >> 8) & 0xFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  
  	if (h2 > 16)
  		return 0;
  
  	for (s = sht[h1]; s; s = s->next) {
  		for (f = s->ht[h2]; f; f = f->next) {
  			if (f->handle == handle)
  				return (unsigned long)f;
  		}
  	}
  	return 0;
  }
  
  static void rsvp_put(struct tcf_proto *tp, unsigned long f)
  {
  }
  
  static int rsvp_init(struct tcf_proto *tp)
  {
  	struct rsvp_head *data;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
243
  	data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  	if (data) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
  		tp->root = data;
  		return 0;
  	}
  	return -ENOBUFS;
  }
cc7ec456f   Eric Dumazet   net_sched: cleanups
250
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
  {
  	tcf_unbind_filter(tp, &f->res);
  	tcf_exts_destroy(tp, &f->exts);
  	kfree(f);
  }
  
  static void rsvp_destroy(struct tcf_proto *tp)
  {
  	struct rsvp_head *data = xchg(&tp->root, NULL);
  	struct rsvp_session **sht;
  	int h1, h2;
  
  	if (data == NULL)
  		return;
  
  	sht = data->ht;
cc7ec456f   Eric Dumazet   net_sched: cleanups
268
  	for (h1 = 0; h1 < 256; h1++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
  		struct rsvp_session *s;
  
  		while ((s = sht[h1]) != NULL) {
  			sht[h1] = s->next;
cc7ec456f   Eric Dumazet   net_sched: cleanups
273
  			for (h2 = 0; h2 <= 16; h2++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  				struct rsvp_filter *f;
  
  				while ((f = s->ht[h2]) != NULL) {
  					s->ht[h2] = f->next;
  					rsvp_delete_filter(tp, f);
  				}
  			}
  			kfree(s);
  		}
  	}
  	kfree(data);
  }
  
  static int rsvp_delete(struct tcf_proto *tp, unsigned long arg)
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
289
290
  	struct rsvp_filter **fp, *f = (struct rsvp_filter *)arg;
  	unsigned int h = f->handle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
  	struct rsvp_session **sp;
  	struct rsvp_session *s = f->sess;
  	int i;
cc7ec456f   Eric Dumazet   net_sched: cleanups
294
  	for (fp = &s->ht[(h >> 8) & 0xFF]; *fp; fp = &(*fp)->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
298
299
300
301
  		if (*fp == f) {
  			tcf_tree_lock(tp);
  			*fp = f->next;
  			tcf_tree_unlock(tp);
  			rsvp_delete_filter(tp, f);
  
  			/* Strip tree */
cc7ec456f   Eric Dumazet   net_sched: cleanups
302
  			for (i = 0; i <= 16; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
  				if (s->ht[i])
  					return 0;
  
  			/* OK, session has no flows */
cc7ec456f   Eric Dumazet   net_sched: cleanups
307
  			for (sp = &((struct rsvp_head *)tp->root)->ht[h & 0xFF];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  			     *sp; sp = &(*sp)->next) {
  				if (*sp == s) {
  					tcf_tree_lock(tp);
  					*sp = s->next;
  					tcf_tree_unlock(tp);
  
  					kfree(s);
  					return 0;
  				}
  			}
  
  			return 0;
  		}
  	}
  	return 0;
  }
cc7ec456f   Eric Dumazet   net_sched: cleanups
324
  static unsigned int gen_handle(struct tcf_proto *tp, unsigned salt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
329
330
  {
  	struct rsvp_head *data = tp->root;
  	int i = 0xFFFF;
  
  	while (i-- > 0) {
  		u32 h;
cc7ec456f   Eric Dumazet   net_sched: cleanups
331

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
339
340
341
342
  		if ((data->hgenerator += 0x10000) == 0)
  			data->hgenerator = 0x10000;
  		h = data->hgenerator|salt;
  		if (rsvp_get(tp, h) == 0)
  			return h;
  	}
  	return 0;
  }
  
  static int tunnel_bts(struct rsvp_head *data)
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
343
344
  	int n = data->tgenerator >> 5;
  	u32 b = 1 << (data->tgenerator & 0x1F);
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
345

cc7ec456f   Eric Dumazet   net_sched: cleanups
346
  	if (data->tmap[n] & b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
351
352
353
354
355
356
357
358
  		return 0;
  	data->tmap[n] |= b;
  	return 1;
  }
  
  static void tunnel_recycle(struct rsvp_head *data)
  {
  	struct rsvp_session **sht = data->ht;
  	u32 tmap[256/32];
  	int h1, h2;
  
  	memset(tmap, 0, sizeof(tmap));
cc7ec456f   Eric Dumazet   net_sched: cleanups
359
  	for (h1 = 0; h1 < 256; h1++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
  		struct rsvp_session *s;
  		for (s = sht[h1]; s; s = s->next) {
cc7ec456f   Eric Dumazet   net_sched: cleanups
362
  			for (h2 = 0; h2 <= 16; h2++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  				struct rsvp_filter *f;
  
  				for (f = s->ht[h2]; f; f = f->next) {
  					if (f->tunnelhdr == 0)
  						continue;
  					data->tgenerator = f->res.classid;
  					tunnel_bts(data);
  				}
  			}
  		}
  	}
  
  	memcpy(data->tmap, tmap, sizeof(tmap));
  }
  
  static u32 gen_tunnel(struct rsvp_head *data)
  {
  	int i, k;
cc7ec456f   Eric Dumazet   net_sched: cleanups
381
382
  	for (k = 0; k < 2; k++) {
  		for (i = 255; i > 0; i--) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
386
387
388
389
390
391
  			if (++data->tgenerator == 0)
  				data->tgenerator = 1;
  			if (tunnel_bts(data))
  				return data->tgenerator;
  		}
  		tunnel_recycle(data);
  	}
  	return 0;
  }
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
392
393
394
395
396
397
398
399
  static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
  	[TCA_RSVP_CLASSID]	= { .type = NLA_U32 },
  	[TCA_RSVP_DST]		= { .type = NLA_BINARY,
  				    .len = RSVP_DST_LEN * sizeof(u32) },
  	[TCA_RSVP_SRC]		= { .type = NLA_BINARY,
  				    .len = RSVP_DST_LEN * sizeof(u32) },
  	[TCA_RSVP_PINFO]	= { .len = sizeof(struct tc_rsvp_pinfo) },
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  static int rsvp_change(struct tcf_proto *tp, unsigned long base,
  		       u32 handle,
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
402
  		       struct nlattr **tca,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
408
  		       unsigned long *arg)
  {
  	struct rsvp_head *data = tp->root;
  	struct rsvp_filter *f, **fp;
  	struct rsvp_session *s, **sp;
  	struct tc_rsvp_pinfo *pinfo = NULL;
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
409
  	struct nlattr *opt = tca[TCA_OPTIONS];
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
410
  	struct nlattr *tb[TCA_RSVP_MAX + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	struct tcf_exts e;
cc7ec456f   Eric Dumazet   net_sched: cleanups
412
  	unsigned int h1, h2;
66c6f529c   Al Viro   [NET]: net/sched ...
413
  	__be32 *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
  	int err;
  
  	if (opt == NULL)
  		return handle ? -EINVAL : 0;
6fa8c0144   Patrick McHardy   [NET_SCHED]: Use ...
418
  	err = nla_parse_nested(tb, TCA_RSVP_MAX, opt, rsvp_policy);
cee63723b   Patrick McHardy   [NET_SCHED]: Prop...
419
420
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421

27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
422
  	err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &rsvp_ext_map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
  	if (err < 0)
  		return err;
cc7ec456f   Eric Dumazet   net_sched: cleanups
425
426
  	f = (struct rsvp_filter *)*arg;
  	if (f) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
430
  		/* Node exists: adjust only classid */
  
  		if (f->handle != handle && handle)
  			goto errout2;
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
431
432
  		if (tb[TCA_RSVP_CLASSID]) {
  			f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
438
439
440
441
442
443
  			tcf_bind_filter(tp, &f->res, base);
  		}
  
  		tcf_exts_change(tp, &f->exts, &e);
  		return 0;
  	}
  
  	/* Now more serious part... */
  	err = -EINVAL;
  	if (handle)
  		goto errout2;
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
444
  	if (tb[TCA_RSVP_DST] == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
  		goto errout2;
  
  	err = -ENOBUFS;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
448
  	f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
  	if (f == NULL)
  		goto errout2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
  	h2 = 16;
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
452
453
  	if (tb[TCA_RSVP_SRC]) {
  		memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  		h2 = hash_src(f->src);
  	}
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
456
457
  	if (tb[TCA_RSVP_PINFO]) {
  		pinfo = nla_data(tb[TCA_RSVP_PINFO]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
  		f->spi = pinfo->spi;
  		f->tunnelhdr = pinfo->tunnelhdr;
  	}
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
461
462
  	if (tb[TCA_RSVP_CLASSID])
  		f->res.classid = nla_get_u32(tb[TCA_RSVP_CLASSID]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463

27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
464
  	dst = nla_data(tb[TCA_RSVP_DST]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  	h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0);
  
  	err = -ENOMEM;
  	if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0)
  		goto errout;
  
  	if (f->tunnelhdr) {
  		err = -EINVAL;
  		if (f->res.classid > 255)
  			goto errout;
  
  		err = -ENOMEM;
  		if (f->res.classid == 0 &&
  		    (f->res.classid = gen_tunnel(data)) == 0)
  			goto errout;
  	}
cc7ec456f   Eric Dumazet   net_sched: cleanups
481
  	for (sp = &data->ht[h1]; (s = *sp) != NULL; sp = &s->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
  		if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
  		    pinfo && pinfo->protocol == s->protocol &&
f64f9e719   Joe Perches   net: Move && and ...
484
  		    memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  #if RSVP_DST_LEN == 4
f64f9e719   Joe Perches   net: Move && and ...
486
487
488
  		    dst[0] == s->dst[0] &&
  		    dst[1] == s->dst[1] &&
  		    dst[2] == s->dst[2] &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  #endif
f64f9e719   Joe Perches   net: Move && and ...
490
  		    pinfo->tunnelid == s->tunnelid) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
495
496
497
498
499
500
501
502
503
  
  insert:
  			/* OK, we found appropriate session */
  
  			fp = &s->ht[h2];
  
  			f->sess = s;
  			if (f->tunnelhdr == 0)
  				tcf_bind_filter(tp, &f->res, base);
  
  			tcf_exts_change(tp, &f->exts, &e);
  
  			for (fp = &s->ht[h2]; *fp; fp = &(*fp)->next)
cc7ec456f   Eric Dumazet   net_sched: cleanups
504
  				if (((*fp)->spi.mask & f->spi.mask) != f->spi.mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
512
513
514
515
516
517
  					break;
  			f->next = *fp;
  			wmb();
  			*fp = f;
  
  			*arg = (unsigned long)f;
  			return 0;
  		}
  	}
  
  	/* No session found. Create new one. */
  
  	err = -ENOBUFS;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
518
  	s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  	if (s == NULL)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  	memcpy(s->dst, dst, sizeof(s->dst));
  
  	if (pinfo) {
  		s->dpi = pinfo->dpi;
  		s->protocol = pinfo->protocol;
  		s->tunnelid = pinfo->tunnelid;
  	}
  	for (sp = &data->ht[h1]; *sp; sp = &(*sp)->next) {
  		if (((*sp)->dpi.mask&s->dpi.mask) != s->dpi.mask)
  			break;
  	}
  	s->next = *sp;
  	wmb();
  	*sp = s;
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
535

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
  	goto insert;
  
  errout:
a51482bde   Jesper Juhl   [NET]: kfree cleanup
539
  	kfree(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
547
  errout2:
  	tcf_exts_destroy(tp, &e);
  	return err;
  }
  
  static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
  {
  	struct rsvp_head *head = tp->root;
cc7ec456f   Eric Dumazet   net_sched: cleanups
548
  	unsigned int h, h1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  
  	if (arg->stop)
  		return;
  
  	for (h = 0; h < 256; h++) {
  		struct rsvp_session *s;
  
  		for (s = head->ht[h]; s; s = s->next) {
  			for (h1 = 0; h1 <= 16; h1++) {
  				struct rsvp_filter *f;
  
  				for (f = s->ht[h1]; f; f = f->next) {
  					if (arg->count < arg->skip) {
  						arg->count++;
  						continue;
  					}
  					if (arg->fn(tp, (unsigned long)f, arg) < 0) {
  						arg->stop = 1;
  						return;
  					}
  					arg->count++;
  				}
  			}
  		}
  	}
  }
  
  static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
  		     struct sk_buff *skb, struct tcmsg *t)
  {
cc7ec456f   Eric Dumazet   net_sched: cleanups
579
  	struct rsvp_filter *f = (struct rsvp_filter *)fh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	struct rsvp_session *s;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
581
  	unsigned char *b = skb_tail_pointer(skb);
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
582
  	struct nlattr *nest;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
585
586
587
588
589
  	struct tc_rsvp_pinfo pinfo;
  
  	if (f == NULL)
  		return skb->len;
  	s = f->sess;
  
  	t->tcm_handle = f->handle;
4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
590
591
592
  	nest = nla_nest_start(skb, TCA_OPTIONS);
  	if (nest == NULL)
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593

add93b610   Patrick McHardy   [NET_SCHED]: Conv...
594
  	NLA_PUT(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
598
599
  	pinfo.dpi = s->dpi;
  	pinfo.spi = f->spi;
  	pinfo.protocol = s->protocol;
  	pinfo.tunnelid = s->tunnelid;
  	pinfo.tunnelhdr = f->tunnelhdr;
8a47077a0   Patrick McHardy   [NETLINK]: Missin...
600
  	pinfo.pad = 0;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
601
  	NLA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  	if (f->res.classid)
24beeab53   Patrick McHardy   [NET_SCHED]: Use ...
603
  		NLA_PUT_U32(skb, TCA_RSVP_CLASSID, f->res.classid);
cc7ec456f   Eric Dumazet   net_sched: cleanups
604
  	if (((f->handle >> 8) & 0xFF) != 16)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
605
  		NLA_PUT(skb, TCA_RSVP_SRC, sizeof(f->src), f->src);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  
  	if (tcf_exts_dump(skb, &f->exts, &rsvp_ext_map) < 0)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
608
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609

4b3550ef5   Patrick McHardy   [NET_SCHED]: Use ...
610
  	nla_nest_end(skb, nest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
  
  	if (tcf_exts_dump_stats(skb, &f->exts, &rsvp_ext_map) < 0)
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
613
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  	return skb->len;
add93b610   Patrick McHardy   [NET_SCHED]: Conv...
615
  nla_put_failure:
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
616
  	nlmsg_trim(skb, b);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
  	return -1;
  }
27e95a8c6   Igor Maravić   pkt_sched: cls_rs...
619
  static struct tcf_proto_ops RSVP_OPS __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  	.kind		=	RSVP_ID,
  	.classify	=	rsvp_classify,
  	.init		=	rsvp_init,
  	.destroy	=	rsvp_destroy,
  	.get		=	rsvp_get,
  	.put		=	rsvp_put,
  	.change		=	rsvp_change,
  	.delete		=	rsvp_delete,
  	.walk		=	rsvp_walk,
  	.dump		=	rsvp_dump,
  	.owner		=	THIS_MODULE,
  };
  
  static int __init init_rsvp(void)
  {
  	return register_tcf_proto_ops(&RSVP_OPS);
  }
10297b993   YOSHIFUJI Hideaki   [NET] SCHED: Fix ...
637
  static void __exit exit_rsvp(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
  {
  	unregister_tcf_proto_ops(&RSVP_OPS);
  }
  
  module_init(init_rsvp)
  module_exit(exit_rsvp)