Skip to content

Commit

Permalink
rxrpc: Break MTU determination from ICMP into its own function
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Howells committed Jun 15, 2016
1 parent abe89ef commit 1a70c05
Showing 1 changed file with 54 additions and 39 deletions.
93 changes: 54 additions & 39 deletions net/rxrpc/peer_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,45 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
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
*/
Expand Down Expand Up @@ -126,50 +165,26 @@ void rxrpc_error_report(struct sock *sk)
return;
}

if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP &&
serr->ee.ee_type == ICMP_DEST_UNREACH &&
serr->ee.ee_code == ICMP_FRAG_NEEDED
) {
u32 mtu = serr->ee.ee_info;

_net("Rx Received 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);
}
if ((serr->ee.ee_origin == SO_EE_ORIGIN_ICMP &&
serr->ee.ee_type == ICMP_DEST_UNREACH &&
serr->ee.ee_code == ICMP_FRAG_NEEDED)) {
rxrpc_adjust_mtu(peer, serr);
rxrpc_free_skb(skb);
skb = NULL;
goto out;
}

out:
rcu_read_unlock();
rxrpc_put_peer(peer);

/* pass the transport ref to error_handler to release */
skb_queue_tail(&trans->error_queue, skb);
rxrpc_queue_work(&trans->error_handler);
if (skb) {
/* pass the transport ref to error_handler to release */
skb_queue_tail(&trans->error_queue, skb);
rxrpc_queue_work(&trans->error_handler);
} else {
rxrpc_put_transport(trans);
}
_leave("");
}

Expand Down

0 comments on commit 1a70c05

Please sign in to comment.