aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/dst.h1
-rw-r--r--net/ipv4/route.c41
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
676static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4) 676static 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
766static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) 767static 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
922static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) 923static 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
939static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, 939static 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
949void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, 956void 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 }