diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 105 |
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 | ||
65 | static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, | 65 | static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, |
66 | const struct in6_addr *dest); | 66 | const struct in6_addr *dest); |
67 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); | 67 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); |
68 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); | 68 | static 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 | ||
330 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) | 334 | static __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 | ||
336 | static inline int rt6_need_strict(const struct in6_addr *daddr) | 349 | static 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 | ||
733 | static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort, | 745 | static 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 | ||
896 | static 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 | |||
884 | void ip6_route_input(struct sk_buff *skb) | 906 | void 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 | ||
904 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, | 923 | static 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 | } |
1766 | out: | 1786 | out: |
@@ -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 | ||
1795 | static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, | 1815 | static 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, |