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, |
