diff options
author | Patrick McHardy <kaber@trash.net> | 2007-04-09 11:47:18 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-25 22:28:38 -0700 |
commit | c5c2523893747f88a83376abad310c8ad13f7197 (patch) | |
tree | 58f1ab25ac9f7ca7460abbd24e9bab9c8683f6fd /net/ipv4 | |
parent | 557922584d9c5b6b990bcfb2fec3134f0e73a05d (diff) |
[XFRM]: Optimize MTU calculation
Replace the probing based MTU estimation, which usually takes 2-3 iterations
to find a fitting value and may underestimate the MTU, by an exact calculation.
Also fix underestimation of the XFRM trailer_len, which causes unnecessary
reallocations.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/esp4.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index bdc65d8af18..a315d5d2276 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -272,32 +272,34 @@ out: return -EINVAL; } -static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) +static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) { struct esp_data *esp = x->data; u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); - int enclen = 0; + u32 align = max_t(u32, blksize, esp->conf.padlen); + u32 rem; + + mtu -= x->props.header_len + esp->auth.icv_trunc_len; + rem = mtu & (align - 1); + mtu &= ~(align - 1); switch (x->props.mode) { case XFRM_MODE_TUNNEL: - mtu = ALIGN(mtu +2, blksize); break; default: case XFRM_MODE_TRANSPORT: /* The worst case */ - mtu = ALIGN(mtu + 2, 4) + blksize - 4; + mtu -= blksize - 4; + mtu += min_t(u32, blksize - 4, rem); break; case XFRM_MODE_BEET: /* The worst case. */ - enclen = IPV4_BEET_PHMAXLEN; - mtu = ALIGN(mtu + enclen + 2, blksize); + mtu -= IPV4_BEET_PHMAXLEN; + mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem); break; } - if (esp->conf.padlen) - mtu = ALIGN(mtu, esp->conf.padlen); - - return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen; + return mtu - 2; } static void esp4_err(struct sk_buff *skb, u32 info) @@ -340,6 +342,7 @@ static int esp_init_state(struct xfrm_state *x) { struct esp_data *esp = NULL; struct crypto_blkcipher *tfm; + u32 align; /* null auth and encryption can have zero length keys */ if (x->aalg) { @@ -421,7 +424,10 @@ static int esp_init_state(struct xfrm_state *x) } } x->data = esp; - x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len; + align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); + if (esp->conf.padlen) + align = max_t(u32, align, esp->conf.padlen); + x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len; return 0; error: @@ -438,7 +444,7 @@ static struct xfrm_type esp_type = .proto = IPPROTO_ESP, .init_state = esp_init_state, .destructor = esp_destroy, - .get_max_size = esp4_get_max_size, + .get_mtu = esp4_get_mtu, .input = esp_input, .output = esp_output }; |