Commit 0010e465 authored by Timo Teras's avatar Timo Teras Committed by David S. Miller

ipv4: Update MTU to all related cache entries in ip_rt_frag_needed()

Add struct net_device parameter to ip_rt_frag_needed() and update MTU to
cache entries where ifindex is specified. This is similar to what is
already done in ip_rt_redirect().
Signed-off-by: default avatarTimo Teras <timo.teras@iki.fi>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 980c478d
...@@ -116,7 +116,7 @@ extern int __ip_route_output_key(struct net *, struct rtable **, const struct f ...@@ -116,7 +116,7 @@ extern int __ip_route_output_key(struct net *, struct rtable **, const struct f
extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags); extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin); extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu); extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
extern void ip_rt_send_redirect(struct sk_buff *skb); extern void ip_rt_send_redirect(struct sk_buff *skb);
extern unsigned inet_addr_type(struct net *net, __be32 addr); extern unsigned inet_addr_type(struct net *net, __be32 addr);
......
...@@ -691,7 +691,8 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -691,7 +691,8 @@ static void icmp_unreach(struct sk_buff *skb)
NIPQUAD(iph->daddr)); NIPQUAD(iph->daddr));
} else { } else {
info = ip_rt_frag_needed(net, iph, info = ip_rt_frag_needed(net, iph,
ntohs(icmph->un.frag.mtu)); ntohs(icmph->un.frag.mtu),
skb->dev);
if (!info) if (!info)
goto out; goto out;
} }
......
...@@ -1430,11 +1430,13 @@ static inline unsigned short guess_mtu(unsigned short old_mtu) ...@@ -1430,11 +1430,13 @@ static inline unsigned short guess_mtu(unsigned short old_mtu)
} }
unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
unsigned short new_mtu) unsigned short new_mtu,
struct net_device *dev)
{ {
int i; int i, k;
unsigned short old_mtu = ntohs(iph->tot_len); unsigned short old_mtu = ntohs(iph->tot_len);
struct rtable *rth; struct rtable *rth;
int ikeys[2] = { dev->ifindex, 0 };
__be32 skeys[2] = { iph->saddr, 0, }; __be32 skeys[2] = { iph->saddr, 0, };
__be32 daddr = iph->daddr; __be32 daddr = iph->daddr;
unsigned short est_mtu = 0; unsigned short est_mtu = 0;
...@@ -1442,22 +1444,26 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, ...@@ -1442,22 +1444,26 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
if (ipv4_config.no_pmtu_disc) if (ipv4_config.no_pmtu_disc)
return 0; return 0;
for (k = 0; k < 2; k++) {
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
unsigned hash = rt_hash(daddr, skeys[i], 0); unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]);
rcu_read_lock(); rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
rth = rcu_dereference(rth->u.dst.rt_next)) { rth = rcu_dereference(rth->u.dst.rt_next)) {
if (rth->fl.fl4_dst == daddr &&
rth->fl.fl4_src == skeys[i] &&
rth->rt_dst == daddr &&
rth->rt_src == iph->saddr &&
rth->fl.iif == 0 &&
!(dst_metric_locked(&rth->u.dst, RTAX_MTU)) &&
net_eq(dev_net(rth->u.dst.dev), net) &&
rth->rt_genid == atomic_read(&rt_genid)) {
unsigned short mtu = new_mtu; unsigned short mtu = new_mtu;
if (rth->fl.fl4_dst != daddr ||
rth->fl.fl4_src != skeys[i] ||
rth->rt_dst != daddr ||
rth->rt_src != iph->saddr ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0 ||
dst_metric_locked(&rth->u.dst, RTAX_MTU) ||
!net_eq(dev_net(rth->u.dst.dev), net) ||
rth->rt_genid != atomic_read(&rt_genid))
continue;
if (new_mtu < 68 || new_mtu >= old_mtu) { if (new_mtu < 68 || new_mtu >= old_mtu) {
/* BSD 4.2 compatibility hack :-( */ /* BSD 4.2 compatibility hack :-( */
...@@ -1483,9 +1489,9 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, ...@@ -1483,9 +1489,9 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
est_mtu = mtu; est_mtu = mtu;
} }
} }
}
rcu_read_unlock(); rcu_read_unlock();
} }
}
return est_mtu ? : new_mtu; return est_mtu ? : new_mtu;
} }
......
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