Blame view

net/decnet/dn_table.c 20 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * DECnet       An implementation of the DECnet protocol suite for the LINUX
   *              operating system.  DECnet is implemented using the  BSD Socket
   *              interface as the means of communication with the user level.
   *
   *              DECnet Routing Forwarding Information Base (Routing Tables)
   *
   * Author:      Steve Whitehouse <SteveW@ACM.org>
   *              Mostly copied from the IPv4 routing code
   *
   *
   * Changes:
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
  #include <linux/string.h>
  #include <linux/net.h>
  #include <linux/socket.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
24
25
26
27
  #include <linux/sockios.h>
  #include <linux/init.h>
  #include <linux/skbuff.h>
  #include <linux/netlink.h>
  #include <linux/rtnetlink.h>
  #include <linux/proc_fs.h>
  #include <linux/netdevice.h>
  #include <linux/timer.h>
  #include <linux/spinlock.h>
60063497a   Arun Sharma   atomic: use <linu...
28
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
  #include <asm/uaccess.h>
  #include <linux/route.h> /* RTF_xxx */
  #include <net/neighbour.h>
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
32
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  #include <net/dst.h>
  #include <net/flow.h>
a8731cbf6   Steven Whitehouse   [DECNET]: Covert ...
35
  #include <net/fib_rules.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  #include <net/dn.h>
  #include <net/dn_route.h>
  #include <net/dn_fib.h>
  #include <net/dn_neigh.h>
  #include <net/dn_dev.h>
  
  struct dn_zone
  {
  	struct dn_zone		*dz_next;
  	struct dn_fib_node 	**dz_hash;
  	int			dz_nent;
  	int			dz_divisor;
  	u32			dz_hashmask;
  #define DZ_HASHMASK(dz)	((dz)->dz_hashmask)
  	int			dz_order;
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
51
  	__le16			dz_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
61
  #define DZ_MASK(dz)	((dz)->dz_mask)
  };
  
  struct dn_hash
  {
  	struct dn_zone	*dh_zones[17];
  	struct dn_zone	*dh_zone_list;
  };
  
  #define dz_key_0(key)		((key).datum = 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
  
  #define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
64
  	for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  
  #define endfor_nexthops(fi) }
  
  #define DN_MAX_DIVISOR 1024
  #define DN_S_ZOMBIE 1
  #define DN_S_ACCESSED 2
  
  #define DN_FIB_SCAN(f, fp) \
  for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
  
  #define DN_FIB_SCAN_KEY(f, fp, key) \
  for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
  
  #define RT_TABLE_MIN 1
