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 | |
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>
-rw-r--r-- | include/net/if_inet6.h | 2 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 128 |
2 files changed, 54 insertions, 76 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 09d906460a43..498401541519 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -54,7 +54,7 @@ struct inet6_ifaddr { | |||
54 | struct inet6_dev *idev; | 54 | struct inet6_dev *idev; |
55 | struct rt6_info *rt; | 55 | struct rt6_info *rt; |
56 | 56 | ||
57 | struct inet6_ifaddr *lst_next; /* next addr in addr_lst */ | 57 | struct hlist_node addr_lst; |
58 | struct inet6_ifaddr *if_next; /* next addr in inet6_dev */ | 58 | struct inet6_ifaddr *if_next; /* next addr in inet6_dev */ |
59 | 59 | ||
60 | #ifdef CONFIG_IPV6_PRIVACY | 60 | #ifdef CONFIG_IPV6_PRIVACY |
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); |