~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/decnet/dn_fib.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * DECnet       An implementation of the DECnet protocol suite for the LINUX
  3  *              operating system.  DECnet is implemented using the  BSD Socket
  4  *              interface as the means of communication with the user level.
  5  *
  6  *              DECnet Routing Forwarding Information Base (Glue/Info List)
  7  *
  8  * Author:      Steve Whitehouse <SteveW@ACM.org>
  9  *
 10  *
 11  * Changes:
 12  *              Alexey Kuznetsov : SMP locking changes
 13  *              Steve Whitehouse : Rewrote it... Well to be more correct, I
 14  *                                 copied most of it from the ipv4 fib code.
 15  *
 16  */
 17 #include <linux/config.h>
 18 #include <linux/string.h>
 19 #include <linux/net.h>
 20 #include <linux/socket.h>
 21 #include <linux/sockios.h>
 22 #include <linux/init.h>
 23 #include <linux/skbuff.h>
 24 #include <linux/netlink.h>
 25 #include <linux/rtnetlink.h>
 26 #include <linux/proc_fs.h>
 27 #include <linux/netdevice.h>
 28 #include <linux/timer.h>
 29 #include <linux/spinlock.h>
 30 #include <asm/atomic.h>
 31 #include <asm/uaccess.h>
 32 #include <net/neighbour.h>
 33 #include <net/dst.h>
 34 #include <net/dn.h>
 35 #include <net/dn_route.h>
 36 #include <net/dn_fib.h>
 37 #include <net/dn_neigh.h>
 38 #include <net/dn_dev.h>
 39 
 40 
 41 #define for_fib_info() { struct dn_fib_info *fi;\
 42         for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
 43 #define endfor_fib_info() }
 44 
 45 #define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
 46         for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
 47 
 48 #define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
 49         for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
 50 
 51 #define endfor_nexthops(fi) }
 52 
 53 #ifdef CONFIG_RTNETLINK
 54 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
 55 #endif /* CONFIG_RTNETLINK */
 56 
 57 
 58 static struct dn_fib_info *dn_fib_info_list = NULL;
 59 static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED;
 60 int dn_fib_info_cnt;
 61 
 62 static struct
 63 {
 64         int error;
 65         u8 scope;
 66 } dn_fib_props[RTA_MAX+1] = {
 67         { 0, RT_SCOPE_NOWHERE },                /* RTN_UNSPEC */
 68         { 0, RT_SCOPE_UNIVERSE },               /* RTN_UNICAST */
 69         { 0, RT_SCOPE_HOST },                   /* RTN_LOCAL */
 70         { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_BROADCAST */
 71         { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_ANYCAST */
 72         { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_MULTICAST */
 73         { -EINVAL, RT_SCOPE_UNIVERSE },         /* RTN_BLACKHOLE */
 74         { -EHOSTUNREACH, RT_SCOPE_UNIVERSE },   /* RTN_UNREACHABLE */
 75         { -EACCES, RT_SCOPE_UNIVERSE },         /* RTN_PROHIBIT */
 76         { -EAGAIN, RT_SCOPE_UNIVERSE },         /* RTN_THROW */
 77         { -EINVAL, RT_SCOPE_NOWHERE },          /* RTN_NAT */
 78         { -EINVAL, RT_SCOPE_NOWHERE }           /* RTN_XRESOLVE */
 79 };
 80 
 81 void dn_fib_free_info(struct dn_fib_info *fi)
 82 {
 83         if (fi->fib_dead == 0) {
 84                 printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
 85                 return;
 86         }
 87 
 88         change_nexthops(fi) {
 89                 if (nh->nh_dev)
 90                         dev_put(nh->nh_dev);
 91                 nh->nh_dev = NULL;
 92         } endfor_nexthops(fi);
 93         dn_fib_info_cnt--;
 94         kfree(fi);
 95 }
 96 
 97 void dn_fib_release_info(struct dn_fib_info *fi)
 98 {
 99         write_lock(&dn_fib_info_lock);
100         if (fi && --fi->fib_treeref == 0) {
101                 if (fi->fib_next)
102                         fi->fib_next->fib_prev = fi->fib_prev;
103                 if (fi->fib_prev)
104                         fi->fib_prev->fib_next = fi->fib_next;
105                 if (fi == dn_fib_info_list)
106                         dn_fib_info_list = fi->fib_next;
107                 fi->fib_dead = 1;
108                 dn_fib_info_put(fi);
109         }
110         write_unlock(&dn_fib_info_lock);
111 }
112 
113 static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
114 {
115         const struct dn_fib_nh *onh = ofi->fib_nh;
116 
117         for_nexthops(fi) {
118                 if (nh->nh_oif != onh->nh_oif ||
119                         nh->nh_gw != onh->nh_gw ||
120                         nh->nh_scope != onh->nh_scope ||
121                         nh->nh_weight != onh->nh_weight ||
122                         ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
123                                 return -1;
124                 onh++;
125         } endfor_nexthops(fi);
126         return 0;
127 }
128 
129 static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
130 {
131         for_fib_info() {
132                 if (fi->fib_nhs != nfi->fib_nhs)
133                         continue;
134                 if (nfi->fib_protocol == fi->fib_protocol &&
135                         nfi->fib_prefsrc == fi->fib_prefsrc &&
136                         nfi->fib_priority == fi->fib_priority &&
137                         ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
138                         (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
139                                 return fi;
140         } endfor_fib_info();
141         return NULL;
142 }
143 
144 u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
145 {
146         while(RTA_OK(attr,attrlen)) {
147                 if (attr->rta_type == type)
148                         return *(u16*)RTA_DATA(attr);
149                 attr = RTA_NEXT(attr, attrlen);
150         }
151 
152         return 0;
153 }
154 
155 static int dn_fib_count_nhs(struct rtattr *rta)
156 {
157         int nhs = 0;
158         struct rtnexthop *nhp = RTA_DATA(rta);
159         int nhlen = RTA_PAYLOAD(rta);
160 
161         while(nhlen >= (int)sizeof(struct rtnexthop)) {
162                 if ((nhlen -= nhp->rtnh_len) < 0)
163                         return 0;
164                 nhs++;
165                 nhp = RTNH_NEXT(nhp);
166         }
167 
168         return nhs;
169 }
170 
171 static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
172 {
173         struct rtnexthop *nhp = RTA_DATA(rta);
174         int nhlen = RTA_PAYLOAD(rta);
175 
176         change_nexthops(fi) {
177                 int attrlen = nhlen - sizeof(struct rtnexthop);
178                 if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
179                         return -EINVAL;
180 
181                 nh->nh_flags  = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
182                 nh->nh_oif    = nhp->rtnh_ifindex;
183                 nh->nh_weight = nhp->rtnh_hops + 1;
184 
185                 if (attrlen) {
186                         nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
187                 }
188                 nhp = RTNH_NEXT(nhp);
189         } endfor_nexthops(fi);
190 
191         return 0;
192 }
193 
194 
195 static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
196 {
197         int err;
198 
199         if (nh->nh_gw) {
200                 struct dn_fib_key key;
201                 struct dn_fib_res res;
202 
203                 if (nh->nh_flags&RTNH_F_ONLINK) {
204                         struct net_device *dev;
205 
206                         if (r->rtm_scope >= RT_SCOPE_LINK)
207                                 return -EINVAL;
208                         if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
209                                 return -ENODEV;
210                         if (!(dev->flags&IFF_UP))
211                                 return -ENETDOWN;
212                         nh->nh_dev = dev;
213                         atomic_inc(&dev->refcnt);
214                         nh->nh_scope = RT_SCOPE_LINK;
215                         return 0;
216                 }
217 
218                 memset(&key, 0, sizeof(key));
219                 key.dst = nh->nh_gw;
220                 key.oif = nh->nh_oif;
221                 key.scope = r->rtm_scope + 1;
222 
223                 if (key.scope < RT_SCOPE_LINK)
224                         key.scope = RT_SCOPE_LINK;
225 
226                 if ((err = dn_fib_lookup(&key, &res)) != 0)
227                         return err;
228 
229                 nh->nh_scope = res.scope;
230                 nh->nh_oif = DN_FIB_RES_OIF(res);
231                 nh->nh_dev = DN_FIB_RES_DEV(res);
232                 if (nh->nh_dev)
233                         atomic_inc(&nh->nh_dev->refcnt);
234                 dn_fib_res_put(&res);
235         } else {
236                 struct net_device *dev;
237 
238                 if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
239                         return -EINVAL;
240 
241                 dev = __dev_get_by_index(nh->nh_oif);
242                 if (dev == NULL || dev->dn_ptr == NULL)
243                         return -ENODEV;
244                 if (!(dev->flags&IFF_UP))
245                         return -ENETDOWN;
246                 nh->nh_dev = dev;
247                 atomic_inc(&nh->nh_dev->refcnt);
248                 nh->nh_scope = RT_SCOPE_HOST;
249         }
250 
251         return 0;
252 }
253 
254 
255 struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
256 {
257         int err;
258         struct dn_fib_info *fi = NULL;
259         struct dn_fib_info *ofi;
260         int nhs = 1;
261 
262         if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
263                 goto err_inval;
264 
265         if (rta->rta_mp) {
266                 nhs = dn_fib_count_nhs(rta->rta_mp);
267                 if (nhs == 0)
268                         goto err_inval;
269         }
270 
271         fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
272         err = -ENOBUFS;
273         if (fi == NULL)
274                 goto failure;
275         memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh));
276 
277         fi->fib_protocol = r->rtm_protocol;
278         fi->fib_nhs = nhs;
279         fi->fib_flags = r->rtm_flags;
280         if (rta->rta_priority)
281                 fi->fib_priority = *rta->rta_priority;
282         if (rta->rta_prefsrc)
283                 memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
284 
285         if (rta->rta_mp) {
286                 if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
287                         goto failure;
288                 if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
289                         goto err_inval;
290                 if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
291                         goto err_inval;
292         } else {
293                 struct dn_fib_nh *nh = fi->fib_nh;
294                 if (rta->rta_oif)
295                         nh->nh_oif = *rta->rta_oif;
296                 if (rta->rta_gw)
297                         memcpy(&nh->nh_gw, rta->rta_gw, 2);
298                 nh->nh_flags = r->rtm_flags;
299                 nh->nh_weight = 1;
300         }
301 
302         if (dn_fib_props[r->rtm_type].error) {
303                 if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
304                         goto err_inval;
305                 goto link_it;
306         }
307 
308         if (r->rtm_scope > RT_SCOPE_HOST)
309                 goto err_inval;
310 
311         if (r->rtm_scope == RT_SCOPE_HOST) {
312                 struct dn_fib_nh *nh = fi->fib_nh;
313 
314                 /* Local address is added */
315                 if (nhs != 1 || nh->nh_gw)
316                         goto err_inval;
317                 nh->nh_scope = RT_SCOPE_NOWHERE;
318                 nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);
319                 err = -ENODEV;
320                 if (nh->nh_dev == NULL)
321                         goto failure;
322         } else {
323                 change_nexthops(fi) {
324                         if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
325                                 goto failure;
326                 } endfor_nexthops(fi)
327         }
328 
329 #if I_GET_AROUND_TO_FIXING_PREFSRC
330         if (fi->fib_prefsrc) {
331                 if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
332                     memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
333                         if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
334                                 goto err_inval;
335         }
336 #endif
337 
338 link_it:
339         if ((ofi = dn_fib_find_info(fi)) != NULL) {
340                 fi->fib_dead = 1;
341                 dn_fib_free_info(fi);
342                 ofi->fib_treeref++;
343                 return ofi;
344         }
345 
346         fi->fib_treeref++;
347         atomic_inc(&fi->fib_clntref);
348         write_lock(&dn_fib_info_lock);
349         fi->fib_next = dn_fib_info_list;
350         fi->fib_prev = NULL;
351         if (dn_fib_info_list)
352                 dn_fib_info_list->fib_prev = fi;
353         dn_fib_info_list = fi;
354         dn_fib_info_cnt++;
355         write_unlock(&dn_fib_info_lock);
356         return fi;
357 
358 err_inval:
359         err = -EINVAL;
360 
361 failure:
362         *errp = err;
363         if (fi) {
364                 fi->fib_dead = 1;
365                 dn_fib_free_info(fi);
366         }
367 
368         return NULL;
369 }
370 
371 
372 void dn_fib_select_multipath(const struct dn_fib_key *key, struct dn_fib_res *res)
373 {
374         struct dn_fib_info *fi = res->fi;
375         int w;
376 
377         if (fi->fib_power <= 0) {
378                 int power = 0;
379                 change_nexthops(fi) {
380                         if (!(nh->nh_flags&RTNH_F_DEAD)) {
381                                 power += nh->nh_weight;
382                                 nh->nh_power = nh->nh_weight;
383                         }
384                 } endfor_nexthops(fi);
385                 fi->fib_power = power;
386         }
387 
388         w = jiffies % fi->fib_power;
389 
390         change_nexthops(fi) {
391                 if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
392                         if ((w -= nh->nh_power) <= 0) {
393                                 nh->nh_power--;
394                                 fi->fib_power--;
395                                 res->nh_sel = nhsel;
396                                 return;
397                         }
398                 }
399         } endfor_nexthops(fi);
400 
401         printk(KERN_DEBUG "DECnet: BUG! dn_fib_select_multipath\n");
402 }
403 
404 
405 
406 /*
407  * Punt to user via netlink for example, but for now
408  * we just drop it.
409  */
410 int dn_fib_rt_message(struct sk_buff *skb)
411 {
412         kfree_skb(skb);
413 
414         return 0;
415 }
416 
417 
418 #ifdef CONFIG_RTNETLINK
419 
420 static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
421 {
422         int i;
423 
424         for(i = 1; i <= RTA_MAX; i++) {
425                 struct rtattr *attr = rta[i-1];
426                 if (attr) {
427                         if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
428                                 return -EINVAL;
429                         if (i != RTA_MULTIPATH && i != RTA_METRICS)
430                                 rta[i-1] = (struct rtattr *)RTA_DATA(attr);
431                 }
432         }
433 
434         return 0;
435 }
436 
437 int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
438 {
439         struct dn_fib_table *tb;
440         struct rtattr **rta = arg;
441         struct rtmsg *r = NLMSG_DATA(nlh);
442 
443         if (dn_fib_check_attr(r, rta))
444                 return -EINVAL;
445 
446         tb = dn_fib_get_table(r->rtm_table, 0);
447         if (tb)
448                 return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
449 
450         return -ESRCH;
451 }
452 
453 int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
454 {
455         struct dn_fib_table *tb;
456         struct rtattr **rta = arg;
457         struct rtmsg *r = NLMSG_DATA(nlh);
458 
459         if (dn_fib_check_attr(r, rta))
460                 return -EINVAL;
461 
462         tb = dn_fib_get_table(r->rtm_table, 1);
463         if (tb) 
464                 return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
465 
466         return -ENOBUFS;
467 }
468 
469 
470 int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
471 {
472         int t;
473         int s_t;
474         struct dn_fib_table *tb;
475 
476         if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
477                 ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
478                         return dn_cache_dump(skb, cb);
479 
480         s_t = cb->args[0];
481         if (s_t == 0)
482                 s_t = cb->args[0] = DN_MIN_TABLE;
483 
484         for(t = s_t; t < DN_NUM_TABLES; t++) {
485                 if (t < s_t)
486                         continue;
487                 if (t > s_t)
488                         memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(int));
489                 tb = dn_fib_get_table(t, 0);
490                 if (tb == NULL)
491                         continue;
492                 if (tb->dump(tb, skb, cb) < 0)
493                         break;
494         }
495 
496         cb->args[0] = t;
497 
498         return skb->len;
499 }
500 #endif /* CONFIG_RTNETLINK */
501 
502 int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
503 {
504         int ret = 0;
505         int scope = RT_SCOPE_NOWHERE;
506 
507         if (force)
508                 scope = -1;
509 
510         for_fib_info() {
511                 /* 
512                  * This makes no sense for DECnet.... we will almost
513                  * certainly have more than one local address the same
514                  * over all our interfaces. It needs thinking about
515                  * some more.
516                  */
517                 if (local && fi->fib_prefsrc == local) {
518                         fi->fib_flags |= RTNH_F_DEAD;
519                         ret++;
520                 } else if (dev && fi->fib_nhs) {
521                         int dead = 0;
522 
523                         change_nexthops(fi) {
524                                 if (nh->nh_flags&RTNH_F_DEAD)
525                                         dead++;
526                                 else if (nh->nh_dev == dev &&
527                                                 nh->nh_scope != scope) {
528                                         nh->nh_flags |= RTNH_F_DEAD;
529                                         fi->fib_power -= nh->nh_power;
530                                         nh->nh_power = 0;
531                                         dead++;
532                                 }
533                         } endfor_nexthops(fi)
534                         if (dead == fi->fib_nhs) {
535                                 fi->fib_flags |= RTNH_F_DEAD;
536                                 ret++;
537                         }
538                 }
539         } endfor_fib_info();
540         return ret;
541 }
542 
543 
544 int dn_fib_sync_up(struct net_device *dev)
545 {
546         int ret = 0;
547 
548         if (!(dev->flags&IFF_UP))
549                 return 0;
550 
551         for_fib_info() {
552                 int alive = 0;
553 
554                 change_nexthops(fi) {
555                         if (!(nh->nh_flags&RTNH_F_DEAD)) {
556                                 alive++;
557                                 continue;
558                         }
559                         if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
560                                 continue;
561                         if (nh->nh_dev != dev || dev->dn_ptr == NULL)
562                                 continue;
563                         alive++;
564                         nh->nh_power = 0;
565                         nh->nh_flags &= ~RTNH_F_DEAD;
566                 } endfor_nexthops(fi);
567 
568                 if (alive == fi->fib_nhs) {
569                         fi->fib_flags &= ~RTNH_F_DEAD;
570                         ret++;
571                 }
572         } endfor_fib_info();
573         return ret;
574 }
575 
576 void dn_fib_flush(void)
577 {
578         int flushed = 0;
579         struct dn_fib_table *tb;
580         int id;
581 
582         for(id = DN_NUM_TABLES; id > 0; id--) {
583                 if ((tb = dn_fib_get_table(id, 0)) == NULL)
584                         continue;
585                 flushed += tb->flush(tb);
586         }
587 
588         if (flushed)
589                 dn_rt_cache_flush(-1);
590 }
591 
592 int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
593 {
594 
595         if (!capable(CAP_NET_ADMIN))
596                 return -EPERM;
597 
598         switch(cmd) {
599                 case SIOCADDRT:
600                 case SIOCDELRT:
601                         return 0;
602         }
603 
604         return -EINVAL;
605 }
606 
607 #ifdef CONFIG_PROC_FS
608 
609 static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
610 {
611         int first = offset / 128;
612         char *ptr = buffer;
613         int count = (length + 127) / 128;
614         int len;
615         int i;
616         struct dn_fib_table *tb;
617 
618         *start = buffer + (offset % 128);
619 
620         if (--first < 0) {
621                 sprintf(buffer, "%-127s\n", "Iface\tDest\tGW  \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
622                 --count;
623                 ptr += 128;
624                 first = 0;
625         }
626 
627 
628         for(i = DN_MIN_TABLE; (i <= DN_NUM_TABLES) && (count > 0); i++) {
629                 if ((tb = dn_fib_get_table(i, 0)) != NULL) {
630                         int n = tb->get_info(tb, ptr, first, count);
631                         count -= n;
632                         ptr += n * 128;
633                 }
634         }
635 
636         len = ptr - *start;
637         if (len >= length)
638                 return length;
639         if (len >= 0)
640                 return len;
641 
642         return 0;
643 }
644 
645 #endif /* CONFIG_PROC_FS */
646 
647 
648 void __exit dn_fib_cleanup(void)
649 {
650 #ifdef CONFIG_PROC_FS
651         proc_net_remove("decnet_route");
652 #endif
653 
654         dn_fib_table_cleanup();
655         dn_fib_rules_cleanup();
656 }
657 
658 
659 void __init dn_fib_init(void)
660 {
661 
662 #ifdef CONFIG_PROC_FS
663         proc_net_create("decnet_route", 0, decnet_rt_get_info);
664 #endif
665 
666         dn_fib_table_init();
667         dn_fib_rules_init();
668 }
669 
670 
671 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.