abcab2683   Patrick McHardy   [DECNET]: Increas...
79
80
  #define DN_FIB_TABLE_HASHSZ 256
  static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  static DEFINE_RWLOCK(dn_fib_tables_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82

e18b890bb   Christoph Lameter   [PATCH] slab: rem...
83
  static struct kmem_cache *dn_hash_kmem __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
  static int dn_fib_hash_zombies;
  
  static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
  {
c4106aa88   Harvey Harrison   decnet: remove pr...
88
  	u16 h = le16_to_cpu(key.datum)>>(16 - dz->dz_order);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
  	h ^= (h >> 10);
  	h ^= (h >> 6);
  	h &= DZ_HASHMASK(dz);
  	return *(dn_fib_idx_t *)&h;
  }
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
94
  static inline dn_fib_key_t dz_key(__le16 dst, struct dn_zone *dz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  {
  	dn_fib_key_t k;
  	k.datum = dst & DZ_MASK(dz);
  	return k;
  }
  
  static inline struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
  {
  	return &dz->dz_hash[dn_hash(key, dz).datum];
  }
  
  static inline struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
  {
  	return dz->dz_hash[dn_hash(key, dz).datum];
  }
  
  static inline int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
  {
  	return a.datum == b.datum;
  }
  
  static inline int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
  {
  	return a.datum <= b.datum;
  }
  
  static inline void dn_rebuild_zone(struct dn_zone *dz,
  				   struct dn_fib_node **old_ht,
  				   int old_divisor)
  {
a01c1335a   David S. Miller   decnet: Don't lea...
125
  	struct dn_fib_node *f, **fp, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
  
  	for(i = 0; i < old_divisor; i++) {
a01c1335a   David S. Miller   decnet: Don't lea...
129
130
  		for(f = old_ht[i]; f; f = next) {
  			next = f->fn_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  			for(fp = dn_chain_p(f->fn_key, dz);
  				*fp && dn_key_leq((*fp)->fn_key, f->fn_key);
  				fp = &(*fp)->fn_next)
  				/* NOTHING */;
  			f->fn_next = *fp;
  			*fp = f;
  		}
  	}
  }
  
  static void dn_rehash_zone(struct dn_zone *dz)
  {
  	struct dn_fib_node **ht, **old_ht;
  	int old_divisor, new_divisor;
  	u32 new_hashmask;
  
  	old_divisor = dz->dz_divisor;
06f8fe11b   Joe Perches   decnet: Reduce sw...
148
149
150
151
152
153
154
155
156
157
158
159
160
  	switch (old_divisor) {
  	case 16:
  		new_divisor = 256;
  		new_hashmask = 0xFF;
  		break;
  	default:
  		printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d
  ",
  		       old_divisor);
  	case 256:
  		new_divisor = 1024;
  		new_hashmask = 0x3FF;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	}
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
162
  	ht = kcalloc(new_divisor, sizeof(struct dn_fib_node*), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
  	if (ht == NULL)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  	write_lock_bh(&dn_fib_tables_lock);
  	old_ht = dz->dz_hash;
  	dz->dz_hash = ht;
  	dz->dz_hashmask = new_hashmask;
  	dz->dz_divisor = new_divisor;
  	dn_rebuild_zone(dz, old_ht, old_divisor);
  	write_unlock_bh(&dn_fib_tables_lock);
  	kfree(old_ht);
  }
  
  static void dn_free_node(struct dn_fib_node *f)
  {
  	dn_fib_release_info(DN_FIB_INFO(f));
  	kmem_cache_free(dn_hash_kmem, f);
  }
  
  
  static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
  {
  	int i;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
185
  	struct dn_zone *dz = kzalloc(sizeof(struct dn_zone), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  	if (!dz)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
  	if (z) {
  		dz->dz_divisor = 16;
  		dz->dz_hashmask = 0x0F;
  	} else {
  		dz->dz_divisor = 1;
  		dz->dz_hashmask = 0;
  	}
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
195
  	dz->dz_hash = kcalloc(dz->dz_divisor, sizeof(struct dn_fib_node *), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
  	if (!dz->dz_hash) {
  		kfree(dz);
  		return NULL;
  	}
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  	dz->dz_order = z;
  	dz->dz_mask = dnet_make_mask(z);
  
  	for(i = z + 1; i <= 16; i++)
  		if (table->dh_zones[i])
  			break;
  
  	write_lock_bh(&dn_fib_tables_lock);
  	if (i>16) {
  		dz->dz_next = table->dh_zone_list;
  		table->dh_zone_list = dz;
  	} else {
  		dz->dz_next = table->dh_zones[i]->dz_next;
  		table->dh_zones[i]->dz_next = dz;
  	}
  	table->dh_zones[z] = dz;
  	write_unlock_bh(&dn_fib_tables_lock);
  	return dz;
  }
  
  
  static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi)
  {
  	struct rtnexthop *nhp;
  	int nhlen;
  
  	if (rta->rta_priority && *rta->rta_priority != fi->fib_priority)
  		return 1;
  
  	if (rta->rta_oif || rta->rta_gw) {
  		if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
  		    (!rta->rta_gw  || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0))
  			return 0;
  		return 1;
  	}
  
  	if (rta->rta_mp == NULL)
  		return 0;
  
  	nhp = RTA_DATA(rta->rta_mp);
  	nhlen = RTA_PAYLOAD(rta->rta_mp);
  
  	for_nexthops(fi) {
  		int attrlen = nhlen - sizeof(struct rtnexthop);
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
244
  		__le16 gw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  
  		if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
  			return -EINVAL;
  		if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
  			return 1;
  		if (attrlen) {
  			gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
  
  			if (gw && gw != nh->nh_gw)
  				return 1;
  		}
  		nhp = RTNH_NEXT(nhp);
  	} endfor_nexthops(fi);
  
  	return 0;
  }
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
261
262
  static inline size_t dn_fib_nlmsg_size(struct dn_fib_info *fi)
  {
75356f27e   David S. Miller   [DECNET]: Fix bui...
263
  	size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  			 + nla_total_size(4) /* RTA_TABLE */
  			 + nla_total_size(2) /* RTA_DST */
  			 + nla_total_size(4); /* RTA_PRIORITY */
  
  	/* space for nested metrics */
  	payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
  
  	if (fi->fib_nhs) {
  		/* Also handles the special case fib_nhs == 1 */
  
  		/* each nexthop is packed in an attribute */
  		size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
  
  		/* may contain a gateway attribute */
  		nhsize += nla_total_size(4);
  
  		/* all nexthops are packed in a nested attribute */
  		payload += nla_total_size(fi->fib_nhs * nhsize);
  	}
  
  	return payload;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
  static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
287
288
  			u32 tb_id, u8 type, u8 scope, void *dst, int dst_len,
  			struct dn_fib_info *fi, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
290
291
  	struct rtmsg *rtm;
  	struct nlmsghdr *nlh;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
292
  	unsigned char *b = skb_tail_pointer(skb);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
293
294
295
296
297
298
299
300
  
  	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
  	rtm = NLMSG_DATA(nlh);
  	rtm->rtm_family = AF_DECnet;
  	rtm->rtm_dst_len = dst_len;
  	rtm->rtm_src_len = 0;
  	rtm->rtm_tos = 0;
  	rtm->rtm_table = tb_id;
9e762a4a8   Patrick McHardy   [NET]: Introduce ...
301
  	RTA_PUT_U32(skb, RTA_TABLE, tb_id);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
302
303
  	rtm->rtm_flags = fi->fib_flags;
  	rtm->rtm_scope = scope;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  	rtm->rtm_type  = type;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
305
306
307
308
309
  	if (rtm->rtm_dst_len)
  		RTA_PUT(skb, RTA_DST, 2, dst);
  	rtm->rtm_protocol = fi->fib_protocol;
  	if (fi->fib_priority)
  		RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
  	if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
  		goto rtattr_failure;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  	if (fi->fib_nhs == 1) {
  		if (fi->fib_nh->nh_gw)
  			RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw);
  		if (fi->fib_nh->nh_oif)
  			RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
  	}
  	if (fi->fib_nhs > 1) {
  		struct rtnexthop *nhp;
  		struct rtattr *mp_head;
  		if (skb_tailroom(skb) <= RTA_SPACE(0))
  			goto rtattr_failure;
  		mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0));
  
  		for_nexthops(fi) {
  			if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
  				goto rtattr_failure;
  			nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
  			nhp->rtnh_flags = nh->nh_flags & 0xFF;
  			nhp->rtnh_hops = nh->nh_weight - 1;
  			nhp->rtnh_ifindex = nh->nh_oif;
  			if (nh->nh_gw)
  				RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw);
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
334
  			nhp->rtnh_len = skb_tail_pointer(skb) - (unsigned char *)nhp;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
335
336
  		} endfor_nexthops(fi);
  		mp_head->rta_type = RTA_MULTIPATH;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
