Commit 1a70c05b authored by David Howells's avatar David Howells

rxrpc: Break MTU determination from ICMP into its own function

Break MTU determination from ICMP out into its own function to reduce the
complexity of the error report handler.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent abe89ef0
...@@ -71,6 +71,45 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local, ...@@ -71,6 +71,45 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
return rxrpc_lookup_peer_rcu(local, &srx); return rxrpc_lookup_peer_rcu(local, &srx);
} }
/*
* Handle an MTU/fragmentation problem.
*/
static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, struct sock_exterr_skb *serr)
{
u32 mtu = serr->ee.ee_info;
_net("Rx ICMP Fragmentation Needed (%d)", mtu);
/* wind down the local interface MTU */
if (mtu > 0 && peer->if_mtu == 65535 && mtu < peer->if_mtu) {
peer->if_mtu = mtu;
_net("I/F MTU %u", mtu);
}
if (mtu == 0) {
/* they didn't give us a size, estimate one */
mtu = peer->if_mtu;
if (mtu > 1500) {
mtu >>= 1;
if (mtu < 1500)
mtu = 1500;
} else {
mtu -= 100;
if (mtu < peer->hdrsize)
mtu = peer->hdrsize + 4;
}
}
if (mtu < peer->mtu) {
spin_lock_bh(&peer->lock);
peer->mtu = mtu;
peer->maxdata = peer->mtu - peer->hdrsize;
spin_unlock_bh(&peer->lock);
_net("Net MTU %u (maxdata %u)",
peer->mtu, peer->maxdata);
}
}
/* /*
* handle an error received on the local endpoint * handle an error received on the local endpoint
*/ */
...@@ -126,50 +165,26 @@ void rxrpc_error_report(struct sock *sk) ...@@ -126,50 +165,26 @@ void rxrpc_error_report(struct sock *sk)
return; return;
} }
if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP && if ((serr->ee.ee_origin == SO_EE_ORIGIN_ICMP &&
serr->ee.ee_type == ICMP_DEST_UNREACH && serr->ee.ee_type == ICMP_DEST_UNREACH &&
serr->ee.ee_code == ICMP_FRAG_NEEDED serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
) { rxrpc_adjust_mtu(peer, serr);
u32 mtu = serr->ee.ee_info; rxrpc_free_skb(skb);
skb = NULL;
_net("Rx Received ICMP Fragmentation Needed (%d)", mtu); goto out;
/* wind down the local interface MTU */
if (mtu > 0 && peer->if_mtu == 65535 && mtu < peer->if_mtu) {
peer->if_mtu = mtu;
_net("I/F MTU %u", mtu);
}
if (mtu == 0) {
/* they didn't give us a size, estimate one */
mtu = peer->if_mtu;
if (mtu > 1500) {
mtu >>= 1;
if (mtu < 1500)
mtu = 1500;
} else {
mtu -= 100;
if (mtu < peer->hdrsize)
mtu = peer->hdrsize + 4;
}
}
if (mtu < peer->mtu) {
spin_lock_bh(&peer->lock);
peer->mtu = mtu;
peer->maxdata = peer->mtu - peer->hdrsize;
spin_unlock_bh(&peer->lock);
_net("Net MTU %u (maxdata %u)",
peer->mtu, peer->maxdata);
}
} }
out:
rcu_read_unlock(); rcu_read_unlock();
rxrpc_put_peer(peer); rxrpc_put_peer(peer);
if (skb) {
/* pass the transport ref to error_handler to release */ /* pass the transport ref to error_handler to release */
skb_queue_tail(&trans->error_queue, skb); skb_queue_tail(&trans->error_queue, skb);
rxrpc_queue_work(&trans->error_handler); rxrpc_queue_work(&trans->error_handler);
} else {
rxrpc_put_transport(trans);
}
_leave(""); _leave("");
} }
......
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