diff options
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r-- | net/ipv4/fib_frontend.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index aa00398be80e..4f0ed458c883 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.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 | 38 | ||
38 | #include <net/ip.h> | 39 | #include <net/ip.h> |
39 | #include <net/protocol.h> | 40 | #include <net/protocol.h> |
@@ -125,7 +126,7 @@ void fib_select_default(struct net *net, | |||
125 | #endif | 126 | #endif |
126 | tb = fib_get_table(net, table); | 127 | tb = fib_get_table(net, table); |
127 | if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) | 128 | if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) |
128 | tb->tb_select_default(tb, flp, res); | 129 | fib_table_select_default(tb, flp, res); |
129 | } | 130 | } |
130 | 131 | ||
131 | static void fib_flush(struct net *net) | 132 | static void fib_flush(struct net *net) |
@@ -139,7 +140,7 @@ static void fib_flush(struct net *net) | |||
139 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { | 140 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
140 | head = &net->ipv4.fib_table_hash[h]; | 141 | head = &net->ipv4.fib_table_hash[h]; |
141 | hlist_for_each_entry(tb, node, head, tb_hlist) | 142 | hlist_for_each_entry(tb, node, head, tb_hlist) |
142 | flushed += tb->tb_flush(tb); | 143 | flushed += fib_table_flush(tb); |
143 | } | 144 | } |
144 | 145 | ||
145 | if (flushed) | 146 | if (flushed) |
@@ -162,7 +163,7 @@ struct net_device * ip_dev_find(struct net *net, __be32 addr) | |||
162 | #endif | 163 | #endif |
163 | 164 | ||
164 | local_table = fib_get_table(net, RT_TABLE_LOCAL); | 165 | local_table = fib_get_table(net, RT_TABLE_LOCAL); |
165 | if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) | 166 | if (!local_table || fib_table_lookup(local_table, &fl, &res)) |
166 | return NULL; | 167 | return NULL; |
167 | if (res.type != RTN_LOCAL) | 168 | if (res.type != RTN_LOCAL) |
168 | goto out; | 169 | goto out; |
@@ -200,7 +201,7 @@ static inline unsigned __inet_dev_addr_type(struct net *net, | |||
200 | local_table = fib_get_table(net, RT_TABLE_LOCAL); | 201 | local_table = fib_get_table(net, RT_TABLE_LOCAL); |
201 | if (local_table) { | 202 | if (local_table) { |
202 | ret = RTN_UNICAST; | 203 | ret = RTN_UNICAST; |
203 | if (!local_table->tb_lookup(local_table, &fl, &res)) { | 204 | if (!fib_table_lookup(local_table, &fl, &res)) { |
204 | if (!dev || dev == res.fi->fib_dev) | 205 | if (!dev || dev == res.fi->fib_dev) |
205 | ret = res.type; | 206 | ret = res.type; |
206 | fib_res_put(&res); | 207 | fib_res_put(&res); |
@@ -241,16 +242,19 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
241 | .iif = oif }; | 242 | .iif = oif }; |
242 | 243 | ||
243 | struct fib_result res; | 244 | struct fib_result res; |
244 | int no_addr, rpf; | 245 | int no_addr, rpf, accept_local; |
245 | int ret; | 246 | int ret; |
246 | struct net *net; | 247 | struct net *net; |
247 | 248 | ||
248 | no_addr = rpf = 0; | 249 | no_addr = rpf = accept_local = 0; |
249 | rcu_read_lock(); | 250 | rcu_read_lock(); |
250 | in_dev = __in_dev_get_rcu(dev); | 251 | in_dev = __in_dev_get_rcu(dev); |
251 | if (in_dev) { | 252 | if (in_dev) { |
252 | no_addr = in_dev->ifa_list == NULL; | 253 | no_addr = in_dev->ifa_list == NULL; |
253 | rpf = IN_DEV_RPFILTER(in_dev); | 254 | rpf = IN_DEV_RPFILTER(in_dev); |
255 | accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); | ||
256 | if (mark && !IN_DEV_SRC_VMARK(in_dev)) | ||
257 | fl.mark = 0; | ||
254 | } | 258 | } |
255 | rcu_read_unlock(); | 259 | rcu_read_unlock(); |
256 | 260 | ||
@@ -260,8 +264,10 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
260 | net = dev_net(dev); | 264 | net = dev_net(dev); |
261 | if (fib_lookup(net, &fl, &res)) | 265 | if (fib_lookup(net, &fl, &res)) |
262 | goto last_resort; | 266 | goto last_resort; |
263 | if (res.type != RTN_UNICAST) | 267 | if (res.type != RTN_UNICAST) { |
264 | goto e_inval_res; | 268 | if (res.type != RTN_LOCAL || !accept_local) |
269 | goto e_inval_res; | ||
270 | } | ||
265 | *spec_dst = FIB_RES_PREFSRC(res); | 271 | *spec_dst = FIB_RES_PREFSRC(res); |
266 | fib_combine_itag(itag, &res); | 272 | fib_combine_itag(itag, &res); |
267 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 273 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
@@ -476,13 +482,13 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
476 | if (cmd == SIOCDELRT) { | 482 | if (cmd == SIOCDELRT) { |
477 | tb = fib_get_table(net, cfg.fc_table); | 483 | tb = fib_get_table(net, cfg.fc_table); |
478 | if (tb) | 484 | if (tb) |
479 | err = tb->tb_delete(tb, &cfg); | 485 | err = fib_table_delete(tb, &cfg); |
480 | else | 486 | else |
481 | err = -ESRCH; | 487 | err = -ESRCH; |
482 | } else { | 488 | } else { |
483 | tb = fib_new_table(net, cfg.fc_table); | 489 | tb = fib_new_table(net, cfg.fc_table); |
484 | if (tb) | 490 | if (tb) |
485 | err = tb->tb_insert(tb, &cfg); | 491 | err = fib_table_insert(tb, &cfg); |
486 | else | 492 | else |
487 | err = -ENOBUFS; | 493 | err = -ENOBUFS; |
488 | } | 494 | } |
@@ -597,7 +603,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *ar | |||
597 | goto errout; | 603 | goto errout; |
598 | } | 604 | } |
599 | 605 | ||
600 | err = tb->tb_delete(tb, &cfg); | 606 | err = fib_table_delete(tb, &cfg); |
601 | errout: | 607 | errout: |
602 | return err; | 608 | return err; |
603 | } | 609 | } |
@@ -619,7 +625,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *ar | |||
619 | goto errout; | 625 | goto errout; |
620 | } | 626 | } |
621 | 627 | ||
622 | err = tb->tb_insert(tb, &cfg); | 628 | err = fib_table_insert(tb, &cfg); |
623 | errout: | 629 | errout: |
624 | return err; | 630 | return err; |
625 | } | 631 | } |
@@ -650,7 +656,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
650 | if (dumped) | 656 | if (dumped) |
651 | memset(&cb->args[2], 0, sizeof(cb->args) - | 657 | memset(&cb->args[2], 0, sizeof(cb->args) - |
652 | 2 * sizeof(cb->args[0])); | 658 | 2 * sizeof(cb->args[0])); |
653 | if (tb->tb_dump(tb, skb, cb) < 0) | 659 | if (fib_table_dump(tb, skb, cb) < 0) |
654 | goto out; | 660 | goto out; |
655 | dumped = 1; | 661 | dumped = 1; |
656 | next: | 662 | next: |
@@ -704,9 +710,9 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad | |||
704 | cfg.fc_scope = RT_SCOPE_HOST; | 710 | cfg.fc_scope = RT_SCOPE_HOST; |
705 | 711 | ||
706 | if (cmd == RTM_NEWROUTE) | 712 | if (cmd == RTM_NEWROUTE) |
707 | tb->tb_insert(tb, &cfg); | 713 | fib_table_insert(tb, &cfg); |
708 | else | 714 | else |
709 | tb->tb_delete(tb, &cfg); | 715 | fib_table_delete(tb, &cfg); |
710 | } | 716 | } |
711 | 717 | ||
712 | void fib_add_ifaddr(struct in_ifaddr *ifa) | 718 | void fib_add_ifaddr(struct in_ifaddr *ifa) |
@@ -835,7 +841,7 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb ) | |||
835 | local_bh_disable(); | 841 | local_bh_disable(); |
836 | 842 | ||
837 | frn->tb_id = tb->tb_id; | 843 | frn->tb_id = tb->tb_id; |
838 | frn->err = tb->tb_lookup(tb, &fl, &res); | 844 | frn->err = fib_table_lookup(tb, &fl, &res); |
839 | 845 | ||
840 | if (!frn->err) { | 846 | if (!frn->err) { |
841 | frn->prefixlen = res.prefixlen; | 847 | frn->prefixlen = res.prefixlen; |
@@ -878,7 +884,7 @@ static void nl_fib_input(struct sk_buff *skb) | |||
878 | netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT); | 884 | netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT); |
879 | } | 885 | } |
880 | 886 | ||
881 | static int nl_fib_lookup_init(struct net *net) | 887 | static int __net_init nl_fib_lookup_init(struct net *net) |
882 | { | 888 | { |
883 | struct sock *sk; | 889 | struct sock *sk; |
884 | sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0, | 890 | sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0, |
@@ -895,11 +901,11 @@ static void nl_fib_lookup_exit(struct net *net) | |||
895 | net->ipv4.fibnl = NULL; | 901 | net->ipv4.fibnl = NULL; |
896 | } | 902 | } |
897 | 903 | ||
898 | static void fib_disable_ip(struct net_device *dev, int force) | 904 | static void fib_disable_ip(struct net_device *dev, int force, int delay) |
899 | { | 905 | { |
900 | if (fib_sync_down_dev(dev, force)) | 906 | if (fib_sync_down_dev(dev, force)) |
901 | fib_flush(dev_net(dev)); | 907 | fib_flush(dev_net(dev)); |
902 | rt_cache_flush(dev_net(dev), 0); | 908 | rt_cache_flush(dev_net(dev), delay); |
903 | arp_ifdown(dev); | 909 | arp_ifdown(dev); |
904 | } | 910 | } |
905 | 911 | ||
@@ -922,7 +928,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
922 | /* Last address was deleted from this interface. | 928 | /* Last address was deleted from this interface. |
923 | Disable IP. | 929 | Disable IP. |
924 | */ | 930 | */ |
925 | fib_disable_ip(dev, 1); | 931 | fib_disable_ip(dev, 1, 0); |
926 | } else { | 932 | } else { |
927 | rt_cache_flush(dev_net(dev), -1); | 933 | rt_cache_flush(dev_net(dev), -1); |
928 | } | 934 | } |
@@ -937,7 +943,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
937 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 943 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
938 | 944 | ||
939 | if (event == NETDEV_UNREGISTER) { | 945 | if (event == NETDEV_UNREGISTER) { |
940 | fib_disable_ip(dev, 2); | 946 | fib_disable_ip(dev, 2, -1); |
941 | return NOTIFY_DONE; | 947 | return NOTIFY_DONE; |
942 | } | 948 | } |
943 | 949 | ||
@@ -955,12 +961,15 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
955 | rt_cache_flush(dev_net(dev), -1); | 961 | rt_cache_flush(dev_net(dev), -1); |
956 | break; | 962 | break; |
957 | case NETDEV_DOWN: | 963 | case NETDEV_DOWN: |
958 | fib_disable_ip(dev, 0); | 964 | fib_disable_ip(dev, 0, 0); |
959 | break; | 965 | break; |
960 | case NETDEV_CHANGEMTU: | 966 | case NETDEV_CHANGEMTU: |
961 | case NETDEV_CHANGE: | 967 | case NETDEV_CHANGE: |
962 | rt_cache_flush(dev_net(dev), 0); | 968 | rt_cache_flush(dev_net(dev), 0); |
963 | break; | 969 | break; |
970 | case NETDEV_UNREGISTER_BATCH: | ||
971 | rt_cache_flush_batch(); | ||
972 | break; | ||
964 | } | 973 | } |
965 | return NOTIFY_DONE; | 974 | return NOTIFY_DONE; |
966 | } | 975 | } |
@@ -996,7 +1005,7 @@ fail: | |||
996 | return err; | 1005 | return err; |
997 | } | 1006 | } |
998 | 1007 | ||
999 | static void __net_exit ip_fib_net_exit(struct net *net) | 1008 | static void ip_fib_net_exit(struct net *net) |
1000 | { | 1009 | { |
1001 | unsigned int i; | 1010 | unsigned int i; |
1002 | 1011 | ||
@@ -1012,7 +1021,7 @@ static void __net_exit ip_fib_net_exit(struct net *net) | |||
1012 | head = &net->ipv4.fib_table_hash[i]; | 1021 | head = &net->ipv4.fib_table_hash[i]; |
1013 | hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) { | 1022 | hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) { |
1014 | hlist_del(node); | 1023 | hlist_del(node); |
1015 | tb->tb_flush(tb); | 1024 | fib_table_flush(tb); |
1016 | kfree(tb); | 1025 | kfree(tb); |
1017 | } | 1026 | } |
1018 | } | 1027 | } |