337
  		mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
338
  	}
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
339
  	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
340
  	return skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
  
  
  nlmsg_failure:
  rtattr_failure:
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
345
  	nlmsg_trim(skb, b);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
346
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  }
2dfe55b47   Patrick McHardy   [NET]: Use u32 fo...
348
  static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
349
  			struct nlmsghdr *nlh, struct netlink_skb_parms *req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
351
352
  	struct sk_buff *skb;
  	u32 pid = req ? req->pid : 0;
dc738dd83   Thomas Graf   [DECNET]: Convert...
353
  	int err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
355
356
  	skb = nlmsg_new(dn_fib_nlmsg_size(DN_FIB_INFO(f)), GFP_KERNEL);
  	if (skb == NULL)
dc738dd83   Thomas Graf   [DECNET]: Convert...
357
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
359
  	err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
dc738dd83   Thomas Graf   [DECNET]: Convert...
360
361
  			       f->fn_type, f->fn_scope, &f->fn_key, z,
  			       DN_FIB_INFO(f), 0);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
362
363
364
365
366
367
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in dn_fib_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
368
369
  	rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
  	return;
dc738dd83   Thomas Graf   [DECNET]: Convert...
370
371
  errout:
  	if (err < 0)
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
372
  		rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  }
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
374
  static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
