aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c105
1 files changed, 71 insertions, 34 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 496b62712fe8..bc4888d902b2 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -62,7 +62,7 @@
62#include <linux/sysctl.h> 62#include <linux/sysctl.h>
63#endif 63#endif
64 64
65static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, 65static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
66 const struct in6_addr *dest); 66 const struct in6_addr *dest);
67static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); 67static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
68static unsigned int ip6_default_advmss(const struct dst_entry *dst); 68static unsigned int ip6_default_advmss(const struct dst_entry *dst);
@@ -285,6 +285,10 @@ static void ip6_dst_destroy(struct dst_entry *dst)
285 rt->rt6i_idev = NULL; 285 rt->rt6i_idev = NULL;
286 in6_dev_put(idev); 286 in6_dev_put(idev);
287 } 287 }
288
289 if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from)
290 dst_release(dst->from);
291
288 if (peer) { 292 if (peer) {
289 rt->rt6i_peer = NULL; 293 rt->rt6i_peer = NULL;
290 inet_putpeer(peer); 294 inet_putpeer(peer);
@@ -329,8 +333,17 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
329 333
330static __inline__ int rt6_check_expired(const struct rt6_info *rt) 334static __inline__ int rt6_check_expired(const struct rt6_info *rt)
331{ 335{
332 return (rt->rt6i_flags & RTF_EXPIRES) && 336 struct rt6_info *ort = NULL;
333 time_after(jiffies, rt->dst.expires); 337
338 if (rt->rt6i_flags & RTF_EXPIRES) {
339 if (time_after(jiffies, rt->dst.expires))
340 return 1;
341 } else if (rt->dst.from) {
342 ort = (struct rt6_info *) rt->dst.from;
343 return (ort->rt6i_flags & RTF_EXPIRES) &&
344 time_after(jiffies, ort->dst.expires);
345 }
346 return 0;
334} 347}
335 348
336static inline int rt6_need_strict(const struct in6_addr *daddr) 349static inline int rt6_need_strict(const struct in6_addr *daddr)
@@ -620,12 +633,11 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
620 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); 633 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
621 634
622 if (rt) { 635 if (rt) {
623 if (!addrconf_finite_timeout(lifetime)) { 636 if (!addrconf_finite_timeout(lifetime))
624 rt->rt6i_flags &= ~RTF_EXPIRES; 637 rt6_clean_expires(rt);
625 } else { 638 else
626 rt->dst.expires = jiffies + HZ * lifetime; 639 rt6_set_expires(rt, jiffies + HZ * lifetime);
627 rt->rt6i_flags |= RTF_EXPIRES; 640
628 }
629 dst_release(&rt->dst); 641 dst_release(&rt->dst);
630 } 642 }
631 return 0; 643 return 0;
@@ -730,7 +742,7 @@ int ip6_ins_rt(struct rt6_info *rt)
730 return __ip6_ins_rt(rt, &info); 742 return __ip6_ins_rt(rt, &info);
731} 743}
732 744
733static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort, 745static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
734 const struct in6_addr *daddr, 746 const struct in6_addr *daddr,
735 const struct in6_addr *saddr) 747 const struct in6_addr *saddr)
736{ 748{
@@ -881,6 +893,16 @@ static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *
881 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags); 893 return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags);
882} 894}
883 895
896static struct dst_entry *ip6_route_input_lookup(struct net *net,
897 struct net_device *dev,
898 struct flowi6 *fl6, int flags)
899{
900 if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG)
901 flags |= RT6_LOOKUP_F_IFACE;
902
903 return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input);
904}
905
884void ip6_route_input(struct sk_buff *skb) 906void ip6_route_input(struct sk_buff *skb)
885{ 907{
886 const struct ipv6hdr *iph = ipv6_hdr(skb); 908 const struct ipv6hdr *iph = ipv6_hdr(skb);
@@ -895,10 +917,7 @@ void ip6_route_input(struct sk_buff *skb)
895 .flowi6_proto = iph->nexthdr, 917 .flowi6_proto = iph->nexthdr,
896 }; 918 };
897 919
898 if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) 920 skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
899 flags |= RT6_LOOKUP_F_IFACE;
900
901 skb_dst_set(skb, fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input));
902} 921}
903 922
904static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, 923static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
@@ -947,10 +966,10 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
947 rt->rt6i_idev = ort->rt6i_idev; 966 rt->rt6i_idev = ort->rt6i_idev;
948 if (rt->rt6i_idev) 967 if (rt->rt6i_idev)
949 in6_dev_hold(rt->rt6i_idev); 968 in6_dev_hold(rt->rt6i_idev);
950 rt->dst.expires = 0;
951 969
952 rt->rt6i_gateway = ort->rt6i_gateway; 970 rt->rt6i_gateway = ort->rt6i_gateway;
953 rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; 971 rt->rt6i_flags = ort->rt6i_flags;
972 rt6_clean_expires(rt);
954 rt->rt6i_metric = 0; 973 rt->rt6i_metric = 0;
955 974
956 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); 975 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
@@ -1012,10 +1031,9 @@ static void ip6_link_failure(struct sk_buff *skb)
1012 1031
1013 rt = (struct rt6_info *) skb_dst(skb); 1032 rt = (struct rt6_info *) skb_dst(skb);
1014 if (rt) { 1033 if (rt) {
1015 if (rt->rt6i_flags & RTF_CACHE) { 1034 if (rt->rt6i_flags & RTF_CACHE)
1016 dst_set_expires(&rt->dst, 0); 1035 rt6_update_expires(rt, 0);
1017 rt->rt6i_flags |= RTF_EXPIRES; 1036 else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
1018 } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
1019 rt->rt6i_node->fn_sernum = -1; 1037 rt->rt6i_node->fn_sernum = -1;
1020 } 1038 }
1021} 1039}
@@ -1282,9 +1300,12 @@ int ip6_route_add(struct fib6_config *cfg)
1282 } 1300 }
1283 1301
1284 rt->dst.obsolete = -1; 1302 rt->dst.obsolete = -1;
1285 rt->dst.expires = (cfg->fc_flags & RTF_EXPIRES) ? 1303
1286 jiffies + clock_t_to_jiffies(cfg->fc_expires) : 1304 if (cfg->fc_flags & RTF_EXPIRES)
1287 0; 1305 rt6_set_expires(rt, jiffies +
1306 clock_t_to_jiffies(cfg->fc_expires));
1307 else
1308 rt6_clean_expires(rt);
1288 1309
1289 if (cfg->fc_protocol == RTPROT_UNSPEC) 1310 if (cfg->fc_protocol == RTPROT_UNSPEC)
1290 cfg->fc_protocol = RTPROT_BOOT; 1311 cfg->fc_protocol = RTPROT_BOOT;
@@ -1729,8 +1750,8 @@ again:
1729 features |= RTAX_FEATURE_ALLFRAG; 1750 features |= RTAX_FEATURE_ALLFRAG;
1730 dst_metric_set(&rt->dst, RTAX_FEATURES, features); 1751 dst_metric_set(&rt->dst, RTAX_FEATURES, features);
1731 } 1752 }
1732 dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); 1753 rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1733 rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; 1754 rt->rt6i_flags |= RTF_MODIFIED;
1734 goto out; 1755 goto out;
1735 } 1756 }
1736 1757
@@ -1758,9 +1779,8 @@ again:
1758 * which is 10 mins. After 10 mins the decreased pmtu is expired 1779 * which is 10 mins. After 10 mins the decreased pmtu is expired
1759 * and detecting PMTU increase will be automatically happened. 1780 * and detecting PMTU increase will be automatically happened.
1760 */ 1781 */
1761 dst_set_expires(&nrt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); 1782 rt6_update_expires(nrt, net->ipv6.sysctl.ip6_rt_mtu_expires);
1762 nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; 1783 nrt->rt6i_flags |= RTF_DYNAMIC;
1763
1764 ip6_ins_rt(nrt); 1784 ip6_ins_rt(nrt);
1765 } 1785 }
1766out: 1786out:
@@ -1792,7 +1812,7 @@ void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *sad
1792 * Misc support functions 1812 * Misc support functions
1793 */ 1813 */
1794 1814
1795static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, 1815static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
1796 const struct in6_addr *dest) 1816 const struct in6_addr *dest)
1797{ 1817{
1798 struct net *net = dev_net(ort->dst.dev); 1818 struct net *net = dev_net(ort->dst.dev);
@@ -1812,10 +1832,14 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
1812 if (rt->rt6i_idev) 1832 if (rt->rt6i_idev)
1813 in6_dev_hold(rt->rt6i_idev); 1833 in6_dev_hold(rt->rt6i_idev);
1814 rt->dst.lastuse = jiffies; 1834 rt->dst.lastuse = jiffies;
1815 rt->dst.expires = 0;
1816 1835
1817 rt->rt6i_gateway = ort->rt6i_gateway; 1836 rt->rt6i_gateway = ort->rt6i_gateway;
1818 rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; 1837 rt->rt6i_flags = ort->rt6i_flags;
1838 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1839 (RTF_DEFAULT | RTF_ADDRCONF))
1840 rt6_set_from(rt, ort);
1841 else
1842 rt6_clean_expires(rt);
1819 rt->rt6i_metric = 0; 1843 rt->rt6i_metric = 0;
1820 1844
1821#ifdef CONFIG_IPV6_SUBTREES 1845#ifdef CONFIG_IPV6_SUBTREES
@@ -2537,7 +2561,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
2537 struct sk_buff *skb; 2561 struct sk_buff *skb;
2538 struct rtmsg *rtm; 2562 struct rtmsg *rtm;
2539 struct flowi6 fl6; 2563 struct flowi6 fl6;
2540 int err, iif = 0; 2564 int err, iif = 0, oif = 0;
2541 2565
2542 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); 2566 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
2543 if (err < 0) 2567 if (err < 0)
@@ -2564,15 +2588,29 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
2564 iif = nla_get_u32(tb[RTA_IIF]); 2588 iif = nla_get_u32(tb[RTA_IIF]);
2565 2589
2566 if (tb[RTA_OIF]) 2590 if (tb[RTA_OIF])
2567 fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]); 2591 oif = nla_get_u32(tb[RTA_OIF]);
2568 2592
2569 if (iif) { 2593 if (iif) {
2570 struct net_device *dev; 2594 struct net_device *dev;
2595 int flags = 0;
2596
2571 dev = __dev_get_by_index(net, iif); 2597 dev = __dev_get_by_index(net, iif);
2572 if (!dev) { 2598 if (!dev) {
2573 err = -ENODEV; 2599 err = -ENODEV;
2574 goto errout; 2600 goto errout;
2575 } 2601 }
2602
2603 fl6.flowi6_iif = iif;
2604
2605 if (!ipv6_addr_any(&fl6.saddr))
2606 flags |= RT6_LOOKUP_F_HAS_SADDR;
2607
2608 rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
2609 flags);
2610 } else {
2611 fl6.flowi6_oif = oif;
2612
2613 rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
2576 } 2614 }
2577 2615
2578 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 2616 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
@@ -2587,7 +2625,6 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
2587 skb_reset_mac_header(skb); 2625 skb_reset_mac_header(skb);
2588 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); 2626 skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
2589 2627
2590 rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6);
2591 skb_dst_set(skb, &rt->dst); 2628 skb_dst_set(skb, &rt->dst);
2592 2629
2593 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, 2630 err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,