diff options
Diffstat (limited to 'net/ipv4/fib_frontend.c')
| -rw-r--r-- | net/ipv4/fib_frontend.c | 188 |
1 files changed, 71 insertions, 117 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 5cd75e2dab2..92fc5f69f5d 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
| 18 | #include <asm/system.h> | ||
| 18 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
| 19 | #include <linux/capability.h> | 20 | #include <linux/capability.h> |
| 20 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| @@ -31,7 +32,6 @@ | |||
| 31 | #include <linux/if_addr.h> | 32 | #include <linux/if_addr.h> |
| 32 | #include <linux/if_arp.h> | 33 | #include <linux/if_arp.h> |
| 33 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
| 34 | #include <linux/cache.h> | ||
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/list.h> | 36 | #include <linux/list.h> |
| 37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| @@ -86,24 +86,6 @@ struct fib_table *fib_new_table(struct net *net, u32 id) | |||
| 86 | tb = fib_trie_table(id); | 86 | tb = fib_trie_table(id); |
| 87 | if (!tb) | 87 | if (!tb) |
| 88 | return NULL; | 88 | return NULL; |
| 89 | |||
| 90 | switch (id) { | ||
| 91 | case RT_TABLE_LOCAL: | ||
| 92 | net->ipv4.fib_local = tb; | ||
| 93 | break; | ||
| 94 | |||
| 95 | case RT_TABLE_MAIN: | ||
| 96 | net->ipv4.fib_main = tb; | ||
| 97 | break; | ||
| 98 | |||
| 99 | case RT_TABLE_DEFAULT: | ||
| 100 | net->ipv4.fib_default = tb; | ||
| 101 | break; | ||
| 102 | |||
| 103 | default: | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | |||
| 107 | h = id & (FIB_TABLE_HASHSZ - 1); | 89 | h = id & (FIB_TABLE_HASHSZ - 1); |
| 108 | hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); | 90 | hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); |
| 109 | return tb; | 91 | return tb; |
| @@ -148,20 +130,20 @@ static void fib_flush(struct net *net) | |||
| 148 | } | 130 | } |
| 149 | 131 | ||
| 150 | if (flushed) | 132 | if (flushed) |
| 151 | rt_cache_flush(net); | 133 | rt_cache_flush(net, -1); |
| 152 | } | 134 | } |
| 153 | 135 | ||
| 154 | /* | 136 | /* |
| 155 | * Find address type as if only "dev" was present in the system. If | 137 | * Find address type as if only "dev" was present in the system. If |
| 156 | * on_dev is NULL then all interfaces are taken into consideration. | 138 | * on_dev is NULL then all interfaces are taken into consideration. |
| 157 | */ | 139 | */ |
| 158 | static inline unsigned int __inet_dev_addr_type(struct net *net, | 140 | static inline unsigned __inet_dev_addr_type(struct net *net, |
| 159 | const struct net_device *dev, | 141 | const struct net_device *dev, |
| 160 | __be32 addr) | 142 | __be32 addr) |
| 161 | { | 143 | { |
| 162 | struct flowi4 fl4 = { .daddr = addr }; | 144 | struct flowi4 fl4 = { .daddr = addr }; |
| 163 | struct fib_result res; | 145 | struct fib_result res; |
| 164 | unsigned int ret = RTN_BROADCAST; | 146 | unsigned ret = RTN_BROADCAST; |
| 165 | struct fib_table *local_table; | 147 | struct fib_table *local_table; |
| 166 | 148 | ||
| 167 | if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) | 149 | if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) |
| @@ -169,6 +151,10 @@ static inline unsigned int __inet_dev_addr_type(struct net *net, | |||
| 169 | if (ipv4_is_multicast(addr)) | 151 | if (ipv4_is_multicast(addr)) |
| 170 | return RTN_MULTICAST; | 152 | return RTN_MULTICAST; |
| 171 | 153 | ||
| 154 | #ifdef CONFIG_IP_MULTIPLE_TABLES | ||
| 155 | res.r = NULL; | ||
| 156 | #endif | ||
| 157 | |||
| 172 | local_table = fib_get_table(net, RT_TABLE_LOCAL); | 158 | local_table = fib_get_table(net, RT_TABLE_LOCAL); |
| 173 | if (local_table) { | 159 | if (local_table) { |
| 174 | ret = RTN_UNICAST; | 160 | ret = RTN_UNICAST; |
| @@ -195,44 +181,6 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, | |||
| 195 | } | 181 | } |
| 196 | EXPORT_SYMBOL(inet_dev_addr_type); | 182 | EXPORT_SYMBOL(inet_dev_addr_type); |
| 197 | 183 | ||
| 198 | __be32 fib_compute_spec_dst(struct sk_buff *skb) | ||
| 199 | { | ||
| 200 | struct net_device *dev = skb->dev; | ||
| 201 | struct in_device *in_dev; | ||
| 202 | struct fib_result res; | ||
| 203 | struct rtable *rt; | ||
| 204 | struct flowi4 fl4; | ||
| 205 | struct net *net; | ||
| 206 | int scope; | ||
| 207 | |||
| 208 | rt = skb_rtable(skb); | ||
| 209 | if ((rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | RTCF_LOCAL)) == | ||
| 210 | RTCF_LOCAL) | ||
| 211 | return ip_hdr(skb)->daddr; | ||
| 212 | |||
| 213 | in_dev = __in_dev_get_rcu(dev); | ||
| 214 | BUG_ON(!in_dev); | ||
| 215 | |||
| 216 | net = dev_net(dev); | ||
| 217 | |||
| 218 | scope = RT_SCOPE_UNIVERSE; | ||
| 219 | if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { | ||
| 220 | fl4.flowi4_oif = 0; | ||
| 221 | fl4.flowi4_iif = LOOPBACK_IFINDEX; | ||
| 222 | fl4.daddr = ip_hdr(skb)->saddr; | ||
| 223 | fl4.saddr = 0; | ||
| 224 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); | ||
| 225 | fl4.flowi4_scope = scope; | ||
| 226 | fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; | ||
| 227 | if (!fib_lookup(net, &fl4, &res)) | ||
| 228 | return FIB_RES_PREFSRC(net, res); | ||
| 229 | } else { | ||
| 230 | scope = RT_SCOPE_LINK; | ||
| 231 | } | ||
| 232 | |||
| 233 | return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); | ||
| 234 | } | ||
| 235 | |||
| 236 | /* Given (packet source, input interface) and optional (dst, oif, tos): | 184 | /* Given (packet source, input interface) and optional (dst, oif, tos): |
| 237 | * - (main) check, that source is valid i.e. not broadcast or our local | 185 | * - (main) check, that source is valid i.e. not broadcast or our local |
| 238 | * address. | 186 | * address. |
| @@ -241,15 +189,17 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) | |||
| 241 | * - check, that packet arrived from expected physical interface. | 189 | * - check, that packet arrived from expected physical interface. |
| 242 | * called with rcu_read_lock() | 190 | * called with rcu_read_lock() |
| 243 | */ | 191 | */ |
| 244 | static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, | 192 | int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, |
| 245 | u8 tos, int oif, struct net_device *dev, | 193 | int oif, struct net_device *dev, __be32 *spec_dst, |
| 246 | int rpf, struct in_device *idev, u32 *itag) | 194 | u32 *itag) |
| 247 | { | 195 | { |
| 248 | int ret, no_addr, accept_local; | 196 | struct in_device *in_dev; |
| 249 | struct fib_result res; | ||
| 250 | struct flowi4 fl4; | 197 | struct flowi4 fl4; |
| 251 | struct net *net; | 198 | struct fib_result res; |
| 199 | int no_addr, rpf, accept_local; | ||
| 252 | bool dev_match; | 200 | bool dev_match; |
| 201 | int ret; | ||
| 202 | struct net *net; | ||
| 253 | 203 | ||
| 254 | fl4.flowi4_oif = 0; | 204 | fl4.flowi4_oif = 0; |
| 255 | fl4.flowi4_iif = oif; | 205 | fl4.flowi4_iif = oif; |
| @@ -258,10 +208,20 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, | |||
| 258 | fl4.flowi4_tos = tos; | 208 | fl4.flowi4_tos = tos; |
| 259 | fl4.flowi4_scope = RT_SCOPE_UNIVERSE; | 209 | fl4.flowi4_scope = RT_SCOPE_UNIVERSE; |
| 260 | 210 | ||
| 261 | no_addr = idev->ifa_list == NULL; | 211 | no_addr = rpf = accept_local = 0; |
| 212 | in_dev = __in_dev_get_rcu(dev); | ||
| 213 | if (in_dev) { | ||
| 214 | no_addr = in_dev->ifa_list == NULL; | ||
| 215 | |||
| 216 | /* Ignore rp_filter for packets protected by IPsec. */ | ||
| 217 | rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(in_dev); | ||
| 218 | |||
| 219 | accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); | ||
| 220 | fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; | ||
| 221 | } | ||
| 262 | 222 | ||
| 263 | accept_local = IN_DEV_ACCEPT_LOCAL(idev); | 223 | if (in_dev == NULL) |
| 264 | fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0; | 224 | goto e_inval; |
| 265 | 225 | ||
| 266 | net = dev_net(dev); | 226 | net = dev_net(dev); |
| 267 | if (fib_lookup(net, &fl4, &res)) | 227 | if (fib_lookup(net, &fl4, &res)) |
| @@ -270,6 +230,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, | |||
| 270 | if (res.type != RTN_LOCAL || !accept_local) | 230 | if (res.type != RTN_LOCAL || !accept_local) |
| 271 | goto e_inval; | 231 | goto e_inval; |
| 272 | } | 232 | } |
| 233 | *spec_dst = FIB_RES_PREFSRC(net, res); | ||
| 273 | fib_combine_itag(itag, &res); | 234 | fib_combine_itag(itag, &res); |
| 274 | dev_match = false; | 235 | dev_match = false; |
| 275 | 236 | ||
| @@ -298,14 +259,17 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, | |||
| 298 | 259 | ||
| 299 | ret = 0; | 260 | ret = 0; |
| 300 | if (fib_lookup(net, &fl4, &res) == 0) { | 261 | if (fib_lookup(net, &fl4, &res) == 0) { |
| 301 | if (res.type == RTN_UNICAST) | 262 | if (res.type == RTN_UNICAST) { |
| 263 | *spec_dst = FIB_RES_PREFSRC(net, res); | ||
| 302 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; | 264 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
| 265 | } | ||
| 303 | } | 266 | } |
| 304 | return ret; | 267 | return ret; |
| 305 | 268 | ||
| 306 | last_resort: | 269 | last_resort: |
| 307 | if (rpf) | 270 | if (rpf) |
| 308 | goto e_rpf; | 271 | goto e_rpf; |
| 272 | *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); | ||
| 309 | *itag = 0; | 273 | *itag = 0; |
| 310 | return 0; | 274 | return 0; |
| 311 | 275 | ||
| @@ -315,21 +279,6 @@ e_rpf: | |||
| 315 | return -EXDEV; | 279 | return -EXDEV; |
| 316 | } | 280 | } |
| 317 | 281 | ||
| 318 | /* Ignore rp_filter for packets protected by IPsec. */ | ||
| 319 | int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, | ||
| 320 | u8 tos, int oif, struct net_device *dev, | ||
| 321 | struct in_device *idev, u32 *itag) | ||
| 322 | { | ||
| 323 | int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); | ||
| 324 | |||
| 325 | if (!r && !fib_num_tclassid_users(dev_net(dev)) && | ||
| 326 | (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) { | ||
| 327 | *itag = 0; | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag); | ||
| 331 | } | ||
| 332 | |||
| 333 | static inline __be32 sk_extract_addr(struct sockaddr *addr) | 282 | static inline __be32 sk_extract_addr(struct sockaddr *addr) |
| 334 | { | 283 | { |
| 335 | return ((struct sockaddr_in *) addr)->sin_addr.s_addr; | 284 | return ((struct sockaddr_in *) addr)->sin_addr.s_addr; |
| @@ -488,7 +437,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
| 488 | switch (cmd) { | 437 | switch (cmd) { |
| 489 | case SIOCADDRT: /* Add a route */ | 438 | case SIOCADDRT: /* Add a route */ |
| 490 | case SIOCDELRT: /* Delete a route */ | 439 | case SIOCDELRT: /* Delete a route */ |
| 491 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 440 | if (!capable(CAP_NET_ADMIN)) |
| 492 | return -EPERM; | 441 | return -EPERM; |
| 493 | 442 | ||
| 494 | if (copy_from_user(&rt, arg, sizeof(rt))) | 443 | if (copy_from_user(&rt, arg, sizeof(rt))) |
| @@ -558,7 +507,7 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, | |||
| 558 | cfg->fc_flags = rtm->rtm_flags; | 507 | cfg->fc_flags = rtm->rtm_flags; |
| 559 | cfg->fc_nlflags = nlh->nlmsg_flags; | 508 | cfg->fc_nlflags = nlh->nlmsg_flags; |
| 560 | 509 | ||
| 561 | cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; | 510 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; |
| 562 | cfg->fc_nlinfo.nlh = nlh; | 511 | cfg->fc_nlinfo.nlh = nlh; |
| 563 | cfg->fc_nlinfo.nl_net = net; | 512 | cfg->fc_nlinfo.nl_net = net; |
| 564 | 513 | ||
| @@ -746,7 +695,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) | |||
| 746 | if (ifa->ifa_flags & IFA_F_SECONDARY) { | 695 | if (ifa->ifa_flags & IFA_F_SECONDARY) { |
| 747 | prim = inet_ifa_byprefix(in_dev, prefix, mask); | 696 | prim = inet_ifa_byprefix(in_dev, prefix, mask); |
| 748 | if (prim == NULL) { | 697 | if (prim == NULL) { |
| 749 | pr_warn("%s: bug: prim == NULL\n", __func__); | 698 | printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL\n"); |
| 750 | return; | 699 | return; |
| 751 | } | 700 | } |
| 752 | } | 701 | } |
| @@ -792,7 +741,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | |||
| 792 | #define BRD_OK 2 | 741 | #define BRD_OK 2 |
| 793 | #define BRD0_OK 4 | 742 | #define BRD0_OK 4 |
| 794 | #define BRD1_OK 8 | 743 | #define BRD1_OK 8 |
| 795 | unsigned int ok = 0; | 744 | unsigned ok = 0; |
| 796 | int subnet = 0; /* Primary network */ | 745 | int subnet = 0; /* Primary network */ |
| 797 | int gone = 1; /* Address is missing */ | 746 | int gone = 1; /* Address is missing */ |
| 798 | int same_prefsrc = 0; /* Another primary with same IP */ | 747 | int same_prefsrc = 0; /* Another primary with same IP */ |
| @@ -800,11 +749,11 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | |||
| 800 | if (ifa->ifa_flags & IFA_F_SECONDARY) { | 749 | if (ifa->ifa_flags & IFA_F_SECONDARY) { |
| 801 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); | 750 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); |
| 802 | if (prim == NULL) { | 751 | if (prim == NULL) { |
| 803 | pr_warn("%s: bug: prim == NULL\n", __func__); | 752 | printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n"); |
| 804 | return; | 753 | return; |
| 805 | } | 754 | } |
| 806 | if (iprim && iprim != prim) { | 755 | if (iprim && iprim != prim) { |
| 807 | pr_warn("%s: bug: iprim != prim\n", __func__); | 756 | printk(KERN_WARNING "fib_del_ifaddr: bug: iprim != prim\n"); |
| 808 | return; | 757 | return; |
| 809 | } | 758 | } |
| 810 | } else if (!ipv4_is_zeronet(any) && | 759 | } else if (!ipv4_is_zeronet(any) && |
| @@ -931,6 +880,10 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) | |||
| 931 | .flowi4_scope = frn->fl_scope, | 880 | .flowi4_scope = frn->fl_scope, |
| 932 | }; | 881 | }; |
| 933 | 882 | ||
| 883 | #ifdef CONFIG_IP_MULTIPLE_TABLES | ||
| 884 | res.r = NULL; | ||
| 885 | #endif | ||
| 886 | |||
| 934 | frn->err = -ENOENT; | 887 | frn->err = -ENOENT; |
| 935 | if (tb) { | 888 | if (tb) { |
| 936 | local_bh_disable(); | 889 | local_bh_disable(); |
| @@ -956,7 +909,7 @@ static void nl_fib_input(struct sk_buff *skb) | |||
| 956 | struct fib_result_nl *frn; | 909 | struct fib_result_nl *frn; |
| 957 | struct nlmsghdr *nlh; | 910 | struct nlmsghdr *nlh; |
| 958 | struct fib_table *tb; | 911 | struct fib_table *tb; |
| 959 | u32 portid; | 912 | u32 pid; |
| 960 | 913 | ||
| 961 | net = sock_net(skb->sk); | 914 | net = sock_net(skb->sk); |
| 962 | nlh = nlmsg_hdr(skb); | 915 | nlh = nlmsg_hdr(skb); |
| @@ -974,20 +927,17 @@ static void nl_fib_input(struct sk_buff *skb) | |||
| 974 | 927 | ||
| 975 | nl_fib_lookup(frn, tb); | 928 | nl_fib_lookup(frn, tb); |
| 976 | 929 | ||
| 977 | portid = NETLINK_CB(skb).portid; /* pid of sending process */ | 930 | pid = NETLINK_CB(skb).pid; /* pid of sending process */ |
| 978 | NETLINK_CB(skb).portid = 0; /* from kernel */ | 931 | NETLINK_CB(skb).pid = 0; /* from kernel */ |
| 979 | NETLINK_CB(skb).dst_group = 0; /* unicast */ | 932 | NETLINK_CB(skb).dst_group = 0; /* unicast */ |
| 980 | netlink_unicast(net->ipv4.fibnl, skb, portid, MSG_DONTWAIT); | 933 | netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT); |
| 981 | } | 934 | } |
| 982 | 935 | ||
| 983 | static int __net_init nl_fib_lookup_init(struct net *net) | 936 | static int __net_init nl_fib_lookup_init(struct net *net) |
| 984 | { | 937 | { |
| 985 | struct sock *sk; | 938 | struct sock *sk; |
| 986 | struct netlink_kernel_cfg cfg = { | 939 | sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0, |
| 987 | .input = nl_fib_input, | 940 | nl_fib_input, NULL, THIS_MODULE); |
| 988 | }; | ||
| 989 | |||
| 990 | sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg); | ||
| 991 | if (sk == NULL) | 941 | if (sk == NULL) |
| 992 | return -EAFNOSUPPORT; | 942 | return -EAFNOSUPPORT; |
| 993 | net->ipv4.fibnl = sk; | 943 | net->ipv4.fibnl = sk; |
| @@ -1000,11 +950,11 @@ static void nl_fib_lookup_exit(struct net *net) | |||
| 1000 | net->ipv4.fibnl = NULL; | 950 | net->ipv4.fibnl = NULL; |
| 1001 | } | 951 | } |
| 1002 | 952 | ||
| 1003 | static void fib_disable_ip(struct net_device *dev, int force) | 953 | static void fib_disable_ip(struct net_device *dev, int force, int delay) |
| 1004 | { | 954 | { |
| 1005 | if (fib_sync_down_dev(dev, force)) | 955 | if (fib_sync_down_dev(dev, force)) |
| 1006 | fib_flush(dev_net(dev)); | 956 | fib_flush(dev_net(dev)); |
| 1007 | rt_cache_flush(dev_net(dev)); | 957 | rt_cache_flush(dev_net(dev), delay); |
| 1008 | arp_ifdown(dev); | 958 | arp_ifdown(dev); |
| 1009 | } | 959 | } |
| 1010 | 960 | ||
| @@ -1021,7 +971,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
| 1021 | fib_sync_up(dev); | 971 | fib_sync_up(dev); |
| 1022 | #endif | 972 | #endif |
| 1023 | atomic_inc(&net->ipv4.dev_addr_genid); | 973 | atomic_inc(&net->ipv4.dev_addr_genid); |
| 1024 | rt_cache_flush(dev_net(dev)); | 974 | rt_cache_flush(dev_net(dev), -1); |
| 1025 | break; | 975 | break; |
| 1026 | case NETDEV_DOWN: | 976 | case NETDEV_DOWN: |
| 1027 | fib_del_ifaddr(ifa, NULL); | 977 | fib_del_ifaddr(ifa, NULL); |
| @@ -1030,9 +980,9 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
| 1030 | /* Last address was deleted from this interface. | 980 | /* Last address was deleted from this interface. |
| 1031 | * Disable IP. | 981 | * Disable IP. |
| 1032 | */ | 982 | */ |
| 1033 | fib_disable_ip(dev, 1); | 983 | fib_disable_ip(dev, 1, 0); |
| 1034 | } else { | 984 | } else { |
| 1035 | rt_cache_flush(dev_net(dev)); | 985 | rt_cache_flush(dev_net(dev), -1); |
| 1036 | } | 986 | } |
| 1037 | break; | 987 | break; |
| 1038 | } | 988 | } |
| @@ -1042,16 +992,16 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
| 1042 | static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) | 992 | static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) |
| 1043 | { | 993 | { |
| 1044 | struct net_device *dev = ptr; | 994 | struct net_device *dev = ptr; |
| 1045 | struct in_device *in_dev; | 995 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
| 1046 | struct net *net = dev_net(dev); | 996 | struct net *net = dev_net(dev); |
| 1047 | 997 | ||
| 1048 | if (event == NETDEV_UNREGISTER) { | 998 | if (event == NETDEV_UNREGISTER) { |
| 1049 | fib_disable_ip(dev, 2); | 999 | fib_disable_ip(dev, 2, -1); |
| 1050 | rt_flush_dev(dev); | ||
| 1051 | return NOTIFY_DONE; | 1000 | return NOTIFY_DONE; |
| 1052 | } | 1001 | } |
| 1053 | 1002 | ||
| 1054 | in_dev = __in_dev_get_rtnl(dev); | 1003 | if (!in_dev) |
| 1004 | return NOTIFY_DONE; | ||
| 1055 | 1005 | ||
| 1056 | switch (event) { | 1006 | switch (event) { |
| 1057 | case NETDEV_UP: | 1007 | case NETDEV_UP: |
| @@ -1062,14 +1012,21 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
| 1062 | fib_sync_up(dev); | 1012 | fib_sync_up(dev); |
| 1063 | #endif | 1013 | #endif |
| 1064 | atomic_inc(&net->ipv4.dev_addr_genid); | 1014 | atomic_inc(&net->ipv4.dev_addr_genid); |
| 1065 | rt_cache_flush(net); | 1015 | rt_cache_flush(dev_net(dev), -1); |
| 1066 | break; | 1016 | break; |
| 1067 | case NETDEV_DOWN: | 1017 | case NETDEV_DOWN: |
| 1068 | fib_disable_ip(dev, 0); | 1018 | fib_disable_ip(dev, 0, 0); |
| 1069 | break; | 1019 | break; |
| 1070 | case NETDEV_CHANGEMTU: | 1020 | case NETDEV_CHANGEMTU: |
| 1071 | case NETDEV_CHANGE: | 1021 | case NETDEV_CHANGE: |
| 1072 | rt_cache_flush(net); | 1022 | rt_cache_flush(dev_net(dev), 0); |
| 1023 | break; | ||
| 1024 | case NETDEV_UNREGISTER_BATCH: | ||
| 1025 | /* The batch unregister is only called on the first | ||
| 1026 | * device in the list of devices being unregistered. | ||
| 1027 | * Therefore we should not pass dev_net(dev) in here. | ||
| 1028 | */ | ||
| 1029 | rt_cache_flush_batch(NULL); | ||
| 1073 | break; | 1030 | break; |
| 1074 | } | 1031 | } |
| 1075 | return NOTIFY_DONE; | 1032 | return NOTIFY_DONE; |
| @@ -1134,9 +1091,6 @@ static int __net_init fib_net_init(struct net *net) | |||
| 1134 | { | 1091 | { |
| 1135 | int error; | 1092 | int error; |
| 1136 | 1093 | ||
| 1137 | #ifdef CONFIG_IP_ROUTE_CLASSID | ||
| 1138 | net->ipv4.fib_num_tclassid_users = 0; | ||
| 1139 | #endif | ||
| 1140 | error = ip_fib_net_init(net); | 1094 | error = ip_fib_net_init(net); |
| 1141 | if (error < 0) | 1095 | if (error < 0) |
| 1142 | goto out; | 1096 | goto out; |
