X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv4%2Ffib_semantics.c;h=ded2ae34eab15017821063de974a8792d4474d0b;hb=8725f25acc656c1522d48a6746055099efdaca4c;hp=1351a2617dcef072ee0adebdd59ea1007b9a4bbd;hpb=8f4c1f9b049df3be11090f1c2c4738700302acae;p=linux-2.6 diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 1351a2617d..ded2ae34ea 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -5,8 +5,6 @@ * * IPv4 Forwarding Information Base: semantics. * - * Version: $Id: fib_semantics.c,v 1.19 2002/01/12 07:54:56 davem Exp $ - * * Authors: Alexey Kuznetsov, * * This program is free software; you can redistribute it and/or @@ -47,8 +45,6 @@ #include "fib_lookup.h" -#define FSprintk(a...) - static DEFINE_SPINLOCK(fib_info_lock); static struct hlist_head *fib_info_hash; static struct hlist_head *fib_info_laddrhash; @@ -145,7 +141,7 @@ static const struct void free_fib_info(struct fib_info *fi) { if (fi->fib_dead == 0) { - printk("Freeing alive fib_info %p\n", fi); + printk(KERN_WARNING "Freeing alive fib_info %p\n", fi); return; } change_nexthops(fi) { @@ -154,6 +150,7 @@ void free_fib_info(struct fib_info *fi) nh->nh_dev = NULL; } endfor_nexthops(fi); fib_info_cnt--; + release_net(fi->fib_net); kfree(fi); } @@ -196,6 +193,15 @@ static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info * return 0; } +static inline unsigned int fib_devindex_hashfn(unsigned int val) +{ + unsigned int mask = DEVINDEX_HASHSIZE - 1; + + return (val ^ + (val >> DEVINDEX_HASHBITS) ^ + (val >> (DEVINDEX_HASHBITS * 2))) & mask; +} + static inline unsigned int fib_info_hashfn(const struct fib_info *fi) { unsigned int mask = (fib_hash_size - 1); @@ -204,6 +210,9 @@ static inline unsigned int fib_info_hashfn(const struct fib_info *fi) val ^= fi->fib_protocol; val ^= (__force u32)fi->fib_prefsrc; val ^= fi->fib_priority; + for_nexthops(fi) { + val ^= fib_devindex_hashfn(nh->nh_oif); + } endfor_nexthops(fi) return (val ^ (val >> 7) ^ (val >> 12)) & mask; } @@ -219,6 +228,8 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi) head = &fib_info_hash[hash]; hlist_for_each_entry(fi, node, head, fib_hash) { + if (fi->fib_net != nfi->fib_net) + continue; if (fi->fib_nhs != nfi->fib_nhs) continue; if (nfi->fib_protocol == fi->fib_protocol && @@ -234,15 +245,6 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi) return NULL; } -static inline unsigned int fib_devindex_hashfn(unsigned int val) -{ - unsigned int mask = DEVINDEX_HASHSIZE - 1; - - return (val ^ - (val >> DEVINDEX_HASHBITS) ^ - (val >> (DEVINDEX_HASHBITS * 2))) & mask; -} - /* Check, that the gateway is already configured. Used only by redirect accept routine. */ @@ -320,11 +322,11 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, kfree_skb(skb); goto errout; } - err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, + err = rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE, info->nlh, GFP_KERNEL); errout: if (err < 0) - rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err); + rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); } /* Return the first fib alias matching TOS with @@ -346,7 +348,7 @@ struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio) } int fib_detect_death(struct fib_info *fi, int order, - struct fib_info **last_resort, int *last_idx, int *dflt) + struct fib_info **last_resort, int *last_idx, int dflt) { struct neighbour *n; int state = NUD_NONE; @@ -358,10 +360,10 @@ int fib_detect_death(struct fib_info *fi, int order, } if (state==NUD_REACHABLE) return 0; - if ((state&NUD_VALID) && order != *dflt) + if ((state&NUD_VALID) && order != dflt) return 0; if ((state&NUD_VALID) || - (*last_idx<0 && order > *dflt)) { + (*last_idx<0 && order > dflt)) { *last_resort = fi; *last_idx = order; } @@ -518,7 +520,9 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, struct fib_nh *nh) { int err; + struct net *net; + net = cfg->fc_nlinfo.nl_net; if (nh->nh_gw) { struct fib_result res; @@ -531,9 +535,9 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, if (cfg->fc_scope >= RT_SCOPE_LINK) return -EINVAL; - if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) + if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST) return -EINVAL; - if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) + if ((dev = __dev_get_by_index(net, nh->nh_oif)) == NULL) return -ENODEV; if (!(dev->flags&IFF_UP)) return -ENETDOWN; @@ -556,7 +560,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, /* It is not necessary, but requires a bit of thinking */ if (fl.fl4_scope < RT_SCOPE_LINK) fl.fl4_scope = RT_SCOPE_LINK; - if ((err = fib_lookup(&fl, &res)) != 0) + if ((err = fib_lookup(net, &fl, &res)) != 0) return err; } err = -EINVAL; @@ -580,7 +584,7 @@ out: if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) return -EINVAL; - in_dev = inetdev_by_index(nh->nh_oif); + in_dev = inetdev_by_index(net, nh->nh_oif); if (in_dev == NULL) return -ENODEV; if (!(in_dev->dev->flags&IFF_UP)) { @@ -605,10 +609,10 @@ static inline unsigned int fib_laddr_hashfn(__be32 val) static struct hlist_head *fib_hash_alloc(int bytes) { if (bytes <= PAGE_SIZE) - return kmalloc(bytes, GFP_KERNEL); + return kzalloc(bytes, GFP_KERNEL); else return (struct hlist_head *) - __get_free_pages(GFP_KERNEL, get_order(bytes)); + __get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(bytes)); } static void fib_hash_free(struct hlist_head *hash, int bytes) @@ -684,6 +688,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) struct fib_info *fi = NULL; struct fib_info *ofi; int nhs = 1; + struct net *net = cfg->fc_nlinfo.nl_net; /* Fast check to catch the most weird cases */ if (fib_props[cfg->fc_type].scope > cfg->fc_scope) @@ -712,12 +717,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (!new_info_hash || !new_laddrhash) { fib_hash_free(new_info_hash, bytes); fib_hash_free(new_laddrhash, bytes); - } else { - memset(new_info_hash, 0, bytes); - memset(new_laddrhash, 0, bytes); - + } else fib_hash_move(new_info_hash, new_laddrhash, new_size); - } if (!fib_hash_size) goto failure; @@ -728,6 +729,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) goto failure; fib_info_cnt++; + fi->fib_net = hold_net(net); fi->fib_protocol = cfg->fc_protocol; fi->fib_flags = cfg->fc_flags; fi->fib_priority = cfg->fc_priority; @@ -799,7 +801,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (nhs != 1 || nh->nh_gw) goto err_inval; nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); + nh->nh_dev = dev_get_by_index(net, fi->fib_nh->nh_oif); err = -ENODEV; if (nh->nh_dev == NULL) goto failure; @@ -813,7 +815,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (fi->fib_prefsrc) { if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || fi->fib_prefsrc != cfg->fc_dst) - if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) + if (inet_addr_type(net, fi->fib_prefsrc) != RTN_LOCAL) goto err_inval; } @@ -914,7 +916,8 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp, continue; default: - printk(KERN_DEBUG "impossible 102\n"); + printk(KERN_WARNING "fib_semantic_match bad type %#x\n", + fa->fa_type); return -EINVAL; } } @@ -955,7 +958,10 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, rtm->rtm_dst_len = dst_len; rtm->rtm_src_len = 0; rtm->rtm_tos = tos; - rtm->rtm_table = tb_id; + if (tb_id < 256) + rtm->rtm_table = tb_id; + else + rtm->rtm_table = RT_TABLE_COMPAT; NLA_PUT_U32(skb, RTA_TABLE, tb_id); rtm->rtm_type = type; rtm->rtm_flags = fi->fib_flags; @@ -1029,70 +1035,74 @@ nla_put_failure: referring to it. - device went down -> we must shutdown all nexthops going via it. */ - -int fib_sync_down(__be32 local, struct net_device *dev, int force) +int fib_sync_down_addr(struct net *net, __be32 local) { int ret = 0; - int scope = RT_SCOPE_NOWHERE; - - if (force) - scope = -1; + unsigned int hash = fib_laddr_hashfn(local); + struct hlist_head *head = &fib_info_laddrhash[hash]; + struct hlist_node *node; + struct fib_info *fi; - if (local && fib_info_laddrhash) { - unsigned int hash = fib_laddr_hashfn(local); - struct hlist_head *head = &fib_info_laddrhash[hash]; - struct hlist_node *node; - struct fib_info *fi; + if (fib_info_laddrhash == NULL || local == 0) + return 0; - hlist_for_each_entry(fi, node, head, fib_lhash) { - if (fi->fib_prefsrc == local) { - fi->fib_flags |= RTNH_F_DEAD; - ret++; - } + hlist_for_each_entry(fi, node, head, fib_lhash) { + if (fi->fib_net != net) + continue; + if (fi->fib_prefsrc == local) { + fi->fib_flags |= RTNH_F_DEAD; + ret++; } } + return ret; +} - if (dev) { - struct fib_info *prev_fi = NULL; - unsigned int hash = fib_devindex_hashfn(dev->ifindex); - struct hlist_head *head = &fib_info_devhash[hash]; - struct hlist_node *node; - struct fib_nh *nh; +int fib_sync_down_dev(struct net_device *dev, int force) +{ + int ret = 0; + int scope = RT_SCOPE_NOWHERE; + struct fib_info *prev_fi = NULL; + unsigned int hash = fib_devindex_hashfn(dev->ifindex); + struct hlist_head *head = &fib_info_devhash[hash]; + struct hlist_node *node; + struct fib_nh *nh; - hlist_for_each_entry(nh, node, head, nh_hash) { - struct fib_info *fi = nh->nh_parent; - int dead; + if (force) + scope = -1; - BUG_ON(!fi->fib_nhs); - if (nh->nh_dev != dev || fi == prev_fi) - continue; - prev_fi = fi; - dead = 0; - change_nexthops(fi) { - if (nh->nh_flags&RTNH_F_DEAD) - dead++; - else if (nh->nh_dev == dev && - nh->nh_scope != scope) { - nh->nh_flags |= RTNH_F_DEAD; + hlist_for_each_entry(nh, node, head, nh_hash) { + struct fib_info *fi = nh->nh_parent; + int dead; + + BUG_ON(!fi->fib_nhs); + if (nh->nh_dev != dev || fi == prev_fi) + continue; + prev_fi = fi; + dead = 0; + change_nexthops(fi) { + if (nh->nh_flags&RTNH_F_DEAD) + dead++; + else if (nh->nh_dev == dev && + nh->nh_scope != scope) { + nh->nh_flags |= RTNH_F_DEAD; #ifdef CONFIG_IP_ROUTE_MULTIPATH - spin_lock_bh(&fib_multipath_lock); - fi->fib_power -= nh->nh_power; - nh->nh_power = 0; - spin_unlock_bh(&fib_multipath_lock); + spin_lock_bh(&fib_multipath_lock); + fi->fib_power -= nh->nh_power; + nh->nh_power = 0; + spin_unlock_bh(&fib_multipath_lock); #endif - dead++; - } + dead++; + } #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (force > 1 && nh->nh_dev == dev) { - dead = fi->fib_nhs; - break; - } -#endif - } endfor_nexthops(fi) - if (dead == fi->fib_nhs) { - fi->fib_flags |= RTNH_F_DEAD; - ret++; + if (force > 1 && nh->nh_dev == dev) { + dead = fi->fib_nhs; + break; } +#endif + } endfor_nexthops(fi) + if (dead == fi->fib_nhs) { + fi->fib_flags |= RTNH_F_DEAD; + ret++; } }