fib_frontend.c revision 1af5a8c4a11cfed0c9a7f30fcfb689981750599c
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.
5 *
6 *		IPv4 Forwarding Information Base: FIB frontend.
7 *
8 * Version:	$Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $
9 *
10 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 *
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.
16 */
17
18#include <linux/module.h>
19#include <asm/uaccess.h>
20#include <asm/system.h>
21#include <linux/bitops.h>
22#include <linux/capability.h>
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/sched.h>
26#include <linux/mm.h>
27#include <linux/string.h>
28#include <linux/socket.h>
29#include <linux/sockios.h>
30#include <linux/errno.h>
31#include <linux/in.h>
32#include <linux/inet.h>
33#include <linux/inetdevice.h>
34#include <linux/netdevice.h>
35#include <linux/if_addr.h>
36#include <linux/if_arp.h>
37#include <linux/skbuff.h>
38#include <linux/netlink.h>
39#include <linux/init.h>
40#include <linux/list.h>
41
42#include <net/ip.h>
43#include <net/protocol.h>
44#include <net/route.h>
45#include <net/tcp.h>
46#include <net/sock.h>
47#include <net/icmp.h>
48#include <net/arp.h>
49#include <net/ip_fib.h>
50
51#define FFprint(a...) printk(KERN_DEBUG a)
52
53#ifndef CONFIG_IP_MULTIPLE_TABLES
54
55struct fib_table *ip_fib_local_table;
56struct fib_table *ip_fib_main_table;
57
58#define FIB_TABLE_HASHSZ 1
59static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
60
61#else
62
63#define FIB_TABLE_HASHSZ 256
64static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
65
66struct fib_table *fib_new_table(u32 id)
67{
68	struct fib_table *tb;
69	unsigned int h;
70
71	if (id == 0)
72		id = RT_TABLE_MAIN;
73	tb = fib_get_table(id);
74	if (tb)
75		return tb;
76	tb = fib_hash_init(id);
77	if (!tb)
78		return NULL;
79	h = id & (FIB_TABLE_HASHSZ - 1);
80	hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]);
81	return tb;
82}
83
84struct fib_table *fib_get_table(u32 id)
85{
86	struct fib_table *tb;
87	struct hlist_node *node;
88	unsigned int h;
89
90	if (id == 0)
91		id = RT_TABLE_MAIN;
92	h = id & (FIB_TABLE_HASHSZ - 1);
93	rcu_read_lock();
94	hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) {
95		if (tb->tb_id == id) {
96			rcu_read_unlock();
97			return tb;
98		}
99	}
100	rcu_read_unlock();
101	return NULL;
102}
103#endif /* CONFIG_IP_MULTIPLE_TABLES */
104
105static void fib_flush(void)
106{
107	int flushed = 0;
108	struct fib_table *tb;
109	struct hlist_node *node;
110	unsigned int h;
111
112	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
113		hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist)
114			flushed += tb->tb_flush(tb);
115	}
116
117	if (flushed)
118		rt_cache_flush(-1);
119}
120
121/*
122 *	Find the first device with a given source address.
123 */
124
125struct net_device * ip_dev_find(u32 addr)
126{
127	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
128	struct fib_result res;
129	struct net_device *dev = NULL;
130
131#ifdef CONFIG_IP_MULTIPLE_TABLES
132	res.r = NULL;
133#endif
134
135	if (!ip_fib_local_table ||
136	    ip_fib_local_table->tb_lookup(ip_fib_local_table, &fl, &res))
137		return NULL;
138	if (res.type != RTN_LOCAL)
139		goto out;
140	dev = FIB_RES_DEV(res);
141
142	if (dev)
143		dev_hold(dev);
144out:
145	fib_res_put(&res);
146	return dev;
147}
148
149unsigned inet_addr_type(u32 addr)
150{
151	struct flowi		fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
152	struct fib_result	res;
153	unsigned ret = RTN_BROADCAST;
154
155	if (ZERONET(addr) || BADCLASS(addr))
156		return RTN_BROADCAST;
157	if (MULTICAST(addr))
158		return RTN_MULTICAST;
159
160#ifdef CONFIG_IP_MULTIPLE_TABLES
161	res.r = NULL;
162#endif
163
164	if (ip_fib_local_table) {
165		ret = RTN_UNICAST;
166		if (!ip_fib_local_table->tb_lookup(ip_fib_local_table,
167						   &fl, &res)) {
168			ret = res.type;
169			fib_res_put(&res);
170		}
171	}
172	return ret;
173}
174
175/* Given (packet source, input interface) and optional (dst, oif, tos):
176   - (main) check, that source is valid i.e. not broadcast or our local
177     address.
178   - figure out what "logical" interface this packet arrived
179     and calculate "specific destination" address.
180   - check, that packet arrived from expected physical interface.
181 */
182
183int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
184			struct net_device *dev, u32 *spec_dst, u32 *itag)
185{
186	struct in_device *in_dev;
187	struct flowi fl = { .nl_u = { .ip4_u =
188				      { .daddr = src,
189					.saddr = dst,
190					.tos = tos } },
191			    .iif = oif };
192	struct fib_result res;
193	int no_addr, rpf;
194	int ret;
195
196	no_addr = rpf = 0;
197	rcu_read_lock();
198	in_dev = __in_dev_get_rcu(dev);
199	if (in_dev) {
200		no_addr = in_dev->ifa_list == NULL;
201		rpf = IN_DEV_RPFILTER(in_dev);
202	}
203	rcu_read_unlock();
204
205	if (in_dev == NULL)
206		goto e_inval;
207
208	if (fib_lookup(&fl, &res))
209		goto last_resort;
210	if (res.type != RTN_UNICAST)
211		goto e_inval_res;
212	*spec_dst = FIB_RES_PREFSRC(res);
213	fib_combine_itag(itag, &res);
214#ifdef CONFIG_IP_ROUTE_MULTIPATH
215	if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
216#else
217	if (FIB_RES_DEV(res) == dev)
218#endif
219	{
220		ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
221		fib_res_put(&res);
222		return ret;
223	}
224	fib_res_put(&res);
225	if (no_addr)
226		goto last_resort;
227	if (rpf)
228		goto e_inval;
229	fl.oif = dev->ifindex;
230
231	ret = 0;
232	if (fib_lookup(&fl, &res) == 0) {
233		if (res.type == RTN_UNICAST) {
234			*spec_dst = FIB_RES_PREFSRC(res);
235			ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
236		}
237		fib_res_put(&res);
238	}
239	return ret;
240
241last_resort:
242	if (rpf)
243		goto e_inval;
244	*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
245	*itag = 0;
246	return 0;
247
248e_inval_res:
249	fib_res_put(&res);
250e_inval:
251	return -EINVAL;
252}
253
254#ifndef CONFIG_IP_NOSIOCRT
255
256/*
257 *	Handle IP routing ioctl calls. These are used to manipulate the routing tables
258 */
259
260int ip_rt_ioctl(unsigned int cmd, void __user *arg)
261{
262	int err;
263	struct kern_rta rta;
264	struct rtentry  r;
265	struct {
266		struct nlmsghdr nlh;
267		struct rtmsg	rtm;
268	} req;
269
270	switch (cmd) {
271	case SIOCADDRT:		/* Add a route */
272	case SIOCDELRT:		/* Delete a route */
273		if (!capable(CAP_NET_ADMIN))
274			return -EPERM;
275		if (copy_from_user(&r, arg, sizeof(struct rtentry)))
276			return -EFAULT;
277		rtnl_lock();
278		err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
279		if (err == 0) {
280			if (cmd == SIOCDELRT) {
281				struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
282				err = -ESRCH;
283				if (tb)
284					err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
285			} else {
286				struct fib_table *tb = fib_new_table(req.rtm.rtm_table);
287				err = -ENOBUFS;
288				if (tb)
289					err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
290			}
291			kfree(rta.rta_mx);
292		}
293		rtnl_unlock();
294		return err;
295	}
296	return -EINVAL;
297}
298
299#else
300
301int ip_rt_ioctl(unsigned int cmd, void *arg)
302{
303	return -EINVAL;
304}
305
306#endif
307
308static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
309{
310	int i;
311
312	for (i=1; i<=RTA_MAX; i++, rta++) {
313		struct rtattr *attr = *rta;
314		if (attr) {
315			if (RTA_PAYLOAD(attr) < 4)
316				return -EINVAL;
317			if (i != RTA_MULTIPATH && i != RTA_METRICS &&
318			    i != RTA_TABLE)
319				*rta = (struct rtattr*)RTA_DATA(attr);
320		}
321	}
322	return 0;
323}
324
325int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
326{
327	struct fib_table * tb;
328	struct rtattr **rta = arg;
329	struct rtmsg *r = NLMSG_DATA(nlh);
330
331	if (inet_check_attr(r, rta))
332		return -EINVAL;
333
334	tb = fib_get_table(rtm_get_table(rta, r->rtm_table));
335	if (tb)
336		return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
337	return -ESRCH;
338}
339
340int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
341{
342	struct fib_table * tb;
343	struct rtattr **rta = arg;
344	struct rtmsg *r = NLMSG_DATA(nlh);
345
346	if (inet_check_attr(r, rta))
347		return -EINVAL;
348
349	tb = fib_new_table(rtm_get_table(rta, r->rtm_table));
350	if (tb)
351		return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
352	return -ENOBUFS;
353}
354
355int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
356{
357	unsigned int h, s_h;
358	unsigned int e = 0, s_e;
359	struct fib_table *tb;
360	struct hlist_node *node;
361	int dumped = 0;
362
363	if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
364	    ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
365		return ip_rt_dump(skb, cb);
366
367	s_h = cb->args[0];
368	s_e = cb->args[1];
369
370	for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
371		e = 0;
372		hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) {
373			if (e < s_e)
374				goto next;
375			if (dumped)
376				memset(&cb->args[2], 0, sizeof(cb->args) -
377				                 2 * sizeof(cb->args[0]));
378			if (tb->tb_dump(tb, skb, cb) < 0)
379				goto out;
380			dumped = 1;
381next:
382			e++;
383		}
384	}
385out:
386	cb->args[1] = e;
387	cb->args[0] = h;
388
389	return skb->len;
390}
391
392/* Prepare and feed intra-kernel routing request.
393   Really, it should be netlink message, but :-( netlink
394   can be not configured, so that we feed it directly
395   to fib engine. It is legal, because all events occur
396   only when netlink is already locked.
397 */
398
399static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa)
400{
401	struct fib_table * tb;
402	struct {
403		struct nlmsghdr	nlh;
404		struct rtmsg	rtm;
405	} req;
406	struct kern_rta rta;
407
408	memset(&req.rtm, 0, sizeof(req.rtm));
409	memset(&rta, 0, sizeof(rta));
410
411	if (type == RTN_UNICAST)
412		tb = fib_new_table(RT_TABLE_MAIN);
413	else
414		tb = fib_new_table(RT_TABLE_LOCAL);
415
416	if (tb == NULL)
417		return;
418
419	req.nlh.nlmsg_len = sizeof(req);
420	req.nlh.nlmsg_type = cmd;
421	req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
422	req.nlh.nlmsg_pid = 0;
423	req.nlh.nlmsg_seq = 0;
424
425	req.rtm.rtm_dst_len = dst_len;
426	req.rtm.rtm_table = tb->tb_id;
427	req.rtm.rtm_protocol = RTPROT_KERNEL;
428	req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
429	req.rtm.rtm_type = type;
430
431	rta.rta_dst = &dst;
432	rta.rta_prefsrc = &ifa->ifa_local;
433	rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
434
435	if (cmd == RTM_NEWROUTE)
436		tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
437	else
438		tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
439}
440
441void fib_add_ifaddr(struct in_ifaddr *ifa)
442{
443	struct in_device *in_dev = ifa->ifa_dev;
444	struct net_device *dev = in_dev->dev;
445	struct in_ifaddr *prim = ifa;
446	u32 mask = ifa->ifa_mask;
447	u32 addr = ifa->ifa_local;
448	u32 prefix = ifa->ifa_address&mask;
449
450	if (ifa->ifa_flags&IFA_F_SECONDARY) {
451		prim = inet_ifa_byprefix(in_dev, prefix, mask);
452		if (prim == NULL) {
453			printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
454			return;
455		}
456	}
457
458	fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
459
460	if (!(dev->flags&IFF_UP))
461		return;
462
463	/* Add broadcast address, if it is explicitly assigned. */
464	if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
465		fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
466
467	if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
468	    (prefix != addr || ifa->ifa_prefixlen < 32)) {
469		fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
470			  RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
471
472		/* Add network specific broadcasts, when it takes a sense */
473		if (ifa->ifa_prefixlen < 31) {
474			fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
475			fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
476		}
477	}
478}
479
480static void fib_del_ifaddr(struct in_ifaddr *ifa)
481{
482	struct in_device *in_dev = ifa->ifa_dev;
483	struct net_device *dev = in_dev->dev;
484	struct in_ifaddr *ifa1;
485	struct in_ifaddr *prim = ifa;
486	u32 brd = ifa->ifa_address|~ifa->ifa_mask;
487	u32 any = ifa->ifa_address&ifa->ifa_mask;
488#define LOCAL_OK	1
489#define BRD_OK		2
490#define BRD0_OK		4
491#define BRD1_OK		8
492	unsigned ok = 0;
493
494	if (!(ifa->ifa_flags&IFA_F_SECONDARY))
495		fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
496			  RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
497	else {
498		prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
499		if (prim == NULL) {
500			printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
501			return;
502		}
503	}
504
505	/* Deletion is more complicated than add.
506	   We should take care of not to delete too much :-)
507
508	   Scan address list to be sure that addresses are really gone.
509	 */
510
511	for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
512		if (ifa->ifa_local == ifa1->ifa_local)
513			ok |= LOCAL_OK;
514		if (ifa->ifa_broadcast == ifa1->ifa_broadcast)
515			ok |= BRD_OK;
516		if (brd == ifa1->ifa_broadcast)
517			ok |= BRD1_OK;
518		if (any == ifa1->ifa_broadcast)
519			ok |= BRD0_OK;
520	}
521
522	if (!(ok&BRD_OK))
523		fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
524	if (!(ok&BRD1_OK))
525		fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
526	if (!(ok&BRD0_OK))
527		fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
528	if (!(ok&LOCAL_OK)) {
529		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
530
531		/* Check, that this local address finally disappeared. */
532		if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
533			/* And the last, but not the least thing.
534			   We must flush stray FIB entries.
535
536			   First of all, we scan fib_info list searching
537			   for stray nexthop entries, then ignite fib_flush.
538			*/
539			if (fib_sync_down(ifa->ifa_local, NULL, 0))
540				fib_flush();
541		}
542	}
543#undef LOCAL_OK
544#undef BRD_OK
545#undef BRD0_OK
546#undef BRD1_OK
547}
548
549static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
550{
551
552	struct fib_result       res;
553	struct flowi            fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr,
554							    .fwmark = frn->fl_fwmark,
555							    .tos = frn->fl_tos,
556							    .scope = frn->fl_scope } } };
557	if (tb) {
558		local_bh_disable();
559
560		frn->tb_id = tb->tb_id;
561		frn->err = tb->tb_lookup(tb, &fl, &res);
562
563		if (!frn->err) {
564			frn->prefixlen = res.prefixlen;
565			frn->nh_sel = res.nh_sel;
566			frn->type = res.type;
567			frn->scope = res.scope;
568		}
569		local_bh_enable();
570	}
571}
572
573static void nl_fib_input(struct sock *sk, int len)
574{
575	struct sk_buff *skb = NULL;
576        struct nlmsghdr *nlh = NULL;
577	struct fib_result_nl *frn;
578	u32 pid;
579	struct fib_table *tb;
580
581	skb = skb_dequeue(&sk->sk_receive_queue);
582	nlh = (struct nlmsghdr *)skb->data;
583	if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
584	    nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) {
585		kfree_skb(skb);
586		return;
587	}
588
589	frn = (struct fib_result_nl *) NLMSG_DATA(nlh);
590	tb = fib_get_table(frn->tb_id_in);
591
592	nl_fib_lookup(frn, tb);
593
594	pid = nlh->nlmsg_pid;           /*pid of sending process */
595	NETLINK_CB(skb).pid = 0;         /* from kernel */
596	NETLINK_CB(skb).dst_pid = pid;
597	NETLINK_CB(skb).dst_group = 0;  /* unicast */
598	netlink_unicast(sk, skb, pid, MSG_DONTWAIT);
599}
600
601static void nl_fib_lookup_init(void)
602{
603      netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, THIS_MODULE);
604}
605
606static void fib_disable_ip(struct net_device *dev, int force)
607{
608	if (fib_sync_down(0, dev, force))
609		fib_flush();
610	rt_cache_flush(0);
611	arp_ifdown(dev);
612}
613
614static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
615{
616	struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
617
618	switch (event) {
619	case NETDEV_UP:
620		fib_add_ifaddr(ifa);
621#ifdef CONFIG_IP_ROUTE_MULTIPATH
622		fib_sync_up(ifa->ifa_dev->dev);
623#endif
624		rt_cache_flush(-1);
625		break;
626	case NETDEV_DOWN:
627		fib_del_ifaddr(ifa);
628		if (ifa->ifa_dev->ifa_list == NULL) {
629			/* Last address was deleted from this interface.
630			   Disable IP.
631			 */
632			fib_disable_ip(ifa->ifa_dev->dev, 1);
633		} else {
634			rt_cache_flush(-1);
635		}
636		break;
637	}
638	return NOTIFY_DONE;
639}
640
641static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
642{
643	struct net_device *dev = ptr;
644	struct in_device *in_dev = __in_dev_get_rtnl(dev);
645
646	if (event == NETDEV_UNREGISTER) {
647		fib_disable_ip(dev, 2);
648		return NOTIFY_DONE;
649	}
650
651	if (!in_dev)
652		return NOTIFY_DONE;
653
654	switch (event) {
655	case NETDEV_UP:
656		for_ifa(in_dev) {
657			fib_add_ifaddr(ifa);
658		} endfor_ifa(in_dev);
659#ifdef CONFIG_IP_ROUTE_MULTIPATH
660		fib_sync_up(dev);
661#endif
662		rt_cache_flush(-1);
663		break;
664	case NETDEV_DOWN:
665		fib_disable_ip(dev, 0);
666		break;
667	case NETDEV_CHANGEMTU:
668	case NETDEV_CHANGE:
669		rt_cache_flush(0);
670		break;
671	}
672	return NOTIFY_DONE;
673}
674
675static struct notifier_block fib_inetaddr_notifier = {
676	.notifier_call =fib_inetaddr_event,
677};
678
679static struct notifier_block fib_netdev_notifier = {
680	.notifier_call =fib_netdev_event,
681};
682
683void __init ip_fib_init(void)
684{
685	unsigned int i;
686
687	for (i = 0; i < FIB_TABLE_HASHSZ; i++)
688		INIT_HLIST_HEAD(&fib_table_hash[i]);
689#ifndef CONFIG_IP_MULTIPLE_TABLES
690	ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);
691	hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]);
692	ip_fib_main_table  = fib_hash_init(RT_TABLE_MAIN);
693	hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]);
694#else
695	fib4_rules_init();
696#endif
697
698	register_netdevice_notifier(&fib_netdev_notifier);
699	register_inetaddr_notifier(&fib_inetaddr_notifier);
700	nl_fib_lookup_init();
701}
702
703EXPORT_SYMBOL(inet_addr_type);
704EXPORT_SYMBOL(ip_dev_find);
705