diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-04-26 04:22:15 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-04-26 04:22:59 -0400 |
| commit | 07f9479a40cc778bc1462ada11f95b01360ae4ff (patch) | |
| tree | 0676cf38df3844004bb3ebfd99dfa67a4a8998f5 /net/ipv4/fib_frontend.c | |
| parent | 9d5e6bdb3013acfb311ab407eeca0b6a6a3dedbf (diff) | |
| parent | cd2e49e90f1cae7726c9a2c54488d881d7f1cd1c (diff) | |
Merge branch 'master' into for-next
Fast-forwarded to current state of Linus' tree as there are patches to be
applied for files that didn't exist on the old branch.
Diffstat (limited to 'net/ipv4/fib_frontend.c')
| -rw-r--r-- | net/ipv4/fib_frontend.c | 114 |
1 files changed, 97 insertions, 17 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index a373a259253c..451088330bbb 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
| @@ -228,7 +228,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
| 228 | if (res.type != RTN_LOCAL || !accept_local) | 228 | if (res.type != RTN_LOCAL || !accept_local) |
| 229 | goto e_inval; | 229 | goto e_inval; |
| 230 | } | 230 | } |
| 231 | *spec_dst = FIB_RES_PREFSRC(res); | 231 | *spec_dst = FIB_RES_PREFSRC(net, res); |
| 232 | fib_combine_itag(itag, &res); | 232 | fib_combine_itag(itag, &res); |
| 233 | dev_match = false; | 233 | dev_match = false; |
| 234 | 234 | ||
| @@ -258,7 +258,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
| 258 | ret = 0; | 258 | ret = 0; |
| 259 | if (fib_lookup(net, &fl4, &res) == 0) { | 259 | if (fib_lookup(net, &fl4, &res) == 0) { |
| 260 | if (res.type == RTN_UNICAST) { | 260 | if (res.type == RTN_UNICAST) { |
| 261 | *spec_dst = FIB_RES_PREFSRC(res); | 261 | *spec_dst = FIB_RES_PREFSRC(net, res); |
| 262 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; | 262 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
| 263 | } | 263 | } |
| 264 | } | 264 | } |
| @@ -722,12 +722,17 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) | |||
| 722 | } | 722 | } |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | static void fib_del_ifaddr(struct in_ifaddr *ifa) | 725 | /* Delete primary or secondary address. |
| 726 | * Optionally, on secondary address promotion consider the addresses | ||
| 727 | * from subnet iprim as deleted, even if they are in device list. | ||
| 728 | * In this case the secondary ifa can be in device list. | ||
| 729 | */ | ||
| 730 | void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | ||
| 726 | { | 731 | { |
| 727 | struct in_device *in_dev = ifa->ifa_dev; | 732 | struct in_device *in_dev = ifa->ifa_dev; |
| 728 | struct net_device *dev = in_dev->dev; | 733 | struct net_device *dev = in_dev->dev; |
| 729 | struct in_ifaddr *ifa1; | 734 | struct in_ifaddr *ifa1; |
| 730 | struct in_ifaddr *prim = ifa; | 735 | struct in_ifaddr *prim = ifa, *prim1 = NULL; |
| 731 | __be32 brd = ifa->ifa_address | ~ifa->ifa_mask; | 736 | __be32 brd = ifa->ifa_address | ~ifa->ifa_mask; |
| 732 | __be32 any = ifa->ifa_address & ifa->ifa_mask; | 737 | __be32 any = ifa->ifa_address & ifa->ifa_mask; |
| 733 | #define LOCAL_OK 1 | 738 | #define LOCAL_OK 1 |
| @@ -735,17 +740,26 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) | |||
| 735 | #define BRD0_OK 4 | 740 | #define BRD0_OK 4 |
| 736 | #define BRD1_OK 8 | 741 | #define BRD1_OK 8 |
| 737 | unsigned ok = 0; | 742 | unsigned ok = 0; |
| 743 | int subnet = 0; /* Primary network */ | ||
| 744 | int gone = 1; /* Address is missing */ | ||
| 745 | int same_prefsrc = 0; /* Another primary with same IP */ | ||
| 738 | 746 | ||
| 739 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) | 747 | if (ifa->ifa_flags & IFA_F_SECONDARY) { |
| 740 | fib_magic(RTM_DELROUTE, | ||
| 741 | dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, | ||
| 742 | any, ifa->ifa_prefixlen, prim); | ||
| 743 | else { | ||
| 744 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); | 748 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); |
| 745 | if (prim == NULL) { | 749 | if (prim == NULL) { |
| 746 | printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n"); | 750 | printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n"); |
| 747 | return; | 751 | return; |
| 748 | } | 752 | } |
| 753 | if (iprim && iprim != prim) { | ||
| 754 | printk(KERN_WARNING "fib_del_ifaddr: bug: iprim != prim\n"); | ||
| 755 | return; | ||
| 756 | } | ||
| 757 | } else if (!ipv4_is_zeronet(any) && | ||
| 758 | (any != ifa->ifa_local || ifa->ifa_prefixlen < 32)) { | ||
| 759 | fib_magic(RTM_DELROUTE, | ||
| 760 | dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, | ||
| 761 | any, ifa->ifa_prefixlen, prim); | ||
| 762 | subnet = 1; | ||
| 749 | } | 763 | } |
| 750 | 764 | ||
| 751 | /* Deletion is more complicated than add. | 765 | /* Deletion is more complicated than add. |
| @@ -755,6 +769,49 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) | |||
| 755 | */ | 769 | */ |
| 756 | 770 | ||
| 757 | for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { | 771 | for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { |
| 772 | if (ifa1 == ifa) { | ||
| 773 | /* promotion, keep the IP */ | ||
| 774 | gone = 0; | ||
| 775 | continue; | ||
| 776 | } | ||
| 777 | /* Ignore IFAs from our subnet */ | ||
| 778 | if (iprim && ifa1->ifa_mask == iprim->ifa_mask && | ||
| 779 | inet_ifa_match(ifa1->ifa_address, iprim)) | ||
| 780 | continue; | ||
| 781 | |||
| 782 | /* Ignore ifa1 if it uses different primary IP (prefsrc) */ | ||
| 783 | if (ifa1->ifa_flags & IFA_F_SECONDARY) { | ||
| 784 | /* Another address from our subnet? */ | ||
| 785 | if (ifa1->ifa_mask == prim->ifa_mask && | ||
| 786 | inet_ifa_match(ifa1->ifa_address, prim)) | ||
| 787 | prim1 = prim; | ||
| 788 | else { | ||
| 789 | /* We reached the secondaries, so | ||
| 790 | * same_prefsrc should be determined. | ||
| 791 | */ | ||
| 792 | if (!same_prefsrc) | ||
| 793 | continue; | ||
| 794 | /* Search new prim1 if ifa1 is not | ||
| 795 | * using the current prim1 | ||
| 796 | */ | ||
| 797 | if (!prim1 || | ||
| 798 | ifa1->ifa_mask != prim1->ifa_mask || | ||
| 799 | !inet_ifa_match(ifa1->ifa_address, prim1)) | ||
| 800 | prim1 = inet_ifa_byprefix(in_dev, | ||
| 801 | ifa1->ifa_address, | ||
| 802 | ifa1->ifa_mask); | ||
| 803 | if (!prim1) | ||
| 804 | continue; | ||
| 805 | if (prim1->ifa_local != prim->ifa_local) | ||
| 806 | continue; | ||
| 807 | } | ||
| 808 | } else { | ||
| 809 | if (prim->ifa_local != ifa1->ifa_local) | ||
| 810 | continue; | ||
| 811 | prim1 = ifa1; | ||
| 812 | if (prim != prim1) | ||
| 813 | same_prefsrc = 1; | ||
| 814 | } | ||
| 758 | if (ifa->ifa_local == ifa1->ifa_local) | 815 | if (ifa->ifa_local == ifa1->ifa_local) |
| 759 | ok |= LOCAL_OK; | 816 | ok |= LOCAL_OK; |
| 760 | if (ifa->ifa_broadcast == ifa1->ifa_broadcast) | 817 | if (ifa->ifa_broadcast == ifa1->ifa_broadcast) |
| @@ -763,19 +820,37 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) | |||
| 763 | ok |= BRD1_OK; | 820 | ok |= BRD1_OK; |
| 764 | if (any == ifa1->ifa_broadcast) | 821 | if (any == ifa1->ifa_broadcast) |
| 765 | ok |= BRD0_OK; | 822 | ok |= BRD0_OK; |
| 823 | /* primary has network specific broadcasts */ | ||
| 824 | if (prim1 == ifa1 && ifa1->ifa_prefixlen < 31) { | ||
| 825 | __be32 brd1 = ifa1->ifa_address | ~ifa1->ifa_mask; | ||
| 826 | __be32 any1 = ifa1->ifa_address & ifa1->ifa_mask; | ||
| 827 | |||
| 828 | if (!ipv4_is_zeronet(any1)) { | ||
| 829 | if (ifa->ifa_broadcast == brd1 || | ||
| 830 | ifa->ifa_broadcast == any1) | ||
| 831 | ok |= BRD_OK; | ||
| 832 | if (brd == brd1 || brd == any1) | ||
| 833 | ok |= BRD1_OK; | ||
| 834 | if (any == brd1 || any == any1) | ||
| 835 | ok |= BRD0_OK; | ||
| 836 | } | ||
| 837 | } | ||
| 766 | } | 838 | } |
| 767 | 839 | ||
| 768 | if (!(ok & BRD_OK)) | 840 | if (!(ok & BRD_OK)) |
| 769 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); | 841 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
| 770 | if (!(ok & BRD1_OK)) | 842 | if (subnet && ifa->ifa_prefixlen < 31) { |
| 771 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); | 843 | if (!(ok & BRD1_OK)) |
| 772 | if (!(ok & BRD0_OK)) | 844 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); |
| 773 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); | 845 | if (!(ok & BRD0_OK)) |
| 846 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); | ||
| 847 | } | ||
| 774 | if (!(ok & LOCAL_OK)) { | 848 | if (!(ok & LOCAL_OK)) { |
| 775 | fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); | 849 | fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); |
| 776 | 850 | ||
| 777 | /* Check, that this local address finally disappeared. */ | 851 | /* Check, that this local address finally disappeared. */ |
| 778 | if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { | 852 | if (gone && |
| 853 | inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { | ||
| 779 | /* And the last, but not the least thing. | 854 | /* And the last, but not the least thing. |
| 780 | * We must flush stray FIB entries. | 855 | * We must flush stray FIB entries. |
| 781 | * | 856 | * |
| @@ -885,6 +960,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
| 885 | { | 960 | { |
| 886 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; | 961 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; |
| 887 | struct net_device *dev = ifa->ifa_dev->dev; | 962 | struct net_device *dev = ifa->ifa_dev->dev; |
| 963 | struct net *net = dev_net(dev); | ||
| 888 | 964 | ||
| 889 | switch (event) { | 965 | switch (event) { |
| 890 | case NETDEV_UP: | 966 | case NETDEV_UP: |
| @@ -892,12 +968,12 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
| 892 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 968 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
| 893 | fib_sync_up(dev); | 969 | fib_sync_up(dev); |
| 894 | #endif | 970 | #endif |
| 895 | fib_update_nh_saddrs(dev); | 971 | atomic_inc(&net->ipv4.dev_addr_genid); |
| 896 | rt_cache_flush(dev_net(dev), -1); | 972 | rt_cache_flush(dev_net(dev), -1); |
| 897 | break; | 973 | break; |
| 898 | case NETDEV_DOWN: | 974 | case NETDEV_DOWN: |
| 899 | fib_del_ifaddr(ifa); | 975 | fib_del_ifaddr(ifa, NULL); |
| 900 | fib_update_nh_saddrs(dev); | 976 | atomic_inc(&net->ipv4.dev_addr_genid); |
| 901 | if (ifa->ifa_dev->ifa_list == NULL) { | 977 | if (ifa->ifa_dev->ifa_list == NULL) { |
| 902 | /* Last address was deleted from this interface. | 978 | /* Last address was deleted from this interface. |
| 903 | * Disable IP. | 979 | * Disable IP. |
| @@ -915,6 +991,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
| 915 | { | 991 | { |
| 916 | struct net_device *dev = ptr; | 992 | struct net_device *dev = ptr; |
| 917 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 993 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
| 994 | struct net *net = dev_net(dev); | ||
| 918 | 995 | ||
| 919 | if (event == NETDEV_UNREGISTER) { | 996 | if (event == NETDEV_UNREGISTER) { |
| 920 | fib_disable_ip(dev, 2, -1); | 997 | fib_disable_ip(dev, 2, -1); |
| @@ -932,6 +1009,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
| 932 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 1009 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
| 933 | fib_sync_up(dev); | 1010 | fib_sync_up(dev); |
| 934 | #endif | 1011 | #endif |
| 1012 | atomic_inc(&net->ipv4.dev_addr_genid); | ||
| 935 | rt_cache_flush(dev_net(dev), -1); | 1013 | rt_cache_flush(dev_net(dev), -1); |
| 936 | break; | 1014 | break; |
| 937 | case NETDEV_DOWN: | 1015 | case NETDEV_DOWN: |
| @@ -990,6 +1068,7 @@ static void ip_fib_net_exit(struct net *net) | |||
| 990 | fib4_rules_exit(net); | 1068 | fib4_rules_exit(net); |
| 991 | #endif | 1069 | #endif |
| 992 | 1070 | ||
| 1071 | rtnl_lock(); | ||
| 993 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) { | 1072 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) { |
| 994 | struct fib_table *tb; | 1073 | struct fib_table *tb; |
| 995 | struct hlist_head *head; | 1074 | struct hlist_head *head; |
| @@ -1002,6 +1081,7 @@ static void ip_fib_net_exit(struct net *net) | |||
| 1002 | fib_free_table(tb); | 1081 | fib_free_table(tb); |
| 1003 | } | 1082 | } |
| 1004 | } | 1083 | } |
| 1084 | rtnl_unlock(); | ||
| 1005 | kfree(net->ipv4.fib_table_hash); | 1085 | kfree(net->ipv4.fib_table_hash); |
| 1006 | } | 1086 | } |
| 1007 | 1087 | ||