380
  				struct netlink_callback *cb,
  				struct dn_fib_table *tb,
  				struct dn_zone *dz,
  				struct dn_fib_node *f)
  {
  	int i, s_i;
abcab2683   Patrick McHardy   [DECNET]: Increas...
381
  	s_i = cb->args[4];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
386
  	for(i = 0; f; i++, f = f->fn_next) {
  		if (i < s_i)
  			continue;
  		if (f->fn_state & DN_S_ZOMBIE)
  			continue;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
387
  		if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  				cb->nlh->nlmsg_seq,
  				RTM_NEWROUTE,
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
390
  				tb->n,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  				(f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
392
  				f->fn_scope, &f->fn_key, dz->dz_order,
b6544c0b4   Jamal Hadi Salim   [NETLINK]: Correc...
393
  				f->fn_info, NLM_F_MULTI) < 0) {
abcab2683   Patrick McHardy   [DECNET]: Increas...
394
  			cb->args[4] = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
  			return -1;
  		}
  	}
abcab2683   Patrick McHardy   [DECNET]: Increas...
398
  	cb->args[4] = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
  	return skb->len;
  }
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
401
  static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
404
405
406
  				struct netlink_callback *cb,
  				struct dn_fib_table *tb,
  				struct dn_zone *dz)
  {
  	int h, s_h;
abcab2683   Patrick McHardy   [DECNET]: Increas...
407
  	s_h = cb->args[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
  	for(h = 0; h < dz->dz_divisor; h++) {
  		if (h < s_h)
  			continue;
  		if (h > s_h)
abcab2683   Patrick McHardy   [DECNET]: Increas...
412
  			memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
  		if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
  			continue;
  		if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
abcab2683   Patrick McHardy   [DECNET]: Increas...
416
  			cb->args[3] = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
  			return -1;
  		}
  	}
abcab2683   Patrick McHardy   [DECNET]: Increas...
420
  	cb->args[3] = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
  	return skb->len;
  }
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
423
424
  static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
  				struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
426
  	int m, s_m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
  	struct dn_zone *dz;
  	struct dn_hash *table = (struct dn_hash *)tb->data;
abcab2683   Patrick McHardy   [DECNET]: Increas...
429
  	s_m = cb->args[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
  	read_lock(&dn_fib_tables_lock);
  	for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
  		if (m < s_m)
  			continue;
  		if (m > s_m)
abcab2683   Patrick McHardy   [DECNET]: Increas...
435
  			memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
  
  		if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
abcab2683   Patrick McHardy   [DECNET]: Increas...
438
  			cb->args[2] = m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
  			read_unlock(&dn_fib_tables_lock);
  			return -1;
  		}
  	}
  	read_unlock(&dn_fib_tables_lock);
abcab2683   Patrick McHardy   [DECNET]: Increas...
444
  	cb->args[2] = m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
446
  	return skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  }
abcab2683   Patrick McHardy   [DECNET]: Increas...
448
449
  int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
450
  	struct net *net = sock_net(skb->sk);
abcab2683   Patrick McHardy   [DECNET]: Increas...
451
452
453
454
455
  	unsigned int h, s_h;
  	unsigned int e = 0, s_e;
  	struct dn_fib_table *tb;
  	struct hlist_node *node;
  	int dumped = 0;
09ad9bc75   Octavian Purdila   net: use net_eq t...
456
  	if (!net_eq(net, &init_net))
b854272b3   Denis V. Lunev   [NET]: Modify all...
457
  		return 0;
