Commit ceb33206 authored by David S. Miller's avatar David S. Miller

ipv4: Kill routes during PMTU/redirect updates.

Mark them obsolete so there will be a re-lookup to fetch the
FIB nexthop exception info.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f5b0a874
...@@ -78,6 +78,7 @@ struct dst_entry { ...@@ -78,6 +78,7 @@ struct dst_entry {
#define DST_OBSOLETE_NONE 0 #define DST_OBSOLETE_NONE 0
#define DST_OBSOLETE_DEAD 2 #define DST_OBSOLETE_DEAD 2
#define DST_OBSOLETE_FORCE_CHK -1 #define DST_OBSOLETE_FORCE_CHK -1
#define DST_OBSOLETE_KILL -2
unsigned short header_len; /* more space at head required */ unsigned short header_len; /* more space at head required */
unsigned short trailer_len; /* space to reserve at tail */ unsigned short trailer_len; /* space to reserve at tail */
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
......
...@@ -673,7 +673,8 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, ...@@ -673,7 +673,8 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
return; return;
} }
static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4) static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4,
bool kill_route)
{ {
__be32 new_gw = icmp_hdr(skb)->un.gateway; __be32 new_gw = icmp_hdr(skb)->un.gateway;
__be32 old_gw = ip_hdr(skb)->saddr; __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,8 +729,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
update_or_create_fnhe(nh, fl4->daddr, new_gw, update_or_create_fnhe(nh, fl4->daddr, new_gw,
0, 0); 0, 0);
} }
rt->rt_gateway = new_gw; if (kill_route)
rt->rt_flags |= RTCF_REDIRECTED; rt->dst.obsolete = DST_OBSOLETE_KILL;
call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
} }
neigh_release(n); neigh_release(n);
...@@ -760,7 +761,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf ...@@ -760,7 +761,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf
rt = (struct rtable *) dst; rt = (struct rtable *) dst;
ip_rt_build_flow_key(&fl4, sk, skb); ip_rt_build_flow_key(&fl4, sk, skb);
__ip_do_redirect(rt, skb, &fl4); __ip_do_redirect(rt, skb, &fl4, true);
} }
static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
...@@ -919,7 +920,7 @@ out: kfree_skb(skb); ...@@ -919,7 +920,7 @@ out: kfree_skb(skb);
return 0; return 0;
} }
static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
{ {
struct fib_result res; struct fib_result res;
...@@ -932,8 +933,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) ...@@ -932,8 +933,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
update_or_create_fnhe(nh, fl4->daddr, 0, mtu, update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
jiffies + ip_rt_mtu_expires); jiffies + ip_rt_mtu_expires);
} }
rt->rt_pmtu = mtu; return mtu;
dst_set_expires(&rt->dst, ip_rt_mtu_expires);
} }
static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, 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,7 +943,14 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
struct flowi4 fl4; struct flowi4 fl4;
ip_rt_build_flow_key(&fl4, sk, skb); ip_rt_build_flow_key(&fl4, sk, skb);
__ip_rt_update_pmtu(rt, &fl4, mtu); mtu = __ip_rt_update_pmtu(rt, &fl4, mtu);
if (!rt->rt_pmtu) {
dst->obsolete = DST_OBSOLETE_KILL;
} else {
rt->rt_pmtu = mtu;
dst_set_expires(&rt->dst, ip_rt_mtu_expires);
}
} }
void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, 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,7 +996,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net,
RT_TOS(iph->tos), protocol, mark, flow_flags); RT_TOS(iph->tos), protocol, mark, flow_flags);
rt = __ip_route_output_key(net, &fl4); rt = __ip_route_output_key(net, &fl4);
if (!IS_ERR(rt)) { if (!IS_ERR(rt)) {
__ip_do_redirect(rt, skb, &fl4); __ip_do_redirect(rt, skb, &fl4, false);
ip_rt_put(rt); ip_rt_put(rt);
} }
} }
...@@ -1004,7 +1011,7 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk) ...@@ -1004,7 +1011,7 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk)
__build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
rt = __ip_route_output_key(sock_net(sk), &fl4); rt = __ip_route_output_key(sock_net(sk), &fl4);
if (!IS_ERR(rt)) { if (!IS_ERR(rt)) {
__ip_do_redirect(rt, skb, &fl4); __ip_do_redirect(rt, skb, &fl4, false);
ip_rt_put(rt); ip_rt_put(rt);
} }
} }
...@@ -1014,7 +1021,15 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) ...@@ -1014,7 +1021,15 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
{ {
struct rtable *rt = (struct rtable *) dst; struct rtable *rt = (struct rtable *) dst;
if (rt_is_expired(rt)) /* All IPV4 dsts are created with ->obsolete set to the value
* DST_OBSOLETE_FORCE_CHK which forces validation calls down
* into this function always.
*
* When a PMTU/redirect information update invalidates a
* route, this is indicated by setting obsolete to
* DST_OBSOLETE_KILL.
*/
if (dst->obsolete == DST_OBSOLETE_KILL || rt_is_expired(rt))
return NULL; return NULL;
return dst; return dst;
} }
...@@ -1186,8 +1201,10 @@ static void rt_bind_exception(struct rtable *rt, struct fib_nh *nh, __be32 daddr ...@@ -1186,8 +1201,10 @@ static void rt_bind_exception(struct rtable *rt, struct fib_nh *nh, __be32 daddr
dst_set_expires(&rt->dst, diff); dst_set_expires(&rt->dst, diff);
} }
} }
if (gw) if (gw) {
rt->rt_flags |= RTCF_REDIRECTED;
rt->rt_gateway = gw; rt->rt_gateway = gw;
}
fnhe->fnhe_stamp = jiffies; fnhe->fnhe_stamp = jiffies;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment