diff options
| author | stephen hemminger <shemminger@vyatta.com> | 2010-03-17 16:31:10 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-03-20 18:44:34 -0400 |
| commit | c2e21293c054817c42eb5fa9c613d2ad51954136 (patch) | |
| tree | 481f7de6d3e3a9a3d93af5654ec174ff5945dc2b /net/ipv6/addrconf.c | |
| parent | 372e6c8f1f7b2bb68f9992d2e664925c73552a1d (diff) | |
ipv6: convert addrconf list to hlist
Using hash list macros, simplifies code and helps later RCU.
This patch includes some initialization that is not strictly necessary,
since an empty hlist node/list is all zero; and list is in BSS
and node is allocated with kzalloc.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
| -rw-r--r-- | net/ipv6/addrconf.c | 128 |
1 files changed, 53 insertions, 75 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f372f895cd41..0488b9f8071d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -126,7 +126,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev); | |||
| 126 | /* | 126 | /* |
| 127 | * Configured unicast address hash table | 127 | * Configured unicast address hash table |
| 128 | */ | 128 | */ |
| 129 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | 129 | static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; |
| 130 | static DEFINE_RWLOCK(addrconf_hash_lock); | 130 | static DEFINE_RWLOCK(addrconf_hash_lock); |
| 131 | 131 | ||
| 132 | static void addrconf_verify(unsigned long); | 132 | static void addrconf_verify(unsigned long); |
| @@ -528,7 +528,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
| 528 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | 528 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) |
| 529 | { | 529 | { |
| 530 | WARN_ON(ifp->if_next != NULL); | 530 | WARN_ON(ifp->if_next != NULL); |
| 531 | WARN_ON(ifp->lst_next != NULL); | 531 | WARN_ON(!hlist_unhashed(&ifp->addr_lst)); |
| 532 | 532 | ||
| 533 | #ifdef NET_REFCNT_DEBUG | 533 | #ifdef NET_REFCNT_DEBUG |
| 534 | printk(KERN_DEBUG "inet6_ifa_finish_destroy\n"); | 534 | printk(KERN_DEBUG "inet6_ifa_finish_destroy\n"); |
| @@ -643,6 +643,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 643 | 643 | ||
| 644 | spin_lock_init(&ifa->lock); | 644 | spin_lock_init(&ifa->lock); |
| 645 | init_timer(&ifa->timer); | 645 | init_timer(&ifa->timer); |
| 646 | INIT_HLIST_NODE(&ifa->addr_lst); | ||
| 646 | ifa->timer.data = (unsigned long) ifa; | 647 | ifa->timer.data = (unsigned long) ifa; |
| 647 | ifa->scope = scope; | 648 | ifa->scope = scope; |
| 648 | ifa->prefix_len = pfxlen; | 649 | ifa->prefix_len = pfxlen; |
| @@ -669,8 +670,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 669 | /* Add to big hash table */ | 670 | /* Add to big hash table */ |
| 670 | hash = ipv6_addr_hash(addr); | 671 | hash = ipv6_addr_hash(addr); |
| 671 | 672 | ||
| 672 | ifa->lst_next = inet6_addr_lst[hash]; | 673 | hlist_add_head(&ifa->addr_lst, &inet6_addr_lst[hash]); |
| 673 | inet6_addr_lst[hash] = ifa; | ||
| 674 | in6_ifa_hold(ifa); | 674 | in6_ifa_hold(ifa); |
| 675 | write_unlock(&addrconf_hash_lock); | 675 | write_unlock(&addrconf_hash_lock); |
| 676 | 676 | ||
| @@ -718,15 +718,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
| 718 | ifp->dead = 1; | 718 | ifp->dead = 1; |
| 719 | 719 | ||
| 720 | write_lock_bh(&addrconf_hash_lock); | 720 | write_lock_bh(&addrconf_hash_lock); |
| 721 | for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL; | 721 | hlist_del_init(&ifp->addr_lst); |
| 722 | ifap = &ifa->lst_next) { | 722 | __in6_ifa_put(ifp); |
| 723 | if (ifa == ifp) { | ||
| 724 | *ifap = ifa->lst_next; | ||
| 725 | __in6_ifa_put(ifp); | ||
| 726 | ifa->lst_next = NULL; | ||
| 727 | break; | ||
| 728 | } | ||
| 729 | } | ||
| 730 | write_unlock_bh(&addrconf_hash_lock); | 723 | write_unlock_bh(&addrconf_hash_lock); |
| 731 | 724 | ||
| 732 | write_lock_bh(&idev->lock); | 725 | write_lock_bh(&idev->lock); |
| @@ -1277,11 +1270,12 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
| 1277 | int ipv6_chk_addr(struct net *net, struct in6_addr *addr, | 1270 | int ipv6_chk_addr(struct net *net, struct in6_addr *addr, |
| 1278 | struct net_device *dev, int strict) | 1271 | struct net_device *dev, int strict) |
| 1279 | { | 1272 | { |
| 1280 | struct inet6_ifaddr * ifp; | 1273 | struct inet6_ifaddr *ifp = NULL; |
| 1274 | struct hlist_node *node; | ||
| 1281 | u8 hash = ipv6_addr_hash(addr); | 1275 | u8 hash = ipv6_addr_hash(addr); |
| 1282 | 1276 | ||
| 1283 | read_lock_bh(&addrconf_hash_lock); | 1277 | read_lock_bh(&addrconf_hash_lock); |
| 1284 | for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { | 1278 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) { |
| 1285 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1279 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1286 | continue; | 1280 | continue; |
| 1287 | if (ipv6_addr_equal(&ifp->addr, addr) && | 1281 | if (ipv6_addr_equal(&ifp->addr, addr) && |
| @@ -1300,10 +1294,11 @@ static | |||
| 1300 | int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | 1294 | int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, |
| 1301 | struct net_device *dev) | 1295 | struct net_device *dev) |
| 1302 | { | 1296 | { |
| 1303 | struct inet6_ifaddr * ifp; | 1297 | struct inet6_ifaddr *ifp; |
| 1298 | struct hlist_node *node; | ||
| 1304 | u8 hash = ipv6_addr_hash(addr); | 1299 | u8 hash = ipv6_addr_hash(addr); |
| 1305 | 1300 | ||
| 1306 | for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { | 1301 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) { |
| 1307 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1302 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1308 | continue; | 1303 | continue; |
| 1309 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1304 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
| @@ -1342,11 +1337,12 @@ EXPORT_SYMBOL(ipv6_chk_prefix); | |||
| 1342 | struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, | 1337 | struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, |
| 1343 | struct net_device *dev, int strict) | 1338 | struct net_device *dev, int strict) |
| 1344 | { | 1339 | { |
| 1345 | struct inet6_ifaddr * ifp; | 1340 | struct inet6_ifaddr *ifp = NULL; |
| 1341 | struct hlist_node *node; | ||
| 1346 | u8 hash = ipv6_addr_hash(addr); | 1342 | u8 hash = ipv6_addr_hash(addr); |
| 1347 | 1343 | ||
| 1348 | read_lock_bh(&addrconf_hash_lock); | 1344 | read_lock_bh(&addrconf_hash_lock); |
| 1349 | for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { | 1345 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) { |
| 1350 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1346 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 1351 | continue; | 1347 | continue; |
| 1352 | if (ipv6_addr_equal(&ifp->addr, addr)) { | 1348 | if (ipv6_addr_equal(&ifp->addr, addr)) { |
| @@ -2612,7 +2608,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2612 | struct inet6_dev *idev; | 2608 | struct inet6_dev *idev; |
| 2613 | struct inet6_ifaddr *ifa, *keep_list, **bifa; | 2609 | struct inet6_ifaddr *ifa, *keep_list, **bifa; |
| 2614 | struct net *net = dev_net(dev); | 2610 | struct net *net = dev_net(dev); |
| 2615 | int i; | ||
| 2616 | 2611 | ||
| 2617 | ASSERT_RTNL(); | 2612 | ASSERT_RTNL(); |
| 2618 | 2613 | ||
| @@ -2637,25 +2632,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2637 | 2632 | ||
| 2638 | } | 2633 | } |
| 2639 | 2634 | ||
| 2640 | /* Step 2: clear hash table */ | ||
| 2641 | for (i=0; i<IN6_ADDR_HSIZE; i++) { | ||
| 2642 | bifa = &inet6_addr_lst[i]; | ||
| 2643 | |||
| 2644 | write_lock_bh(&addrconf_hash_lock); | ||
| 2645 | while ((ifa = *bifa) != NULL) { | ||
| 2646 | if (ifa->idev == idev && | ||
| 2647 | (how || !(ifa->flags&IFA_F_PERMANENT) || | ||
| 2648 | ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { | ||
| 2649 | *bifa = ifa->lst_next; | ||
| 2650 | ifa->lst_next = NULL; | ||
| 2651 | __in6_ifa_put(ifa); | ||
| 2652 | continue; | ||
| 2653 | } | ||
| 2654 | bifa = &ifa->lst_next; | ||
| 2655 | } | ||
| 2656 | write_unlock_bh(&addrconf_hash_lock); | ||
| 2657 | } | ||
| 2658 | |||
| 2659 | write_lock_bh(&idev->lock); | 2635 | write_lock_bh(&idev->lock); |
| 2660 | 2636 | ||
| 2661 | /* Step 3: clear flags for stateless addrconf */ | 2637 | /* Step 3: clear flags for stateless addrconf */ |
| @@ -2721,6 +2697,12 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2721 | } | 2697 | } |
| 2722 | write_unlock_bh(&idev->lock); | 2698 | write_unlock_bh(&idev->lock); |
| 2723 | 2699 | ||
| 2700 | /* clear hash table */ | ||
| 2701 | write_lock_bh(&addrconf_hash_lock); | ||
| 2702 | hlist_del_init(&ifa->addr_lst); | ||
| 2703 | __in6_ifa_put(ifa); | ||
| 2704 | write_unlock_bh(&addrconf_hash_lock); | ||
| 2705 | |||
| 2724 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2706 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
| 2725 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | 2707 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); |
| 2726 | in6_ifa_put(ifa); | 2708 | in6_ifa_put(ifa); |
| @@ -2963,36 +2945,37 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) | |||
| 2963 | struct net *net = seq_file_net(seq); | 2945 | struct net *net = seq_file_net(seq); |
| 2964 | 2946 | ||
| 2965 | for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { | 2947 | for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { |
| 2966 | ifa = inet6_addr_lst[state->bucket]; | 2948 | struct hlist_node *n; |
| 2967 | 2949 | hlist_for_each_entry(ifa, n, | |
| 2968 | while (ifa && !net_eq(dev_net(ifa->idev->dev), net)) | 2950 | &inet6_addr_lst[state->bucket], addr_lst) { |
| 2969 | ifa = ifa->lst_next; | 2951 | if (net_eq(dev_net(ifa->idev->dev), net)) |
| 2970 | if (ifa) | 2952 | return ifa; |
| 2971 | break; | 2953 | } |
| 2972 | } | 2954 | } |
| 2973 | return ifa; | 2955 | return NULL; |
| 2974 | } | 2956 | } |
| 2975 | 2957 | ||
| 2976 | static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa) | 2958 | static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, |
| 2959 | struct inet6_ifaddr *ifa) | ||
| 2977 | { | 2960 | { |
| 2978 | struct if6_iter_state *state = seq->private; | 2961 | struct if6_iter_state *state = seq->private; |
| 2979 | struct net *net = seq_file_net(seq); | 2962 | struct net *net = seq_file_net(seq); |
| 2963 | struct hlist_node *n = &ifa->addr_lst; | ||
| 2980 | 2964 | ||
| 2981 | ifa = ifa->lst_next; | 2965 | hlist_for_each_entry_continue(ifa, n, addr_lst) { |
| 2982 | try_again: | 2966 | if (net_eq(dev_net(ifa->idev->dev), net)) |
| 2983 | if (ifa) { | 2967 | return ifa; |
| 2984 | if (!net_eq(dev_net(ifa->idev->dev), net)) { | ||
| 2985 | ifa = ifa->lst_next; | ||
| 2986 | goto try_again; | ||
| 2987 | } | ||
| 2988 | } | 2968 | } |
| 2989 | 2969 | ||
| 2990 | if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) { | 2970 | while (++state->bucket < IN6_ADDR_HSIZE) { |
| 2991 | ifa = inet6_addr_lst[state->bucket]; | 2971 | hlist_for_each_entry(ifa, n, |
| 2992 | goto try_again; | 2972 | &inet6_addr_lst[state->bucket], addr_lst) { |
| 2973 | if (net_eq(dev_net(ifa->idev->dev), net)) | ||
| 2974 | return ifa; | ||
| 2975 | } | ||
| 2993 | } | 2976 | } |
| 2994 | 2977 | ||
| 2995 | return ifa; | 2978 | return NULL; |
| 2996 | } | 2979 | } |
| 2997 | 2980 | ||
| 2998 | static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) | 2981 | static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) |
| @@ -3094,10 +3077,12 @@ void if6_proc_exit(void) | |||
| 3094 | int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | 3077 | int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) |
| 3095 | { | 3078 | { |
| 3096 | int ret = 0; | 3079 | int ret = 0; |
| 3097 | struct inet6_ifaddr * ifp; | 3080 | struct inet6_ifaddr *ifp = NULL; |
| 3081 | struct hlist_node *n; | ||
| 3098 | u8 hash = ipv6_addr_hash(addr); | 3082 | u8 hash = ipv6_addr_hash(addr); |
| 3083 | |||
| 3099 | read_lock_bh(&addrconf_hash_lock); | 3084 | read_lock_bh(&addrconf_hash_lock); |
| 3100 | for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { | 3085 | hlist_for_each_entry(ifp, n, &inet6_addr_lst[hash], addr_lst) { |
| 3101 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 3086 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
| 3102 | continue; | 3087 | continue; |
| 3103 | if (ipv6_addr_equal(&ifp->addr, addr) && | 3088 | if (ipv6_addr_equal(&ifp->addr, addr) && |
| @@ -3118,6 +3103,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | |||
| 3118 | static void addrconf_verify(unsigned long foo) | 3103 | static void addrconf_verify(unsigned long foo) |
| 3119 | { | 3104 | { |
| 3120 | struct inet6_ifaddr *ifp; | 3105 | struct inet6_ifaddr *ifp; |
| 3106 | struct hlist_node *node; | ||
| 3121 | unsigned long now, next; | 3107 | unsigned long now, next; |
| 3122 | int i; | 3108 | int i; |
| 3123 | 3109 | ||
| @@ -3131,7 +3117,7 @@ static void addrconf_verify(unsigned long foo) | |||
| 3131 | 3117 | ||
| 3132 | restart: | 3118 | restart: |
| 3133 | read_lock(&addrconf_hash_lock); | 3119 | read_lock(&addrconf_hash_lock); |
| 3134 | for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { | 3120 | hlist_for_each_entry(ifp, node, &inet6_addr_lst[i], addr_lst) { |
| 3135 | unsigned long age; | 3121 | unsigned long age; |
| 3136 | #ifdef CONFIG_IPV6_PRIVACY | 3122 | #ifdef CONFIG_IPV6_PRIVACY |
| 3137 | unsigned long regen_advance; | 3123 | unsigned long regen_advance; |
| @@ -4550,7 +4536,7 @@ EXPORT_SYMBOL(unregister_inet6addr_notifier); | |||
| 4550 | 4536 | ||
| 4551 | int __init addrconf_init(void) | 4537 | int __init addrconf_init(void) |
| 4552 | { | 4538 | { |
| 4553 | int err; | 4539 | int i, err; |
| 4554 | 4540 | ||
| 4555 | if ((err = ipv6_addr_label_init()) < 0) { | 4541 | if ((err = ipv6_addr_label_init()) < 0) { |
| 4556 | printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n", | 4542 | printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n", |
| @@ -4585,6 +4571,9 @@ int __init addrconf_init(void) | |||
| 4585 | if (err) | 4571 | if (err) |
| 4586 | goto errlo; | 4572 | goto errlo; |
| 4587 | 4573 | ||
| 4574 | for (i = 0; i < IN6_ADDR_HSIZE; i++) | ||
| 4575 | INIT_HLIST_HEAD(&inet6_addr_lst[i]); | ||
| 4576 | |||
| 4588 | register_netdevice_notifier(&ipv6_dev_notf); | 4577 | register_netdevice_notifier(&ipv6_dev_notf); |
| 4589 | 4578 | ||
| 4590 | addrconf_verify(0); | 4579 | addrconf_verify(0); |
| @@ -4613,7 +4602,6 @@ errlo: | |||
| 4613 | 4602 | ||
| 4614 | void addrconf_cleanup(void) | 4603 | void addrconf_cleanup(void) |
| 4615 | { | 4604 | { |
| 4616 | struct inet6_ifaddr *ifa; | ||
| 4617 | struct net_device *dev; | 4605 | struct net_device *dev; |
| 4618 | int i; | 4606 | int i; |
| 4619 | 4607 | ||
| @@ -4634,18 +4622,8 @@ void addrconf_cleanup(void) | |||
| 4634 | * Check hash table. | 4622 | * Check hash table. |
| 4635 | */ | 4623 | */ |
| 4636 | write_lock_bh(&addrconf_hash_lock); | 4624 | write_lock_bh(&addrconf_hash_lock); |
| 4637 | for (i=0; i < IN6_ADDR_HSIZE; i++) { | 4625 | for (i = 0; i < IN6_ADDR_HSIZE; i++) |
| 4638 | for (ifa=inet6_addr_lst[i]; ifa; ) { | 4626 | WARN_ON(!hlist_empty(&inet6_addr_lst[i])); |
| 4639 | struct inet6_ifaddr *bifa; | ||
| 4640 | |||
| 4641 | bifa = ifa; | ||
| 4642 | ifa = ifa->lst_next; | ||
| 4643 | printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa); | ||
| 4644 | /* Do not free it; something is wrong. | ||
| 4645 | Now we can investigate it with debugger. | ||
| 4646 | */ | ||
| 4647 | } | ||
| 4648 | } | ||
| 4649 | write_unlock_bh(&addrconf_hash_lock); | 4627 | write_unlock_bh(&addrconf_hash_lock); |
| 4650 | 4628 | ||
| 4651 | del_timer(&addr_chk_timer); | 4629 | del_timer(&addr_chk_timer); |
