Import 2.1.120pre1
[davej-history.git] / net / ipv4 / fib_frontend.c
blob013a4ba9a95e2e64298bf73adc2d3446be1c3c55
1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
6 * IPv4 Forwarding Information Base: FIB frontend.
8 * Version: $Id: fib_frontend.c,v 1.12 1998/08/26 12:03:24 davem Exp $
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
18 #include <linux/config.h>
19 #include <asm/uaccess.h>
20 #include <asm/system.h>
21 #include <asm/bitops.h>
22 #include <linux/types.h>
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/mm.h>
26 #include <linux/string.h>
27 #include <linux/socket.h>
28 #include <linux/sockios.h>
29 #include <linux/errno.h>
30 #include <linux/in.h>
31 #include <linux/inet.h>
32 #include <linux/netdevice.h>
33 #include <linux/if_arp.h>
34 #include <linux/proc_fs.h>
35 #include <linux/skbuff.h>
36 #include <linux/netlink.h>
37 #include <linux/init.h>
39 #include <net/ip.h>
40 #include <net/protocol.h>
41 #include <net/route.h>
42 #include <net/tcp.h>
43 #include <net/sock.h>
44 #include <net/icmp.h>
45 #include <net/arp.h>
46 #include <net/ip_fib.h>
48 #define FFprint(a...) printk(KERN_DEBUG a)
50 #ifndef CONFIG_IP_MULTIPLE_TABLES
52 #define RT_TABLE_MIN RT_TABLE_MAIN
54 struct fib_table *local_table;
55 struct fib_table *main_table;
57 #else
59 #define RT_TABLE_MIN 1
61 struct fib_table *fib_tables[RT_TABLE_MAX+1];
63 struct fib_table *__fib_new_table(int id)
65 struct fib_table *tb;
67 tb =fib_hash_init(id);
68 if(!tb)
69 return NULL;
70 fib_tables[id] = tb;
71 return tb;
75 #endif/* CONFIG_IP_MULTIPLE_TABLES */
78 voidfib_flush(void)
80 int flushed =0;
81 #ifdef CONFIG_IP_MULTIPLE_TABLES
82 struct fib_table *tb;
83 int id;
85 for(id = RT_TABLE_MAX; id>0; id--) {
86 if((tb =fib_get_table(id))==NULL)
87 continue;
88 flushed += tb->tb_flush(tb);
90 #else/* CONFIG_IP_MULTIPLE_TABLES */
91 flushed += main_table->tb_flush(main_table);
92 flushed += local_table->tb_flush(local_table);
93 #endif/* CONFIG_IP_MULTIPLE_TABLES */
95 if(flushed)
96 rt_cache_flush(-1);
100 #ifdef CONFIG_PROC_FS
103 * Called from the PROCfs module. This outputs /proc/net/route.
105 * It always works in backward compatibility mode.
106 * The format of the file is not supposed to be changed.
109 static int
110 fib_get_procinfo(char*buffer,char**start, off_t offset,int length,int dummy)
112 int first = offset/128;
113 char*ptr = buffer;
114 int count = (length+127)/128;
115 int len;
117 *start = buffer + offset%128;
119 if(--first <0) {
120 sprintf(buffer,"%-127s\n","Iface\tDestination\tGateway\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
121 --count;
122 ptr +=128;
123 first =0;
126 /* rtnl_shlock(); -- it is pointless at the moment --ANK */
127 if(main_table && count >0) {
128 int n = main_table->tb_get_info(main_table, ptr, first, count);
129 count -= n;
130 ptr += n*128;
132 /* rtnl_shunlock(); */
133 len = ptr - *start;
134 if(len >= length)
135 return length;
136 if(len >=0)
137 return len;
138 return0;
141 #endif/* CONFIG_PROC_FS */
144 * Find the first device with a given source address.
147 struct device *ip_dev_find(u32 addr)
149 struct rt_key key;
150 struct fib_result res;
152 memset(&key,0,sizeof(key));
153 key.dst = addr;
155 if(!local_table || local_table->tb_lookup(local_table, &key, &res)
156 || res.type != RTN_LOCAL)
157 return NULL;
159 returnFIB_RES_DEV(res);
162 unsignedinet_addr_type(u32 addr)
164 struct rt_key key;
165 struct fib_result res;
167 if(ZERONET(addr) ||BADCLASS(addr))
168 return RTN_BROADCAST;
169 if(MULTICAST(addr))
170 return RTN_MULTICAST;
172 memset(&key,0,sizeof(key));
173 key.dst = addr;
175 if(local_table) {
176 if(local_table->tb_lookup(local_table, &key, &res) ==0)
177 return res.type;
178 return RTN_UNICAST;
180 return RTN_BROADCAST;
183 /* Given (packet source, input interface) and optional (dst, oif, tos):
184 - (main) check, that source is valid i.e. not broadcast or our local
185 address.
186 - figure out what "logical" interface this packet arrived
187 and calculate "specific destination" address.
188 - check, that packet arrived from expected physical interface.
191 intfib_validate_source(u32 src, u32 dst, u8 tos,int oif,
192 struct device *dev, u32 *spec_dst)
194 struct in_device *in_dev = dev->ip_ptr;
195 struct rt_key key;
196 struct fib_result res;
198 key.dst = src;
199 key.src = dst;
200 key.tos = tos;
201 key.oif =0;
202 key.iif = oif;
203 key.scope = RT_SCOPE_UNIVERSE;
205 if(in_dev == NULL)
206 return-EINVAL;
207 if(fib_lookup(&key, &res))
208 goto last_resort;
209 if(res.type != RTN_UNICAST)
210 return-EINVAL;
211 *spec_dst =FIB_RES_PREFSRC(res);
212 #ifdef CONFIG_IP_ROUTE_MULTIPATH
213 if(FIB_RES_DEV(res) == dev || res.fi->fib_nhs >1)
214 #else
215 if(FIB_RES_DEV(res) == dev)
216 #endif
217 returnFIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
219 if(in_dev->ifa_list == NULL)
220 goto last_resort;
221 if(IN_DEV_RPFILTER(in_dev))
222 return-EINVAL;
223 key.oif = dev->ifindex;
224 if(fib_lookup(&key, &res) ==0&& res.type == RTN_UNICAST) {
225 *spec_dst =FIB_RES_PREFSRC(res);
226 returnFIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
228 return0;
230 last_resort:
231 if(IN_DEV_RPFILTER(in_dev))
232 return-EINVAL;
233 *spec_dst =inet_select_addr(dev,0, RT_SCOPE_UNIVERSE);
234 return0;
237 #ifndef CONFIG_IP_NOSIOCRT
240 * Handle IP routing ioctl calls. These are used to manipulate the routing tables
243 intip_rt_ioctl(unsigned int cmd,void*arg)
245 int err;
246 struct kern_rta rta;
247 struct rtentry r;
248 struct{
249 struct nlmsghdr nlh;
250 struct rtmsg rtm;
251 } req;
253 switch(cmd) {
254 case SIOCADDRT:/* Add a route */
255 case SIOCDELRT:/* Delete a route */
256 if(!capable(CAP_NET_ADMIN))
257 return-EPERM;
258 if(copy_from_user(&r, arg,sizeof(struct rtentry)))
259 return-EFAULT;
260 rtnl_lock();
261 err =fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
262 if(err ==0) {
263 if(cmd == SIOCDELRT) {
264 struct fib_table *tb =fib_get_table(req.rtm.rtm_table);
265 err = -ESRCH;
266 if(tb)
267 err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
268 }else{
269 struct fib_table *tb =fib_new_table(req.rtm.rtm_table);
270 err = -ENOBUFS;
271 if(tb)
272 err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
274 if(rta.rta_mx)
275 kfree(rta.rta_mx);
277 rtnl_unlock();
278 return err;
280 return-EINVAL;
283 #else
285 intip_rt_ioctl(unsigned int cmd,void*arg)
287 return-EINVAL;
290 #endif
292 #ifdef CONFIG_RTNETLINK
294 static intinet_check_attr(struct rtmsg *r,struct rtattr **rta)
296 int i;
298 for(i=1; i<=RTA_MAX; i++) {
299 struct rtattr *attr = rta[i-1];
300 if(attr) {
301 if(RTA_PAYLOAD(attr) <4)
302 return-EINVAL;
303 if(i != RTA_MULTIPATH && i != RTA_METRICS)
304 rta[i-1] = (struct rtattr*)RTA_DATA(attr);
307 return0;
310 intinet_rtm_delroute(struct sk_buff *skb,struct nlmsghdr* nlh,void*arg)
312 struct fib_table * tb;
313 struct rtattr **rta = arg;
314 struct rtmsg *r =NLMSG_DATA(nlh);
316 if(inet_check_attr(r, rta))
317 return-EINVAL;
319 tb =fib_get_table(r->rtm_table);
320 if(tb)
321 return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
322 return-ESRCH;
325 intinet_rtm_newroute(struct sk_buff *skb,struct nlmsghdr* nlh,void*arg)
327 struct fib_table * tb;
328 struct rtattr **rta = arg;
329 struct rtmsg *r =NLMSG_DATA(nlh);
331 if(inet_check_attr(r, rta))
332 return-EINVAL;
334 tb =fib_new_table(r->rtm_table);
335 if(tb)
336 return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
337 return-ENOBUFS;
340 intinet_dump_fib(struct sk_buff *skb,struct netlink_callback *cb)
342 int t;
343 int s_t;
344 struct fib_table *tb;
346 if(NLMSG_PAYLOAD(cb->nlh,0) >=sizeof(struct rtmsg) &&
347 ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
348 returnip_rt_dump(skb, cb);
350 s_t = cb->args[0];
351 if(s_t ==0)
352 s_t = cb->args[0] = RT_TABLE_MIN;
354 for(t=s_t; t<=RT_TABLE_MAX; t++) {
355 if(t < s_t)continue;
356 if(t > s_t)
357 memset(&cb->args[1],0,sizeof(cb->args)-sizeof(int));
358 if((tb =fib_get_table(t))==NULL)
359 continue;
360 if(tb->tb_dump(tb, skb, cb) <0)
361 break;
364 cb->args[0] = t;
366 return skb->len;
369 #endif
371 /* Prepare and feed intra-kernel routing request.
372 Really, it should be netlink message, but :-( netlink
373 can be not configured, so that we feed it directly
374 to fib engine. It is legal, because all events occur
375 only when netlink is already locked.
378 static voidfib_magic(int cmd,int type, u32 dst,int dst_len,struct in_ifaddr *ifa)
380 struct fib_table * tb;
381 struct{
382 struct nlmsghdr nlh;
383 struct rtmsg rtm;
384 } req;
385 struct kern_rta rta;
387 memset(&req.rtm,0,sizeof(req.rtm));
388 memset(&rta,0,sizeof(rta));
390 if(type == RTN_UNICAST)
391 tb =fib_new_table(RT_TABLE_MAIN);
392 else
393 tb =fib_new_table(RT_TABLE_LOCAL);
395 if(tb == NULL)
396 return;
398 req.nlh.nlmsg_len =sizeof(req);
399 req.nlh.nlmsg_type = cmd;
400 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
401 req.nlh.nlmsg_pid =0;
402 req.nlh.nlmsg_seq =0;
404 req.rtm.rtm_dst_len = dst_len;
405 req.rtm.rtm_table = tb->tb_id;
406 req.rtm.rtm_protocol = RTPROT_KERNEL;
407 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
408 req.rtm.rtm_type = type;
410 rta.rta_dst = &dst;
411 rta.rta_prefsrc = &ifa->ifa_local;
412 rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
414 if(cmd == RTM_NEWROUTE)
415 tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
416 else
417 tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
420 static voidfib_add_ifaddr(struct in_ifaddr *ifa)
422 struct in_device *in_dev = ifa->ifa_dev;
423 struct device *dev = in_dev->dev;
424 struct in_ifaddr *prim = ifa;
425 u32 mask = ifa->ifa_mask;
426 u32 addr = ifa->ifa_local;
427 u32 prefix = ifa->ifa_address&mask;
429 if(ifa->ifa_flags&IFA_F_SECONDARY) {
430 prim =inet_ifa_byprefix(in_dev, prefix, mask);
431 if(prim == NULL) {
432 printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
433 return;
437 fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr,32, prim);
439 if(!(dev->flags&IFF_UP))
440 return;
442 /* Add broadcast address, if it is explicitly assigned. */
443 if(ifa->ifa_broadcast && ifa->ifa_broadcast !=0xFFFFFFFF)
444 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast,32, prim);
446 if(!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
447 (prefix != addr || ifa->ifa_prefixlen <32)) {
448 fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
449 RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
451 /* Add network specific broadcasts, when it takes a sense */
452 if(ifa->ifa_prefixlen <31) {
453 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix,32, prim);
454 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask,32, prim);
459 static voidfib_del_ifaddr(struct in_ifaddr *ifa)
461 struct in_device *in_dev = ifa->ifa_dev;
462 struct device *dev = in_dev->dev;
463 struct in_ifaddr *ifa1;
464 struct in_ifaddr *prim = ifa;
465 u32 brd = ifa->ifa_address|~ifa->ifa_mask;
466 u32 any = ifa->ifa_address&ifa->ifa_mask;
467 #define LOCAL_OK 1
468 #define BRD_OK 2
469 #define BRD0_OK 4
470 #define BRD1_OK 8
471 unsigned ok =0;
473 if(!(ifa->ifa_flags&IFA_F_SECONDARY))
474 fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
475 RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
476 else{
477 prim =inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
478 if(prim == NULL) {
479 printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
480 return;
484 /* Deletion is more complicated than add.
485 We should take care of not to delete too much :-)
487 Scan address list to be sure that addresses are really gone.
490 for(ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
491 if(ifa->ifa_local == ifa1->ifa_local)
492 ok |= LOCAL_OK;
493 if(ifa->ifa_broadcast == ifa1->ifa_broadcast)
494 ok |= BRD_OK;
495 if(brd == ifa1->ifa_broadcast)
496 ok |= BRD1_OK;
497 if(any == ifa1->ifa_broadcast)
498 ok |= BRD0_OK;
501 if(!(ok&BRD_OK))
502 fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast,32, prim);
503 if(!(ok&BRD1_OK))
504 fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd,32, prim);
505 if(!(ok&BRD0_OK))
506 fib_magic(RTM_DELROUTE, RTN_BROADCAST, any,32, prim);
507 if(!(ok&LOCAL_OK)) {
508 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local,32, prim);
510 /* Check, that this local address finally disappeared. */
511 if(inet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
512 /* And the last, but not the least thing.
513 We must flush stray FIB entries.
515 First of all, we scan fib_info list searching
516 for stray nexthop entries, then ignite fib_flush.
518 if(fib_sync_down(ifa->ifa_local, NULL,0))
519 fib_flush();
522 #undef LOCAL_OK
523 #undef BRD_OK
524 #undef BRD0_OK
525 #undef BRD1_OK
528 static voidfib_disable_ip(struct device *dev,int force)
530 if(fib_sync_down(0, dev, force))
531 fib_flush();
532 rt_cache_flush(0);
533 arp_ifdown(dev);
536 static intfib_inetaddr_event(struct notifier_block *this,unsigned long event,void*ptr)
538 struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
540 switch(event) {
541 case NETDEV_UP:
542 fib_add_ifaddr(ifa);
543 rt_cache_flush(-1);
544 break;
545 case NETDEV_DOWN:
546 if(ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
547 /* Last address was deleted from this interface.
548 Disable IP.
550 fib_disable_ip(ifa->ifa_dev->dev,1);
551 }else{
552 fib_del_ifaddr(ifa);
553 rt_cache_flush(-1);
555 break;
557 return NOTIFY_DONE;
560 static intfib_netdev_event(struct notifier_block *this,unsigned long event,void*ptr)
562 struct device *dev = ptr;
563 struct in_device *in_dev = dev->ip_ptr;
565 if(!in_dev)
566 return NOTIFY_DONE;
568 switch(event) {
569 case NETDEV_UP:
570 for_ifa(in_dev) {
571 fib_add_ifaddr(ifa);
572 }endfor_ifa(in_dev);
573 #ifdef CONFIG_IP_ROUTE_MULTIPATH
574 fib_sync_up(dev);
575 #endif
576 rt_cache_flush(-1);
577 break;
578 case NETDEV_DOWN:
579 fib_disable_ip(dev,0);
580 break;
581 case NETDEV_UNREGISTER:
582 fib_disable_ip(dev,1);
583 break;
584 case NETDEV_CHANGEMTU:
585 case NETDEV_CHANGE:
586 rt_cache_flush(0);
587 break;
589 return NOTIFY_DONE;
592 struct notifier_block fib_inetaddr_notifier = {
593 fib_inetaddr_event,
594 NULL,
598 struct notifier_block fib_netdev_notifier = {
599 fib_netdev_event,
600 NULL,
604 __initfunc(voidip_fib_init(void))
606 #ifdef CONFIG_PROC_FS
607 proc_net_register(&(struct proc_dir_entry) {
608 PROC_NET_ROUTE,5,"route",
609 S_IFREG | S_IRUGO,1,0,0,
610 0, &proc_net_inode_operations,
611 fib_get_procinfo
613 #endif/* CONFIG_PROC_FS */
615 #ifndef CONFIG_IP_MULTIPLE_TABLES
616 local_table =fib_hash_init(RT_TABLE_LOCAL);
617 main_table =fib_hash_init(RT_TABLE_MAIN);
618 #else
619 fib_rules_init();
620 #endif
622 register_netdevice_notifier(&fib_netdev_notifier);
623 register_inetaddr_notifier(&fib_inetaddr_notifier);
close