abcab2683   Patrick McHardy   [DECNET]: Increas...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  	if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
  		((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
  			return dn_cache_dump(skb, cb);
  
  	s_h = cb->args[0];
  	s_e = cb->args[1];
  
  	for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
  		e = 0;
  		hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) {
  			if (e < s_e)
  				goto next;
  			if (dumped)
  				memset(&cb->args[2], 0, sizeof(cb->args) -
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
472
  						 2 * sizeof(cb->args[0]));
abcab2683   Patrick McHardy   [DECNET]: Increas...
473
474
475
476
477
478
479
480
481
482
483
484
485
  			if (tb->dump(tb, skb, cb) < 0)
  				goto out;
  			dumped = 1;
  next:
  			e++;
  		}
  	}
  out:
  	cb->args[1] = e;
  	cb->args[0] = h;
  
  	return skb->len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
  static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
  {
  	struct dn_hash *table = (struct dn_hash *)tb->data;
  	struct dn_fib_node *new_f, *f, **fp, **del_fp;
  	struct dn_zone *dz;
  	struct dn_fib_info *fi;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
492
  	int z = r->rtm_dst_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  	int type = r->rtm_type;
  	dn_fib_key_t key;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
495
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
497
498
  	if (z > 16)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499
500
501
502
503
504
505
  
  	dz = table->dh_zones[z];
  	if (!dz && !(dz = dn_new_zone(table, z)))
  		return -ENOBUFS;
  
  	dz_key_0(key);
  	if (rta->rta_dst) {
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
506
  		__le16 dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
  		memcpy(&dst, rta->rta_dst, 2);
  		if (dst & ~DZ_MASK(dz))
  			return -EINVAL;
  		key = dz_key(dst, dz);
  	}
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
512
513
  	if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
  
  	if (dz->dz_nent > (dz->dz_divisor << 2) &&
  			dz->dz_divisor > DN_MAX_DIVISOR &&
  			(z==16 || (1<<z) > dz->dz_divisor))
  		dn_rehash_zone(dz);
  
  	fp = dn_chain_p(key, dz);
  
  	DN_FIB_SCAN(f, fp) {
  		if (dn_key_leq(key, f->fn_key))
  			break;
  	}
  
  	del_fp = NULL;
  
  	if (f && (f->fn_state & DN_S_ZOMBIE) &&
  			dn_key_eq(f->fn_key, key)) {
  		del_fp = fp;
  		fp = &f->fn_next;
  		f = *fp;
  		goto create;
  	}
  
  	DN_FIB_SCAN_KEY(f, fp, key) {
  		if (fi->fib_priority <= DN_FIB_INFO(f)->fib_priority)
  			break;
  	}
  
  	if (f && dn_key_eq(f->fn_key, key) &&
  			fi->fib_priority == DN_FIB_INFO(f)->fib_priority) {
  		struct dn_fib_node **ins_fp;
  
  		err = -EEXIST;
  		if (n->nlmsg_flags & NLM_F_EXCL)
  			goto out;
  
  		if (n->nlmsg_flags & NLM_F_REPLACE) {
  			del_fp = fp;
  			fp = &f->fn_next;
  			f = *fp;
  			goto replace;
  		}
  
  		ins_fp = fp;
  		err = -EEXIST;
  
  		DN_FIB_SCAN_KEY(f, fp, key) {
  			if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority)
  				break;
f64f9e719   Joe Perches   net: Move && and ...
563
564
565
  			if (f->fn_type == type &&
  			    f->fn_scope == r->rtm_scope &&
  			    DN_FIB_INFO(f) == fi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  				goto out;
  		}
  
  		if (!(n->nlmsg_flags & NLM_F_APPEND)) {
  			fp = ins_fp;
  			f = *fp;
  		}
  	}
  
  create:
  	err = -ENOENT;
  	if (!(n->nlmsg_flags & NLM_F_CREATE))
  		goto out;
  
  replace:
  	err = -ENOBUFS;
c37622296   Robert P. J. Day   [PATCH] Transform...
582
  	new_f = kmem_cache_zalloc(dn_hash_kmem, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
  	if (new_f == NULL)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
  	new_f->fn_key = key;
  	new_f->fn_type = type;
  	new_f->fn_scope = r->rtm_scope;
  	DN_FIB_INFO(new_f) = fi;
  
  	new_f->fn_next = f;
  	write_lock_bh(&dn_fib_tables_lock);
  	*fp = new_f;
  	write_unlock_bh(&dn_fib_tables_lock);
  	dz->dz_nent++;
  
  	if (del_fp) {
  		f = *del_fp;
  		write_lock_bh(&dn_fib_tables_lock);
  		*del_fp = f->fn_next;
  		write_unlock_bh(&dn_fib_tables_lock);
  
  		if (!(f->fn_state & DN_S_ZOMBIE))
  			dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
  		if (f->fn_state & DN_S_ACCESSED)
  			dn_rt_cache_flush(-1);
  		dn_free_node(f);
  		dz->dz_nent--;
  	} else {
  		dn_rt_cache_flush(-1);
  	}
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
611
  	dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
613
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
618
619
620
621
622
623
  out:
  	dn_fib_release_info(fi);
  	return err;
  }
  
  
  static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
  {
  	struct dn_hash *table = (struct dn_hash*)tb->data;
  	struct dn_fib_node **fp, **del_fp, *f;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
624
  	int z = r->rtm_dst_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
  	struct dn_zone *dz;
  	dn_fib_key_t key;
  	int matched;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
628
629
  	if (z > 16)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
632
633
634
635
  
  	if ((dz = table->dh_zones[z]) == NULL)
  		return -ESRCH;
  
  	dz_key_0(key);
  	if (rta->rta_dst) {
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
636
  		__le16 dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  		memcpy(&dst, rta->rta_dst, 2);
  		if (dst & ~DZ_MASK(dz))
  			return -EINVAL;
  		key = dz_key(dst, dz);
  	}
  
  	fp = dn_chain_p(key, dz);
  
  	DN_FIB_SCAN(f, fp) {
  		if (dn_key_eq(f->fn_key, key))
  			break;
  		if (dn_key_leq(key, f->fn_key))
  			return -ESRCH;
  	}
  
  	matched = 0;
  	del_fp = NULL;
  	DN_FIB_SCAN_KEY(f, fp, key) {
  		struct dn_fib_info *fi = DN_FIB_INFO(f);
  
  		if (f->fn_state & DN_S_ZOMBIE)
  			return -ESRCH;
  
  		matched++;
  
  		if (del_fp == NULL &&
  				(!r->rtm_type || f->fn_type == r->rtm_type) &&
  				(r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
665
  				(!r->rtm_protocol ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
668
669
670
671
672
  					fi->fib_protocol == r->rtm_protocol) &&
  				dn_fib_nh_match(r, n, rta, fi) == 0)
  			del_fp = fp;
  	}
  
  	if (del_fp) {
  		f = *del_fp;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
673
  		dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
  
  		if (matched != 1) {
  			write_lock_bh(&dn_fib_tables_lock);
  			*del_fp = f->fn_next;
  			write_unlock_bh(&dn_fib_tables_lock);
  
  			if (f->fn_state & DN_S_ACCESSED)
  				dn_rt_cache_flush(-1);
  			dn_free_node(f);
  			dz->dz_nent--;
  		} else {
  			f->fn_state |= DN_S_ZOMBIE;
  			if (f->fn_state & DN_S_ACCESSED) {
  				f->fn_state &= ~DN_S_ACCESSED;
  				dn_rt_cache_flush(-1);
  			}
  			if (++dn_fib_hash_zombies > 128)
  				dn_fib_flush();
  		}
  
  		return 0;
  	}
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
696
  	return -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
  }
  
  static inline int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
  {
  	int found = 0;
  	struct dn_fib_node *f;
  
  	while((f = *fp) != NULL) {
  		struct dn_fib_info *fi = DN_FIB_INFO(f);
  
  		if (fi && ((f->fn_state & DN_S_ZOMBIE) || (fi->fib_flags & RTNH_F_DEAD))) {
  			write_lock_bh(&dn_fib_tables_lock);
  			*fp = f->fn_next;
  			write_unlock_bh(&dn_fib_tables_lock);
  
  			dn_free_node(f);
  			found++;
  			continue;
  		}
  		fp = &f->fn_next;
  	}
  
  	return found;
  }
  
  static int dn_fib_table_flush(struct dn_fib_table *tb)
  {
  	struct dn_hash *table = (struct dn_hash *)tb->data;
  	struct dn_zone *dz;
  	int found = 0;
  
  	dn_fib_hash_zombies = 0;
  	for(dz = table->dh_zone_list; dz; dz = dz->dz_next) {
  		int i;
  		int tmp = 0;
  		for(i = dz->dz_divisor-1; i >= 0; i--)
  			tmp += dn_flush_list(&dz->dz_hash[i], dz->dz_order, table);
  		dz->dz_nent -= tmp;
  		found += tmp;
  	}
  
  	return found;
  }
bef55aebd   David S. Miller   decnet: Convert t...
740
  static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowidn *flp, struct dn_fib_res *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
742
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
  	struct dn_zone *dz;
  	struct dn_hash *t = (struct dn_hash *)tb->data;
  
  	read_lock(&dn_fib_tables_lock);
  	for(dz = t->dh_zone_list; dz; dz = dz->dz_next) {
  		struct dn_fib_node *f;
bef55aebd   David S. Miller   decnet: Convert t...
749
  		dn_fib_key_t k = dz_key(flp->daddr, dz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
753
754
755
756
757
758
759
760
761
762
  
  		for(f = dz_chain(k, dz); f; f = f->fn_next) {
  			if (!dn_key_eq(k, f->fn_key)) {
  				if (dn_key_leq(k, f->fn_key))
  					break;
  				else
  					continue;
  			}
  
  			f->fn_state |= DN_S_ACCESSED;
  
  			if (f->fn_state&DN_S_ZOMBIE)
  				continue;
bef55aebd   David S. Miller   decnet: Convert t...
763
  			if (f->fn_scope < flp->flowidn_scope)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
767
768
769
  				continue;
  
  			err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), flp, res);
  
  			if (err == 0) {
  				res->type = f->fn_type;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
770
  				res->scope = f->fn_scope;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
775
776
777
778
779
780
  				res->prefixlen = dz->dz_order;
  				goto out;
  			}
  			if (err < 0)
  				goto out;
  		}
  	}
  	err = 1;
  out:
  	read_unlock(&dn_fib_tables_lock);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
781
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
  }
