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: David Howells <dhowells@redhat.com>
This commit is contained in:
@ -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)
|
|||||||
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);
|
||||||
|
|
||||||
/* pass the transport ref to error_handler to release */
|
if (skb) {
|
||||||
skb_queue_tail(&trans->error_queue, skb);
|
/* pass the transport ref to error_handler to release */
|
||||||
rxrpc_queue_work(&trans->error_handler);
|
skb_queue_tail(&trans->error_queue, skb);
|
||||||
|
rxrpc_queue_work(&trans->error_handler);
|
||||||
|
} else {
|
||||||
|
rxrpc_put_transport(trans);
|
||||||
|
}
|
||||||
_leave("");
|
_leave("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user