diff options
-rw-r--r-- | include/net/dst.h | 1 | ||||
-rw-r--r-- | net/ipv4/route.c | 41 |
2 files changed, 30 insertions, 12 deletions
diff --git a/include/net/dst.h b/include/net/dst.h index 0df661a0c295..baf597890064 100644 --- a/include/net/dst.h +++ b/include/net/dst.h | |||
@@ -78,6 +78,7 @@ struct dst_entry { | |||
78 | #define DST_OBSOLETE_NONE 0 | 78 | #define DST_OBSOLETE_NONE 0 |
79 | #define DST_OBSOLETE_DEAD 2 | 79 | #define DST_OBSOLETE_DEAD 2 |
80 | #define DST_OBSOLETE_FORCE_CHK -1 | 80 | #define DST_OBSOLETE_FORCE_CHK -1 |
81 | #define DST_OBSOLETE_KILL -2 | ||
81 | unsigned short header_len; /* more space at head required */ | 82 | unsigned short header_len; /* more space at head required */ |
82 | unsigned short trailer_len; /* space to reserve at tail */ | 83 | unsigned short trailer_len; /* space to reserve at tail */ |
83 | #ifdef CONFIG_IP_ROUTE_CLASSID | 84 | #ifdef CONFIG_IP_ROUTE_CLASSID |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 50d2498c9284..d52f7699c2fa 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -673,7 +673,8 @@ out_unlock: | |||
673 | return; | 673 | return; |
674 | } | 674 | } |
675 | 675 | ||
676 | static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4) | 676 | static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4, |
677 | bool kill_route) | ||
677 | { | 678 | { |
678 | __be32 new_gw = icmp_hdr(skb)->un.gateway; | 679 | __be32 new_gw = icmp_hdr(skb)->un.gateway; |
679 | __be32 old_gw = ip_hdr(skb)->saddr; | 680 | __be32 old_gw = ip_hdr(skb)->saddr; |
@@ -728,8 +729,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow | |||
728 | update_or_create_fnhe(nh, fl4->daddr, new_gw, | 729 | update_or_create_fnhe(nh, fl4->daddr, new_gw, |
729 | 0, 0); | 730 | 0, 0); |
730 | } | 731 | } |
731 | rt->rt_gateway = new_gw; | 732 | if (kill_route) |
732 | rt->rt_flags |= RTCF_REDIRECTED; | 733 | rt->dst.obsolete = DST_OBSOLETE_KILL; |
733 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | 734 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); |
734 | } | 735 | } |
735 | neigh_release(n); | 736 | neigh_release(n); |
@@ -760,7 +761,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf | |||
760 | rt = (struct rtable *) dst; | 761 | rt = (struct rtable *) dst; |
761 | 762 | ||
762 | ip_rt_build_flow_key(&fl4, sk, skb); | 763 | ip_rt_build_flow_key(&fl4, sk, skb); |
763 | __ip_do_redirect(rt, skb, &fl4); | 764 | __ip_do_redirect(rt, skb, &fl4, true); |
764 | } | 765 | } |
765 | 766 | ||
766 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) | 767 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) |
@@ -919,7 +920,7 @@ out: kfree_skb(skb); | |||
919 | return 0; | 920 | return 0; |
920 | } | 921 | } |
921 | 922 | ||
922 | static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) | 923 | static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) |
923 | { | 924 | { |
924 | struct fib_result res; | 925 | struct fib_result res; |
925 | 926 | ||
@@ -932,8 +933,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) | |||
932 | update_or_create_fnhe(nh, fl4->daddr, 0, mtu, | 933 | update_or_create_fnhe(nh, fl4->daddr, 0, mtu, |
933 | jiffies + ip_rt_mtu_expires); | 934 | jiffies + ip_rt_mtu_expires); |
934 | } | 935 | } |
935 | rt->rt_pmtu = mtu; | 936 | return mtu; |
936 | dst_set_expires(&rt->dst, ip_rt_mtu_expires); | ||
937 | } | 937 | } |
938 | 938 | ||
939 | static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, | 939 | static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, |
@@ -943,7 +943,14 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, | |||
943 | struct flowi4 fl4; | 943 | struct flowi4 fl4; |
944 | 944 | ||
945 | ip_rt_build_flow_key(&fl4, sk, skb); | 945 | ip_rt_build_flow_key(&fl4, sk, skb); |
946 | __ip_rt_update_pmtu(rt, &fl4, mtu); | 946 | mtu = __ip_rt_update_pmtu(rt, &fl4, mtu); |
947 | |||
948 | if (!rt->rt_pmtu) { | ||
949 | dst->obsolete = DST_OBSOLETE_KILL; | ||
950 | } else { | ||
951 | rt->rt_pmtu = mtu; | ||
952 | dst_set_expires(&rt->dst, ip_rt_mtu_expires); | ||
953 | } | ||
947 | } | 954 | } |
948 | 955 | ||
949 | void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, | 956 | void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, |
@@ -989,7 +996,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net, | |||
989 | RT_TOS(iph->tos), protocol, mark, flow_flags); | 996 | RT_TOS(iph->tos), protocol, mark, flow_flags); |
990 | rt = __ip_route_output_key(net, &fl4); | 997 | rt = __ip_route_output_key(net, &fl4); |
991 | if (!IS_ERR(rt)) { | 998 | if (!IS_ERR(rt)) { |
992 | __ip_do_redirect(rt, skb, &fl4); | 999 | __ip_do_redirect(rt, skb, &fl4, false); |
993 | ip_rt_put(rt); | 1000 | ip_rt_put(rt); |
994 | } | 1001 | } |
995 | } | 1002 | } |
@@ -1004,7 +1011,7 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk) | |||
1004 | __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); | 1011 | __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); |
1005 | rt = __ip_route_output_key(sock_net(sk), &fl4); | 1012 | rt = __ip_route_output_key(sock_net(sk), &fl4); |
1006 | if (!IS_ERR(rt)) { | 1013 | if (!IS_ERR(rt)) { |
1007 | __ip_do_redirect(rt, skb, &fl4); | 1014 | __ip_do_redirect(rt, skb, &fl4, false); |
1008 | ip_rt_put(rt); | 1015 | ip_rt_put(rt); |
1009 | } | 1016 | } |
1010 | } | 1017 | } |
@@ -1014,7 +1021,15 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | |||
1014 | { | 1021 | { |
1015 | struct rtable *rt = (struct rtable *) dst; | 1022 | struct rtable *rt = (struct rtable *) dst; |
1016 | 1023 | ||
1017 | if (rt_is_expired(rt)) | 1024 | /* All IPV4 dsts are created with ->obsolete set to the value |
1025 | * DST_OBSOLETE_FORCE_CHK which forces validation calls down | ||
1026 | * into this function always. | ||
1027 | * | ||
1028 | * When a PMTU/redirect information update invalidates a | ||
1029 | * route, this is indicated by setting obsolete to | ||
1030 | * DST_OBSOLETE_KILL. | ||
1031 | */ | ||
1032 | if (dst->obsolete == DST_OBSOLETE_KILL || rt_is_expired(rt)) | ||
1018 | return NULL; | 1033 | return NULL; |
1019 | return dst; | 1034 | return dst; |
1020 | } | 1035 | } |
@@ -1186,8 +1201,10 @@ restart: | |||
1186 | dst_set_expires(&rt->dst, diff); | 1201 | dst_set_expires(&rt->dst, diff); |
1187 | } | 1202 | } |
1188 | } | 1203 | } |
1189 | if (gw) | 1204 | if (gw) { |
1205 | rt->rt_flags |= RTCF_REDIRECTED; | ||
1190 | rt->rt_gateway = gw; | 1206 | rt->rt_gateway = gw; |
1207 | } | ||
1191 | fnhe->fnhe_stamp = jiffies; | 1208 | fnhe->fnhe_stamp = jiffies; |
1192 | break; | 1209 | break; |
1193 | } | 1210 | } |