|
@@ -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 new_mtu)
|
|
|
+ unsigned short new_mtu,
|
|
|
+ struct net_device *dev)
|
|
|
{
|
|
|
- int i;
|
|
|
+ int i, k;
|
|
|
unsigned short old_mtu = ntohs(iph->tot_len);
|
|
|
struct rtable *rth;
|
|
|
+ int ikeys[2] = { dev->ifindex, 0 };
|
|
|
__be32 skeys[2] = { iph->saddr, 0, };
|
|
|
__be32 daddr = iph->daddr;
|
|
|
unsigned short est_mtu = 0;
|
|
@@ -1442,22 +1444,26 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
|
|
|
if (ipv4_config.no_pmtu_disc)
|
|
|
return 0;
|
|
|
|
|
|
- for (i = 0; i < 2; i++) {
|
|
|
- unsigned hash = rt_hash(daddr, skeys[i], 0);
|
|
|
+ for (k = 0; k < 2; k++) {
|
|
|
+ for (i = 0; i < 2; i++) {
|
|
|
+ unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]);
|
|
|
|
|
|
- rcu_read_lock();
|
|
|
- for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
|
|
|
- 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)) {
|
|
|
+ rcu_read_lock();
|
|
|
+ for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
|
|
|
+ rth = rcu_dereference(rth->u.dst.rt_next)) {
|
|
|
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) {
|
|
|
|
|
|
/* BSD 4.2 compatibility hack :-( */
|
|
@@ -1483,8 +1489,8 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
|
|
|
est_mtu = mtu;
|
|
|
}
|
|
|
}
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
- rcu_read_unlock();
|
|
|
}
|
|
|
return est_mtu ? : new_mtu;
|
|
|
}
|