|
@@ -673,7 +673,8 @@ out_unlock:
|
|
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
|
|
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;
|
|
|
|
- rt->rt_flags |= RTCF_REDIRECTED;
|
|
|
|
|
|
+ if (kill_route)
|
|
|
|
+ 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
|
|
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);
|
|
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)
|
|
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;
|
|
|
|
- dst_set_expires(&rt->dst, ip_rt_mtu_expires);
|
|
|
|
|
|
+ return mtu;
|
|
}
|
|
}
|
|
|
|
|
|
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,
|
|
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,
|
|
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)
|
|
__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)
|
|
{
|
|
{
|
|
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 @@ restart:
|
|
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;
|
|
}
|
|
}
|