2dfe55b47   Patrick McHardy   [NET]: Use u32 fo...
783
  struct dn_fib_table *dn_fib_get_table(u32 n, int create)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
785
  	struct dn_fib_table *t;
abcab2683   Patrick McHardy   [DECNET]: Increas...
786
787
  	struct hlist_node *node;
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
789
790
  	if (n < RT_TABLE_MIN)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
792
793
  	if (n > RT_TABLE_MAX)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794

abcab2683   Patrick McHardy   [DECNET]: Increas...
795
796
797
798
799
800
801
802
803
  	h = n & (DN_FIB_TABLE_HASHSZ - 1);
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(t, node, &dn_fib_table_hash[h], hlist) {
  		if (t->n == n) {
  			rcu_read_unlock();
  			return t;
  		}
  	}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
805
806
  	if (!create)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
808
809
810
811
812
  	if (in_interrupt() && net_ratelimit()) {
  		printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table from interrupt
  ");
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
814
  	t = kzalloc(sizeof(struct dn_fib_table) + sizeof(struct dn_hash),
e6b61105f   Arnaldo Carvalho de Melo   [DECNET]: Use kza...
815
  		    GFP_KERNEL);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
816
817
818
819
820
821
822
823
824
  	if (t == NULL)
  		return NULL;
  
  	t->n = n;
  	t->insert = dn_fib_table_insert;
  	t->delete = dn_fib_table_delete;
  	t->lookup = dn_fib_table_lookup;
  	t->flush  = dn_fib_table_flush;
  	t->dump = dn_fib_table_dump;
abcab2683   Patrick McHardy   [DECNET]: Increas...
825
  	hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
827
  	return t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
  struct dn_fib_table *dn_fib_empty_table(void)
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
831
  	u32 id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
833
  	for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
abcab2683   Patrick McHardy   [DECNET]: Increas...
834
  		if (dn_fib_get_table(id, 0) == NULL)
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
835
836
  			return dn_fib_get_table(id, 1);
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  }
abcab2683   Patrick McHardy   [DECNET]: Increas...
838
839
  void dn_fib_flush(void)
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
840
841
  	int flushed = 0;
  	struct dn_fib_table *tb;
abcab2683   Patrick McHardy   [DECNET]: Increas...
842
843
844
845
846
  	struct hlist_node *node;
  	unsigned int h;
  
  	for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
  		hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist)
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
847
848
  			flushed += tb->flush(tb);
  	}
abcab2683   Patrick McHardy   [DECNET]: Increas...
849

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
850
851
  	if (flushed)
  		dn_rt_cache_flush(-1);
abcab2683   Patrick McHardy   [DECNET]: Increas...
852
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
  void __init dn_fib_table_init(void)
  {
  	dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
  					sizeof(struct dn_fib_info),
  					0, SLAB_HWCACHE_ALIGN,
20c2df83d   Paul Mundt   mm: Remove slab d...
858
  					NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
862
  }
  
  void __exit dn_fib_table_cleanup(void)
  {
abcab2683   Patrick McHardy   [DECNET]: Increas...
863
864
865
  	struct dn_fib_table *t;
  	struct hlist_node *node, *next;
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866

abcab2683   Patrick McHardy   [DECNET]: Increas...
867
868
869
  	write_lock(&dn_fib_tables_lock);
  	for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
  		hlist_for_each_entry_safe(t, node, next, &dn_fib_table_hash[h],
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
870
  					  hlist) {
abcab2683   Patrick McHardy   [DECNET]: Increas...
871
872
873
874
875
  			hlist_del(&t->hlist);
  			kfree(t);
  		}
  	}
  	write_unlock(&dn_fib_tables_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  }