11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * INET An implementation of the TCP/IP protocol suite for the LINUX 31da177e4SLinus Torvalds * operating system. INET is implemented using the BSD Socket 41da177e4SLinus Torvalds * interface as the means of communication with the user level. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * IPv4 Forwarding Information Base: policy rules. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Version: $Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $ 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 131da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 141da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 151da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * Fixes: 181da177e4SLinus Torvalds * Rani Assaf : local_rule cannot be deleted 191da177e4SLinus Torvalds * Marc Boucher : routing by fwmark 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <linux/config.h> 231da177e4SLinus Torvalds #include <asm/uaccess.h> 241da177e4SLinus Torvalds #include <asm/system.h> 251da177e4SLinus Torvalds #include <linux/bitops.h> 261da177e4SLinus Torvalds #include <linux/types.h> 271da177e4SLinus Torvalds #include <linux/kernel.h> 281da177e4SLinus Torvalds #include <linux/sched.h> 291da177e4SLinus Torvalds #include <linux/mm.h> 301da177e4SLinus Torvalds #include <linux/string.h> 311da177e4SLinus Torvalds #include <linux/socket.h> 321da177e4SLinus Torvalds #include <linux/sockios.h> 331da177e4SLinus Torvalds #include <linux/errno.h> 341da177e4SLinus Torvalds #include <linux/in.h> 351da177e4SLinus Torvalds #include <linux/inet.h> 3614c85021SArnaldo Carvalho de Melo #include <linux/inetdevice.h> 371da177e4SLinus Torvalds #include <linux/netdevice.h> 381da177e4SLinus Torvalds #include <linux/if_arp.h> 391da177e4SLinus Torvalds #include <linux/proc_fs.h> 401da177e4SLinus Torvalds #include <linux/skbuff.h> 411da177e4SLinus Torvalds #include <linux/netlink.h> 421da177e4SLinus Torvalds #include <linux/init.h> 43*7b204afdSRobert Olsson #include <linux/list.h> 44*7b204afdSRobert Olsson #include <linux/rcupdate.h> 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #include <net/ip.h> 471da177e4SLinus Torvalds #include <net/protocol.h> 481da177e4SLinus Torvalds #include <net/route.h> 491da177e4SLinus Torvalds #include <net/tcp.h> 501da177e4SLinus Torvalds #include <net/sock.h> 511da177e4SLinus Torvalds #include <net/ip_fib.h> 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds #define FRprintk(a...) 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds struct fib_rule 561da177e4SLinus Torvalds { 57*7b204afdSRobert Olsson struct hlist_node hlist; 581da177e4SLinus Torvalds atomic_t r_clntref; 591da177e4SLinus Torvalds u32 r_preference; 601da177e4SLinus Torvalds unsigned char r_table; 611da177e4SLinus Torvalds unsigned char r_action; 621da177e4SLinus Torvalds unsigned char r_dst_len; 631da177e4SLinus Torvalds unsigned char r_src_len; 641da177e4SLinus Torvalds u32 r_src; 651da177e4SLinus Torvalds u32 r_srcmask; 661da177e4SLinus Torvalds u32 r_dst; 671da177e4SLinus Torvalds u32 r_dstmask; 681da177e4SLinus Torvalds u32 r_srcmap; 691da177e4SLinus Torvalds u8 r_flags; 701da177e4SLinus Torvalds u8 r_tos; 711da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 721da177e4SLinus Torvalds u32 r_fwmark; 731da177e4SLinus Torvalds #endif 741da177e4SLinus Torvalds int r_ifindex; 751da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 761da177e4SLinus Torvalds __u32 r_tclassid; 771da177e4SLinus Torvalds #endif 781da177e4SLinus Torvalds char r_ifname[IFNAMSIZ]; 791da177e4SLinus Torvalds int r_dead; 80*7b204afdSRobert Olsson struct rcu_head rcu; 811da177e4SLinus Torvalds }; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds static struct fib_rule default_rule = { 841da177e4SLinus Torvalds .r_clntref = ATOMIC_INIT(2), 851da177e4SLinus Torvalds .r_preference = 0x7FFF, 861da177e4SLinus Torvalds .r_table = RT_TABLE_DEFAULT, 871da177e4SLinus Torvalds .r_action = RTN_UNICAST, 881da177e4SLinus Torvalds }; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds static struct fib_rule main_rule = { 911da177e4SLinus Torvalds .r_clntref = ATOMIC_INIT(2), 921da177e4SLinus Torvalds .r_preference = 0x7FFE, 931da177e4SLinus Torvalds .r_table = RT_TABLE_MAIN, 941da177e4SLinus Torvalds .r_action = RTN_UNICAST, 951da177e4SLinus Torvalds }; 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static struct fib_rule local_rule = { 981da177e4SLinus Torvalds .r_clntref = ATOMIC_INIT(2), 991da177e4SLinus Torvalds .r_table = RT_TABLE_LOCAL, 1001da177e4SLinus Torvalds .r_action = RTN_UNICAST, 1011da177e4SLinus Torvalds }; 1021da177e4SLinus Torvalds 103*7b204afdSRobert Olsson struct hlist_head fib_rules; 104*7b204afdSRobert Olsson 105*7b204afdSRobert Olsson /* writer func called from netlink -- rtnl_sem hold*/ 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 1081da177e4SLinus Torvalds { 1091da177e4SLinus Torvalds struct rtattr **rta = arg; 1101da177e4SLinus Torvalds struct rtmsg *rtm = NLMSG_DATA(nlh); 111*7b204afdSRobert Olsson struct fib_rule *r; 112*7b204afdSRobert Olsson struct hlist_node *node; 1131da177e4SLinus Torvalds int err = -ESRCH; 1141da177e4SLinus Torvalds 115*7b204afdSRobert Olsson hlist_for_each_entry(r, node, &fib_rules, hlist) { 1161da177e4SLinus Torvalds if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) && 1171da177e4SLinus Torvalds rtm->rtm_src_len == r->r_src_len && 1181da177e4SLinus Torvalds rtm->rtm_dst_len == r->r_dst_len && 1191da177e4SLinus Torvalds (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) && 1201da177e4SLinus Torvalds rtm->rtm_tos == r->r_tos && 1211da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 1221da177e4SLinus Torvalds (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) && 1231da177e4SLinus Torvalds #endif 1241da177e4SLinus Torvalds (!rtm->rtm_type || rtm->rtm_type == r->r_action) && 1251da177e4SLinus Torvalds (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) && 1261da177e4SLinus Torvalds (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) && 1271da177e4SLinus Torvalds (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) { 1281da177e4SLinus Torvalds err = -EPERM; 1291da177e4SLinus Torvalds if (r == &local_rule) 1301da177e4SLinus Torvalds break; 1311da177e4SLinus Torvalds 132*7b204afdSRobert Olsson hlist_del_rcu(&r->hlist); 1331da177e4SLinus Torvalds r->r_dead = 1; 1341da177e4SLinus Torvalds fib_rule_put(r); 1351da177e4SLinus Torvalds err = 0; 1361da177e4SLinus Torvalds break; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds return err; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /* Allocate new unique table id */ 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static struct fib_table *fib_empty_table(void) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds int id; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds for (id = 1; id <= RT_TABLE_MAX; id++) 1491da177e4SLinus Torvalds if (fib_tables[id] == NULL) 1501da177e4SLinus Torvalds return __fib_new_table(id); 1511da177e4SLinus Torvalds return NULL; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 154*7b204afdSRobert Olsson static inline void fib_rule_put_rcu(struct rcu_head *head) 155*7b204afdSRobert Olsson { 156*7b204afdSRobert Olsson struct fib_rule *r = container_of(head, struct fib_rule, rcu); 157*7b204afdSRobert Olsson kfree(r); 158*7b204afdSRobert Olsson } 159*7b204afdSRobert Olsson 1601da177e4SLinus Torvalds void fib_rule_put(struct fib_rule *r) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds if (atomic_dec_and_test(&r->r_clntref)) { 1631da177e4SLinus Torvalds if (r->r_dead) 164*7b204afdSRobert Olsson call_rcu(&r->rcu, fib_rule_put_rcu); 1651da177e4SLinus Torvalds else 1661da177e4SLinus Torvalds printk("Freeing alive rule %p\n", r); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 170*7b204afdSRobert Olsson /* writer func called from netlink -- rtnl_sem hold*/ 171*7b204afdSRobert Olsson 1721da177e4SLinus Torvalds int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds struct rtattr **rta = arg; 1751da177e4SLinus Torvalds struct rtmsg *rtm = NLMSG_DATA(nlh); 176*7b204afdSRobert Olsson struct fib_rule *r, *new_r, *last = NULL; 177*7b204afdSRobert Olsson struct hlist_node *node = NULL; 1781da177e4SLinus Torvalds unsigned char table_id; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 || 1811da177e4SLinus Torvalds (rtm->rtm_tos & ~IPTOS_TOS_MASK)) 1821da177e4SLinus Torvalds return -EINVAL; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ) 1851da177e4SLinus Torvalds return -EINVAL; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds table_id = rtm->rtm_table; 1881da177e4SLinus Torvalds if (table_id == RT_TABLE_UNSPEC) { 1891da177e4SLinus Torvalds struct fib_table *table; 1901da177e4SLinus Torvalds if (rtm->rtm_type == RTN_UNICAST) { 1911da177e4SLinus Torvalds if ((table = fib_empty_table()) == NULL) 1921da177e4SLinus Torvalds return -ENOBUFS; 1931da177e4SLinus Torvalds table_id = table->tb_id; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds new_r = kmalloc(sizeof(*new_r), GFP_KERNEL); 1981da177e4SLinus Torvalds if (!new_r) 1991da177e4SLinus Torvalds return -ENOMEM; 2001da177e4SLinus Torvalds memset(new_r, 0, sizeof(*new_r)); 201*7b204afdSRobert Olsson 2021da177e4SLinus Torvalds if (rta[RTA_SRC-1]) 2031da177e4SLinus Torvalds memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4); 2041da177e4SLinus Torvalds if (rta[RTA_DST-1]) 2051da177e4SLinus Torvalds memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4); 2061da177e4SLinus Torvalds if (rta[RTA_GATEWAY-1]) 2071da177e4SLinus Torvalds memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4); 2081da177e4SLinus Torvalds new_r->r_src_len = rtm->rtm_src_len; 2091da177e4SLinus Torvalds new_r->r_dst_len = rtm->rtm_dst_len; 2101da177e4SLinus Torvalds new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len); 2111da177e4SLinus Torvalds new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len); 2121da177e4SLinus Torvalds new_r->r_tos = rtm->rtm_tos; 2131da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 2141da177e4SLinus Torvalds if (rta[RTA_PROTOINFO-1]) 2151da177e4SLinus Torvalds memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4); 2161da177e4SLinus Torvalds #endif 2171da177e4SLinus Torvalds new_r->r_action = rtm->rtm_type; 2181da177e4SLinus Torvalds new_r->r_flags = rtm->rtm_flags; 2191da177e4SLinus Torvalds if (rta[RTA_PRIORITY-1]) 2201da177e4SLinus Torvalds memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4); 2211da177e4SLinus Torvalds new_r->r_table = table_id; 2221da177e4SLinus Torvalds if (rta[RTA_IIF-1]) { 2231da177e4SLinus Torvalds struct net_device *dev; 2241da177e4SLinus Torvalds rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ); 2251da177e4SLinus Torvalds new_r->r_ifindex = -1; 2261da177e4SLinus Torvalds dev = __dev_get_by_name(new_r->r_ifname); 2271da177e4SLinus Torvalds if (dev) 2281da177e4SLinus Torvalds new_r->r_ifindex = dev->ifindex; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 2311da177e4SLinus Torvalds if (rta[RTA_FLOW-1]) 2321da177e4SLinus Torvalds memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4); 2331da177e4SLinus Torvalds #endif 234*7b204afdSRobert Olsson r = container_of(fib_rules.first, struct fib_rule, hlist); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds if (!new_r->r_preference) { 237*7b204afdSRobert Olsson if (r && r->hlist.next != NULL) { 238*7b204afdSRobert Olsson r = container_of(r->hlist.next, struct fib_rule, hlist); 2391da177e4SLinus Torvalds if (r->r_preference) 2401da177e4SLinus Torvalds new_r->r_preference = r->r_preference - 1; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 244*7b204afdSRobert Olsson hlist_for_each_entry(r, node, &fib_rules, hlist) { 2451da177e4SLinus Torvalds if (r->r_preference > new_r->r_preference) 2461da177e4SLinus Torvalds break; 247*7b204afdSRobert Olsson last = r; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds atomic_inc(&new_r->r_clntref); 250*7b204afdSRobert Olsson 251*7b204afdSRobert Olsson if (last) 252*7b204afdSRobert Olsson hlist_add_after_rcu(&last->hlist, &new_r->hlist); 253*7b204afdSRobert Olsson else 254*7b204afdSRobert Olsson hlist_add_before_rcu(&new_r->hlist, &r->hlist); 255*7b204afdSRobert Olsson 2561da177e4SLinus Torvalds return 0; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 2601da177e4SLinus Torvalds u32 fib_rules_tclass(struct fib_result *res) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds if (res->r) 2631da177e4SLinus Torvalds return res->r->r_tclassid; 2641da177e4SLinus Torvalds return 0; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds #endif 2671da177e4SLinus Torvalds 268*7b204afdSRobert Olsson /* callers should hold rtnl semaphore */ 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds static void fib_rules_detach(struct net_device *dev) 2711da177e4SLinus Torvalds { 272*7b204afdSRobert Olsson struct hlist_node *node; 2731da177e4SLinus Torvalds struct fib_rule *r; 2741da177e4SLinus Torvalds 275*7b204afdSRobert Olsson hlist_for_each_entry(r, node, &fib_rules, hlist) { 276*7b204afdSRobert Olsson if (r->r_ifindex == dev->ifindex) 2771da177e4SLinus Torvalds r->r_ifindex = -1; 278*7b204afdSRobert Olsson 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds } 281*7b204afdSRobert Olsson 282*7b204afdSRobert Olsson /* callers should hold rtnl semaphore */ 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds static void fib_rules_attach(struct net_device *dev) 2851da177e4SLinus Torvalds { 286*7b204afdSRobert Olsson struct hlist_node *node; 2871da177e4SLinus Torvalds struct fib_rule *r; 2881da177e4SLinus Torvalds 289*7b204afdSRobert Olsson hlist_for_each_entry(r, node, &fib_rules, hlist) { 290*7b204afdSRobert Olsson if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) 2911da177e4SLinus Torvalds r->r_ifindex = dev->ifindex; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds int fib_lookup(const struct flowi *flp, struct fib_result *res) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds int err; 2981da177e4SLinus Torvalds struct fib_rule *r, *policy; 2991da177e4SLinus Torvalds struct fib_table *tb; 300*7b204afdSRobert Olsson struct hlist_node *node; 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds u32 daddr = flp->fl4_dst; 3031da177e4SLinus Torvalds u32 saddr = flp->fl4_src; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", 3061da177e4SLinus Torvalds NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src)); 307*7b204afdSRobert Olsson 308*7b204afdSRobert Olsson rcu_read_lock(); 309*7b204afdSRobert Olsson 310*7b204afdSRobert Olsson hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) { 3111da177e4SLinus Torvalds if (((saddr^r->r_src) & r->r_srcmask) || 3121da177e4SLinus Torvalds ((daddr^r->r_dst) & r->r_dstmask) || 3131da177e4SLinus Torvalds (r->r_tos && r->r_tos != flp->fl4_tos) || 3141da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 3151da177e4SLinus Torvalds (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) || 3161da177e4SLinus Torvalds #endif 3171da177e4SLinus Torvalds (r->r_ifindex && r->r_ifindex != flp->iif)) 3181da177e4SLinus Torvalds continue; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds FRprintk("tb %d r %d ", r->r_table, r->r_action); 3211da177e4SLinus Torvalds switch (r->r_action) { 3221da177e4SLinus Torvalds case RTN_UNICAST: 3231da177e4SLinus Torvalds policy = r; 3241da177e4SLinus Torvalds break; 3251da177e4SLinus Torvalds case RTN_UNREACHABLE: 326*7b204afdSRobert Olsson rcu_read_unlock(); 3271da177e4SLinus Torvalds return -ENETUNREACH; 3281da177e4SLinus Torvalds default: 3291da177e4SLinus Torvalds case RTN_BLACKHOLE: 330*7b204afdSRobert Olsson rcu_read_unlock(); 3311da177e4SLinus Torvalds return -EINVAL; 3321da177e4SLinus Torvalds case RTN_PROHIBIT: 333*7b204afdSRobert Olsson rcu_read_unlock(); 3341da177e4SLinus Torvalds return -EACCES; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds if ((tb = fib_get_table(r->r_table)) == NULL) 3381da177e4SLinus Torvalds continue; 3391da177e4SLinus Torvalds err = tb->tb_lookup(tb, flp, res); 3401da177e4SLinus Torvalds if (err == 0) { 3411da177e4SLinus Torvalds res->r = policy; 3421da177e4SLinus Torvalds if (policy) 3431da177e4SLinus Torvalds atomic_inc(&policy->r_clntref); 344*7b204afdSRobert Olsson rcu_read_unlock(); 3451da177e4SLinus Torvalds return 0; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds if (err < 0 && err != -EAGAIN) { 348*7b204afdSRobert Olsson rcu_read_unlock(); 3491da177e4SLinus Torvalds return err; 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds FRprintk("FAILURE\n"); 353*7b204afdSRobert Olsson rcu_read_unlock(); 3541da177e4SLinus Torvalds return -ENETUNREACH; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds void fib_select_default(const struct flowi *flp, struct fib_result *res) 3581da177e4SLinus Torvalds { 3591da177e4SLinus Torvalds if (res->r && res->r->r_action == RTN_UNICAST && 3601da177e4SLinus Torvalds FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { 3611da177e4SLinus Torvalds struct fib_table *tb; 3621da177e4SLinus Torvalds if ((tb = fib_get_table(res->r->r_table)) != NULL) 3631da177e4SLinus Torvalds tb->tb_select_default(tb, flp, res); 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) 3681da177e4SLinus Torvalds { 3691da177e4SLinus Torvalds struct net_device *dev = ptr; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds if (event == NETDEV_UNREGISTER) 3721da177e4SLinus Torvalds fib_rules_detach(dev); 3731da177e4SLinus Torvalds else if (event == NETDEV_REGISTER) 3741da177e4SLinus Torvalds fib_rules_attach(dev); 3751da177e4SLinus Torvalds return NOTIFY_DONE; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds static struct notifier_block fib_rules_notifier = { 3801da177e4SLinus Torvalds .notifier_call =fib_rules_event, 3811da177e4SLinus Torvalds }; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds static __inline__ int inet_fill_rule(struct sk_buff *skb, 3841da177e4SLinus Torvalds struct fib_rule *r, 385b6544c0bSJamal Hadi Salim struct netlink_callback *cb, 386b6544c0bSJamal Hadi Salim unsigned int flags) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds struct rtmsg *rtm; 3891da177e4SLinus Torvalds struct nlmsghdr *nlh; 3901da177e4SLinus Torvalds unsigned char *b = skb->tail; 3911da177e4SLinus Torvalds 392b6544c0bSJamal Hadi Salim nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags); 3931da177e4SLinus Torvalds rtm = NLMSG_DATA(nlh); 3941da177e4SLinus Torvalds rtm->rtm_family = AF_INET; 3951da177e4SLinus Torvalds rtm->rtm_dst_len = r->r_dst_len; 3961da177e4SLinus Torvalds rtm->rtm_src_len = r->r_src_len; 3971da177e4SLinus Torvalds rtm->rtm_tos = r->r_tos; 3981da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 3991da177e4SLinus Torvalds if (r->r_fwmark) 4001da177e4SLinus Torvalds RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark); 4011da177e4SLinus Torvalds #endif 4021da177e4SLinus Torvalds rtm->rtm_table = r->r_table; 4031da177e4SLinus Torvalds rtm->rtm_protocol = 0; 4041da177e4SLinus Torvalds rtm->rtm_scope = 0; 4051da177e4SLinus Torvalds rtm->rtm_type = r->r_action; 4061da177e4SLinus Torvalds rtm->rtm_flags = r->r_flags; 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds if (r->r_dst_len) 4091da177e4SLinus Torvalds RTA_PUT(skb, RTA_DST, 4, &r->r_dst); 4101da177e4SLinus Torvalds if (r->r_src_len) 4111da177e4SLinus Torvalds RTA_PUT(skb, RTA_SRC, 4, &r->r_src); 4121da177e4SLinus Torvalds if (r->r_ifname[0]) 4131da177e4SLinus Torvalds RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname); 4141da177e4SLinus Torvalds if (r->r_preference) 4151da177e4SLinus Torvalds RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference); 4161da177e4SLinus Torvalds if (r->r_srcmap) 4171da177e4SLinus Torvalds RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap); 4181da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 4191da177e4SLinus Torvalds if (r->r_tclassid) 4201da177e4SLinus Torvalds RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid); 4211da177e4SLinus Torvalds #endif 4221da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 4231da177e4SLinus Torvalds return skb->len; 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds nlmsg_failure: 4261da177e4SLinus Torvalds rtattr_failure: 4271da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 4281da177e4SLinus Torvalds return -1; 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 431*7b204afdSRobert Olsson /* callers should hold rtnl semaphore */ 432*7b204afdSRobert Olsson 4331da177e4SLinus Torvalds int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) 4341da177e4SLinus Torvalds { 435*7b204afdSRobert Olsson int idx = 0; 4361da177e4SLinus Torvalds int s_idx = cb->args[0]; 4371da177e4SLinus Torvalds struct fib_rule *r; 438*7b204afdSRobert Olsson struct hlist_node *node; 4391da177e4SLinus Torvalds 440*7b204afdSRobert Olsson rcu_read_lock(); 441*7b204afdSRobert Olsson hlist_for_each_entry(r, node, &fib_rules, hlist) { 442*7b204afdSRobert Olsson 4431da177e4SLinus Torvalds if (idx < s_idx) 4441da177e4SLinus Torvalds continue; 445b6544c0bSJamal Hadi Salim if (inet_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) 4461da177e4SLinus Torvalds break; 447*7b204afdSRobert Olsson idx++; 4481da177e4SLinus Torvalds } 449*7b204afdSRobert Olsson rcu_read_unlock(); 4501da177e4SLinus Torvalds cb->args[0] = idx; 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds return skb->len; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds void __init fib_rules_init(void) 4561da177e4SLinus Torvalds { 457*7b204afdSRobert Olsson INIT_HLIST_HEAD(&fib_rules); 458*7b204afdSRobert Olsson hlist_add_head(&local_rule.hlist, &fib_rules); 459*7b204afdSRobert Olsson hlist_add_after(&local_rule.hlist, &main_rule.hlist); 460*7b204afdSRobert Olsson hlist_add_after(&main_rule.hlist, &default_rule.hlist); 4611da177e4SLinus Torvalds register_netdevice_notifier(&fib_rules_notifier); 4621da177e4SLinus Torvalds } 463