1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * INET An implementation of the TCP/IP protocol suite for the LINUX 3*1da177e4SLinus Torvalds * operating system. INET is implemented using the BSD Socket 4*1da177e4SLinus Torvalds * interface as the means of communication with the user level. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * IPv4 Forwarding Information Base: policy rules. 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * Version: $Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $ 9*1da177e4SLinus Torvalds * 10*1da177e4SLinus Torvalds * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 13*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 14*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 15*1da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 16*1da177e4SLinus Torvalds * 17*1da177e4SLinus Torvalds * Fixes: 18*1da177e4SLinus Torvalds * Rani Assaf : local_rule cannot be deleted 19*1da177e4SLinus Torvalds * Marc Boucher : routing by fwmark 20*1da177e4SLinus Torvalds */ 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds #include <linux/config.h> 23*1da177e4SLinus Torvalds #include <asm/uaccess.h> 24*1da177e4SLinus Torvalds #include <asm/system.h> 25*1da177e4SLinus Torvalds #include <linux/bitops.h> 26*1da177e4SLinus Torvalds #include <linux/types.h> 27*1da177e4SLinus Torvalds #include <linux/kernel.h> 28*1da177e4SLinus Torvalds #include <linux/sched.h> 29*1da177e4SLinus Torvalds #include <linux/mm.h> 30*1da177e4SLinus Torvalds #include <linux/string.h> 31*1da177e4SLinus Torvalds #include <linux/socket.h> 32*1da177e4SLinus Torvalds #include <linux/sockios.h> 33*1da177e4SLinus Torvalds #include <linux/errno.h> 34*1da177e4SLinus Torvalds #include <linux/in.h> 35*1da177e4SLinus Torvalds #include <linux/inet.h> 36*1da177e4SLinus Torvalds #include <linux/netdevice.h> 37*1da177e4SLinus Torvalds #include <linux/if_arp.h> 38*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 39*1da177e4SLinus Torvalds #include <linux/skbuff.h> 40*1da177e4SLinus Torvalds #include <linux/netlink.h> 41*1da177e4SLinus Torvalds #include <linux/init.h> 42*1da177e4SLinus Torvalds 43*1da177e4SLinus Torvalds #include <net/ip.h> 44*1da177e4SLinus Torvalds #include <net/protocol.h> 45*1da177e4SLinus Torvalds #include <net/route.h> 46*1da177e4SLinus Torvalds #include <net/tcp.h> 47*1da177e4SLinus Torvalds #include <net/sock.h> 48*1da177e4SLinus Torvalds #include <net/ip_fib.h> 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds #define FRprintk(a...) 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds struct fib_rule 53*1da177e4SLinus Torvalds { 54*1da177e4SLinus Torvalds struct fib_rule *r_next; 55*1da177e4SLinus Torvalds atomic_t r_clntref; 56*1da177e4SLinus Torvalds u32 r_preference; 57*1da177e4SLinus Torvalds unsigned char r_table; 58*1da177e4SLinus Torvalds unsigned char r_action; 59*1da177e4SLinus Torvalds unsigned char r_dst_len; 60*1da177e4SLinus Torvalds unsigned char r_src_len; 61*1da177e4SLinus Torvalds u32 r_src; 62*1da177e4SLinus Torvalds u32 r_srcmask; 63*1da177e4SLinus Torvalds u32 r_dst; 64*1da177e4SLinus Torvalds u32 r_dstmask; 65*1da177e4SLinus Torvalds u32 r_srcmap; 66*1da177e4SLinus Torvalds u8 r_flags; 67*1da177e4SLinus Torvalds u8 r_tos; 68*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 69*1da177e4SLinus Torvalds u32 r_fwmark; 70*1da177e4SLinus Torvalds #endif 71*1da177e4SLinus Torvalds int r_ifindex; 72*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 73*1da177e4SLinus Torvalds __u32 r_tclassid; 74*1da177e4SLinus Torvalds #endif 75*1da177e4SLinus Torvalds char r_ifname[IFNAMSIZ]; 76*1da177e4SLinus Torvalds int r_dead; 77*1da177e4SLinus Torvalds }; 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds static struct fib_rule default_rule = { 80*1da177e4SLinus Torvalds .r_clntref = ATOMIC_INIT(2), 81*1da177e4SLinus Torvalds .r_preference = 0x7FFF, 82*1da177e4SLinus Torvalds .r_table = RT_TABLE_DEFAULT, 83*1da177e4SLinus Torvalds .r_action = RTN_UNICAST, 84*1da177e4SLinus Torvalds }; 85*1da177e4SLinus Torvalds 86*1da177e4SLinus Torvalds static struct fib_rule main_rule = { 87*1da177e4SLinus Torvalds .r_next = &default_rule, 88*1da177e4SLinus Torvalds .r_clntref = ATOMIC_INIT(2), 89*1da177e4SLinus Torvalds .r_preference = 0x7FFE, 90*1da177e4SLinus Torvalds .r_table = RT_TABLE_MAIN, 91*1da177e4SLinus Torvalds .r_action = RTN_UNICAST, 92*1da177e4SLinus Torvalds }; 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds static struct fib_rule local_rule = { 95*1da177e4SLinus Torvalds .r_next = &main_rule, 96*1da177e4SLinus Torvalds .r_clntref = ATOMIC_INIT(2), 97*1da177e4SLinus Torvalds .r_table = RT_TABLE_LOCAL, 98*1da177e4SLinus Torvalds .r_action = RTN_UNICAST, 99*1da177e4SLinus Torvalds }; 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds static struct fib_rule *fib_rules = &local_rule; 102*1da177e4SLinus Torvalds static DEFINE_RWLOCK(fib_rules_lock); 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 105*1da177e4SLinus Torvalds { 106*1da177e4SLinus Torvalds struct rtattr **rta = arg; 107*1da177e4SLinus Torvalds struct rtmsg *rtm = NLMSG_DATA(nlh); 108*1da177e4SLinus Torvalds struct fib_rule *r, **rp; 109*1da177e4SLinus Torvalds int err = -ESRCH; 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) { 112*1da177e4SLinus Torvalds if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) && 113*1da177e4SLinus Torvalds rtm->rtm_src_len == r->r_src_len && 114*1da177e4SLinus Torvalds rtm->rtm_dst_len == r->r_dst_len && 115*1da177e4SLinus Torvalds (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) && 116*1da177e4SLinus Torvalds rtm->rtm_tos == r->r_tos && 117*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 118*1da177e4SLinus Torvalds (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) && 119*1da177e4SLinus Torvalds #endif 120*1da177e4SLinus Torvalds (!rtm->rtm_type || rtm->rtm_type == r->r_action) && 121*1da177e4SLinus Torvalds (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) && 122*1da177e4SLinus Torvalds (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) && 123*1da177e4SLinus Torvalds (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) { 124*1da177e4SLinus Torvalds err = -EPERM; 125*1da177e4SLinus Torvalds if (r == &local_rule) 126*1da177e4SLinus Torvalds break; 127*1da177e4SLinus Torvalds 128*1da177e4SLinus Torvalds write_lock_bh(&fib_rules_lock); 129*1da177e4SLinus Torvalds *rp = r->r_next; 130*1da177e4SLinus Torvalds r->r_dead = 1; 131*1da177e4SLinus Torvalds write_unlock_bh(&fib_rules_lock); 132*1da177e4SLinus Torvalds fib_rule_put(r); 133*1da177e4SLinus Torvalds err = 0; 134*1da177e4SLinus Torvalds break; 135*1da177e4SLinus Torvalds } 136*1da177e4SLinus Torvalds } 137*1da177e4SLinus Torvalds return err; 138*1da177e4SLinus Torvalds } 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds /* Allocate new unique table id */ 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds static struct fib_table *fib_empty_table(void) 143*1da177e4SLinus Torvalds { 144*1da177e4SLinus Torvalds int id; 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds for (id = 1; id <= RT_TABLE_MAX; id++) 147*1da177e4SLinus Torvalds if (fib_tables[id] == NULL) 148*1da177e4SLinus Torvalds return __fib_new_table(id); 149*1da177e4SLinus Torvalds return NULL; 150*1da177e4SLinus Torvalds } 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds void fib_rule_put(struct fib_rule *r) 153*1da177e4SLinus Torvalds { 154*1da177e4SLinus Torvalds if (atomic_dec_and_test(&r->r_clntref)) { 155*1da177e4SLinus Torvalds if (r->r_dead) 156*1da177e4SLinus Torvalds kfree(r); 157*1da177e4SLinus Torvalds else 158*1da177e4SLinus Torvalds printk("Freeing alive rule %p\n", r); 159*1da177e4SLinus Torvalds } 160*1da177e4SLinus Torvalds } 161*1da177e4SLinus Torvalds 162*1da177e4SLinus Torvalds int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 163*1da177e4SLinus Torvalds { 164*1da177e4SLinus Torvalds struct rtattr **rta = arg; 165*1da177e4SLinus Torvalds struct rtmsg *rtm = NLMSG_DATA(nlh); 166*1da177e4SLinus Torvalds struct fib_rule *r, *new_r, **rp; 167*1da177e4SLinus Torvalds unsigned char table_id; 168*1da177e4SLinus Torvalds 169*1da177e4SLinus Torvalds if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 || 170*1da177e4SLinus Torvalds (rtm->rtm_tos & ~IPTOS_TOS_MASK)) 171*1da177e4SLinus Torvalds return -EINVAL; 172*1da177e4SLinus Torvalds 173*1da177e4SLinus Torvalds if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ) 174*1da177e4SLinus Torvalds return -EINVAL; 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds table_id = rtm->rtm_table; 177*1da177e4SLinus Torvalds if (table_id == RT_TABLE_UNSPEC) { 178*1da177e4SLinus Torvalds struct fib_table *table; 179*1da177e4SLinus Torvalds if (rtm->rtm_type == RTN_UNICAST) { 180*1da177e4SLinus Torvalds if ((table = fib_empty_table()) == NULL) 181*1da177e4SLinus Torvalds return -ENOBUFS; 182*1da177e4SLinus Torvalds table_id = table->tb_id; 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds } 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds new_r = kmalloc(sizeof(*new_r), GFP_KERNEL); 187*1da177e4SLinus Torvalds if (!new_r) 188*1da177e4SLinus Torvalds return -ENOMEM; 189*1da177e4SLinus Torvalds memset(new_r, 0, sizeof(*new_r)); 190*1da177e4SLinus Torvalds if (rta[RTA_SRC-1]) 191*1da177e4SLinus Torvalds memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4); 192*1da177e4SLinus Torvalds if (rta[RTA_DST-1]) 193*1da177e4SLinus Torvalds memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4); 194*1da177e4SLinus Torvalds if (rta[RTA_GATEWAY-1]) 195*1da177e4SLinus Torvalds memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4); 196*1da177e4SLinus Torvalds new_r->r_src_len = rtm->rtm_src_len; 197*1da177e4SLinus Torvalds new_r->r_dst_len = rtm->rtm_dst_len; 198*1da177e4SLinus Torvalds new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len); 199*1da177e4SLinus Torvalds new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len); 200*1da177e4SLinus Torvalds new_r->r_tos = rtm->rtm_tos; 201*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 202*1da177e4SLinus Torvalds if (rta[RTA_PROTOINFO-1]) 203*1da177e4SLinus Torvalds memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4); 204*1da177e4SLinus Torvalds #endif 205*1da177e4SLinus Torvalds new_r->r_action = rtm->rtm_type; 206*1da177e4SLinus Torvalds new_r->r_flags = rtm->rtm_flags; 207*1da177e4SLinus Torvalds if (rta[RTA_PRIORITY-1]) 208*1da177e4SLinus Torvalds memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4); 209*1da177e4SLinus Torvalds new_r->r_table = table_id; 210*1da177e4SLinus Torvalds if (rta[RTA_IIF-1]) { 211*1da177e4SLinus Torvalds struct net_device *dev; 212*1da177e4SLinus Torvalds rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ); 213*1da177e4SLinus Torvalds new_r->r_ifindex = -1; 214*1da177e4SLinus Torvalds dev = __dev_get_by_name(new_r->r_ifname); 215*1da177e4SLinus Torvalds if (dev) 216*1da177e4SLinus Torvalds new_r->r_ifindex = dev->ifindex; 217*1da177e4SLinus Torvalds } 218*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 219*1da177e4SLinus Torvalds if (rta[RTA_FLOW-1]) 220*1da177e4SLinus Torvalds memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4); 221*1da177e4SLinus Torvalds #endif 222*1da177e4SLinus Torvalds 223*1da177e4SLinus Torvalds rp = &fib_rules; 224*1da177e4SLinus Torvalds if (!new_r->r_preference) { 225*1da177e4SLinus Torvalds r = fib_rules; 226*1da177e4SLinus Torvalds if (r && (r = r->r_next) != NULL) { 227*1da177e4SLinus Torvalds rp = &fib_rules->r_next; 228*1da177e4SLinus Torvalds if (r->r_preference) 229*1da177e4SLinus Torvalds new_r->r_preference = r->r_preference - 1; 230*1da177e4SLinus Torvalds } 231*1da177e4SLinus Torvalds } 232*1da177e4SLinus Torvalds 233*1da177e4SLinus Torvalds while ( (r = *rp) != NULL ) { 234*1da177e4SLinus Torvalds if (r->r_preference > new_r->r_preference) 235*1da177e4SLinus Torvalds break; 236*1da177e4SLinus Torvalds rp = &r->r_next; 237*1da177e4SLinus Torvalds } 238*1da177e4SLinus Torvalds 239*1da177e4SLinus Torvalds new_r->r_next = r; 240*1da177e4SLinus Torvalds atomic_inc(&new_r->r_clntref); 241*1da177e4SLinus Torvalds write_lock_bh(&fib_rules_lock); 242*1da177e4SLinus Torvalds *rp = new_r; 243*1da177e4SLinus Torvalds write_unlock_bh(&fib_rules_lock); 244*1da177e4SLinus Torvalds return 0; 245*1da177e4SLinus Torvalds } 246*1da177e4SLinus Torvalds 247*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 248*1da177e4SLinus Torvalds u32 fib_rules_tclass(struct fib_result *res) 249*1da177e4SLinus Torvalds { 250*1da177e4SLinus Torvalds if (res->r) 251*1da177e4SLinus Torvalds return res->r->r_tclassid; 252*1da177e4SLinus Torvalds return 0; 253*1da177e4SLinus Torvalds } 254*1da177e4SLinus Torvalds #endif 255*1da177e4SLinus Torvalds 256*1da177e4SLinus Torvalds 257*1da177e4SLinus Torvalds static void fib_rules_detach(struct net_device *dev) 258*1da177e4SLinus Torvalds { 259*1da177e4SLinus Torvalds struct fib_rule *r; 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds for (r=fib_rules; r; r=r->r_next) { 262*1da177e4SLinus Torvalds if (r->r_ifindex == dev->ifindex) { 263*1da177e4SLinus Torvalds write_lock_bh(&fib_rules_lock); 264*1da177e4SLinus Torvalds r->r_ifindex = -1; 265*1da177e4SLinus Torvalds write_unlock_bh(&fib_rules_lock); 266*1da177e4SLinus Torvalds } 267*1da177e4SLinus Torvalds } 268*1da177e4SLinus Torvalds } 269*1da177e4SLinus Torvalds 270*1da177e4SLinus Torvalds static void fib_rules_attach(struct net_device *dev) 271*1da177e4SLinus Torvalds { 272*1da177e4SLinus Torvalds struct fib_rule *r; 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds for (r=fib_rules; r; r=r->r_next) { 275*1da177e4SLinus Torvalds if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) { 276*1da177e4SLinus Torvalds write_lock_bh(&fib_rules_lock); 277*1da177e4SLinus Torvalds r->r_ifindex = dev->ifindex; 278*1da177e4SLinus Torvalds write_unlock_bh(&fib_rules_lock); 279*1da177e4SLinus Torvalds } 280*1da177e4SLinus Torvalds } 281*1da177e4SLinus Torvalds } 282*1da177e4SLinus Torvalds 283*1da177e4SLinus Torvalds int fib_lookup(const struct flowi *flp, struct fib_result *res) 284*1da177e4SLinus Torvalds { 285*1da177e4SLinus Torvalds int err; 286*1da177e4SLinus Torvalds struct fib_rule *r, *policy; 287*1da177e4SLinus Torvalds struct fib_table *tb; 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds u32 daddr = flp->fl4_dst; 290*1da177e4SLinus Torvalds u32 saddr = flp->fl4_src; 291*1da177e4SLinus Torvalds 292*1da177e4SLinus Torvalds FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", 293*1da177e4SLinus Torvalds NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src)); 294*1da177e4SLinus Torvalds read_lock(&fib_rules_lock); 295*1da177e4SLinus Torvalds for (r = fib_rules; r; r=r->r_next) { 296*1da177e4SLinus Torvalds if (((saddr^r->r_src) & r->r_srcmask) || 297*1da177e4SLinus Torvalds ((daddr^r->r_dst) & r->r_dstmask) || 298*1da177e4SLinus Torvalds (r->r_tos && r->r_tos != flp->fl4_tos) || 299*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 300*1da177e4SLinus Torvalds (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) || 301*1da177e4SLinus Torvalds #endif 302*1da177e4SLinus Torvalds (r->r_ifindex && r->r_ifindex != flp->iif)) 303*1da177e4SLinus Torvalds continue; 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds FRprintk("tb %d r %d ", r->r_table, r->r_action); 306*1da177e4SLinus Torvalds switch (r->r_action) { 307*1da177e4SLinus Torvalds case RTN_UNICAST: 308*1da177e4SLinus Torvalds policy = r; 309*1da177e4SLinus Torvalds break; 310*1da177e4SLinus Torvalds case RTN_UNREACHABLE: 311*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 312*1da177e4SLinus Torvalds return -ENETUNREACH; 313*1da177e4SLinus Torvalds default: 314*1da177e4SLinus Torvalds case RTN_BLACKHOLE: 315*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 316*1da177e4SLinus Torvalds return -EINVAL; 317*1da177e4SLinus Torvalds case RTN_PROHIBIT: 318*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 319*1da177e4SLinus Torvalds return -EACCES; 320*1da177e4SLinus Torvalds } 321*1da177e4SLinus Torvalds 322*1da177e4SLinus Torvalds if ((tb = fib_get_table(r->r_table)) == NULL) 323*1da177e4SLinus Torvalds continue; 324*1da177e4SLinus Torvalds err = tb->tb_lookup(tb, flp, res); 325*1da177e4SLinus Torvalds if (err == 0) { 326*1da177e4SLinus Torvalds res->r = policy; 327*1da177e4SLinus Torvalds if (policy) 328*1da177e4SLinus Torvalds atomic_inc(&policy->r_clntref); 329*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 330*1da177e4SLinus Torvalds return 0; 331*1da177e4SLinus Torvalds } 332*1da177e4SLinus Torvalds if (err < 0 && err != -EAGAIN) { 333*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 334*1da177e4SLinus Torvalds return err; 335*1da177e4SLinus Torvalds } 336*1da177e4SLinus Torvalds } 337*1da177e4SLinus Torvalds FRprintk("FAILURE\n"); 338*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 339*1da177e4SLinus Torvalds return -ENETUNREACH; 340*1da177e4SLinus Torvalds } 341*1da177e4SLinus Torvalds 342*1da177e4SLinus Torvalds void fib_select_default(const struct flowi *flp, struct fib_result *res) 343*1da177e4SLinus Torvalds { 344*1da177e4SLinus Torvalds if (res->r && res->r->r_action == RTN_UNICAST && 345*1da177e4SLinus Torvalds FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { 346*1da177e4SLinus Torvalds struct fib_table *tb; 347*1da177e4SLinus Torvalds if ((tb = fib_get_table(res->r->r_table)) != NULL) 348*1da177e4SLinus Torvalds tb->tb_select_default(tb, flp, res); 349*1da177e4SLinus Torvalds } 350*1da177e4SLinus Torvalds } 351*1da177e4SLinus Torvalds 352*1da177e4SLinus Torvalds static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) 353*1da177e4SLinus Torvalds { 354*1da177e4SLinus Torvalds struct net_device *dev = ptr; 355*1da177e4SLinus Torvalds 356*1da177e4SLinus Torvalds if (event == NETDEV_UNREGISTER) 357*1da177e4SLinus Torvalds fib_rules_detach(dev); 358*1da177e4SLinus Torvalds else if (event == NETDEV_REGISTER) 359*1da177e4SLinus Torvalds fib_rules_attach(dev); 360*1da177e4SLinus Torvalds return NOTIFY_DONE; 361*1da177e4SLinus Torvalds } 362*1da177e4SLinus Torvalds 363*1da177e4SLinus Torvalds 364*1da177e4SLinus Torvalds static struct notifier_block fib_rules_notifier = { 365*1da177e4SLinus Torvalds .notifier_call =fib_rules_event, 366*1da177e4SLinus Torvalds }; 367*1da177e4SLinus Torvalds 368*1da177e4SLinus Torvalds static __inline__ int inet_fill_rule(struct sk_buff *skb, 369*1da177e4SLinus Torvalds struct fib_rule *r, 370*1da177e4SLinus Torvalds struct netlink_callback *cb) 371*1da177e4SLinus Torvalds { 372*1da177e4SLinus Torvalds struct rtmsg *rtm; 373*1da177e4SLinus Torvalds struct nlmsghdr *nlh; 374*1da177e4SLinus Torvalds unsigned char *b = skb->tail; 375*1da177e4SLinus Torvalds 376*1da177e4SLinus Torvalds nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm)); 377*1da177e4SLinus Torvalds rtm = NLMSG_DATA(nlh); 378*1da177e4SLinus Torvalds rtm->rtm_family = AF_INET; 379*1da177e4SLinus Torvalds rtm->rtm_dst_len = r->r_dst_len; 380*1da177e4SLinus Torvalds rtm->rtm_src_len = r->r_src_len; 381*1da177e4SLinus Torvalds rtm->rtm_tos = r->r_tos; 382*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK 383*1da177e4SLinus Torvalds if (r->r_fwmark) 384*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark); 385*1da177e4SLinus Torvalds #endif 386*1da177e4SLinus Torvalds rtm->rtm_table = r->r_table; 387*1da177e4SLinus Torvalds rtm->rtm_protocol = 0; 388*1da177e4SLinus Torvalds rtm->rtm_scope = 0; 389*1da177e4SLinus Torvalds rtm->rtm_type = r->r_action; 390*1da177e4SLinus Torvalds rtm->rtm_flags = r->r_flags; 391*1da177e4SLinus Torvalds 392*1da177e4SLinus Torvalds if (r->r_dst_len) 393*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_DST, 4, &r->r_dst); 394*1da177e4SLinus Torvalds if (r->r_src_len) 395*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_SRC, 4, &r->r_src); 396*1da177e4SLinus Torvalds if (r->r_ifname[0]) 397*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname); 398*1da177e4SLinus Torvalds if (r->r_preference) 399*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference); 400*1da177e4SLinus Torvalds if (r->r_srcmap) 401*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap); 402*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE 403*1da177e4SLinus Torvalds if (r->r_tclassid) 404*1da177e4SLinus Torvalds RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid); 405*1da177e4SLinus Torvalds #endif 406*1da177e4SLinus Torvalds nlh->nlmsg_len = skb->tail - b; 407*1da177e4SLinus Torvalds return skb->len; 408*1da177e4SLinus Torvalds 409*1da177e4SLinus Torvalds nlmsg_failure: 410*1da177e4SLinus Torvalds rtattr_failure: 411*1da177e4SLinus Torvalds skb_trim(skb, b - skb->data); 412*1da177e4SLinus Torvalds return -1; 413*1da177e4SLinus Torvalds } 414*1da177e4SLinus Torvalds 415*1da177e4SLinus Torvalds int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) 416*1da177e4SLinus Torvalds { 417*1da177e4SLinus Torvalds int idx; 418*1da177e4SLinus Torvalds int s_idx = cb->args[0]; 419*1da177e4SLinus Torvalds struct fib_rule *r; 420*1da177e4SLinus Torvalds 421*1da177e4SLinus Torvalds read_lock(&fib_rules_lock); 422*1da177e4SLinus Torvalds for (r=fib_rules, idx=0; r; r = r->r_next, idx++) { 423*1da177e4SLinus Torvalds if (idx < s_idx) 424*1da177e4SLinus Torvalds continue; 425*1da177e4SLinus Torvalds if (inet_fill_rule(skb, r, cb) < 0) 426*1da177e4SLinus Torvalds break; 427*1da177e4SLinus Torvalds } 428*1da177e4SLinus Torvalds read_unlock(&fib_rules_lock); 429*1da177e4SLinus Torvalds cb->args[0] = idx; 430*1da177e4SLinus Torvalds 431*1da177e4SLinus Torvalds return skb->len; 432*1da177e4SLinus Torvalds } 433*1da177e4SLinus Torvalds 434*1da177e4SLinus Torvalds void __init fib_rules_init(void) 435*1da177e4SLinus Torvalds { 436*1da177e4SLinus Torvalds register_netdevice_notifier(&fib_rules_notifier); 437*1da177e4SLinus Torvalds } 438