diff options
author | mav <mav@FreeBSD.org> | 2007-05-11 14:36:02 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2007-05-11 14:36:02 +0000 |
commit | f1c1aa5c905e5caa61868c0c4adad2c01e5269c5 (patch) | |
tree | d6de7ba14f7771dbab4838ebd952b3f925156cd9 | |
parent | 3caf7b634042d013a13de3f8552e7944b617eb69 (diff) | |
download | FreeBSD-src-f1c1aa5c905e5caa61868c0c4adad2c01e5269c5.zip FreeBSD-src-f1c1aa5c905e5caa61868c0c4adad2c01e5269c5.tar.gz |
Performance optimization of the "encryption without compression" case by
avoiding memory allocation and data copying.
Encrypting directly at the original mbuf chain.
Approved by: glebius (mentor)
-rw-r--r-- | sys/netgraph/ng_mppc.c | 173 |
1 files changed, 103 insertions, 70 deletions
diff --git a/sys/netgraph/ng_mppc.c b/sys/netgraph/ng_mppc.c index c955c78..28c362d 100644 --- a/sys/netgraph/ng_mppc.c +++ b/sys/netgraph/ng_mppc.c @@ -154,9 +154,9 @@ static ng_disconnect_t ng_mppc_disconnect; /* Helper functions */ static int ng_mppc_compress(node_p node, - struct mbuf *m, struct mbuf **resultp); + struct mbuf **datap); static int ng_mppc_decompress(node_p node, - struct mbuf *m, struct mbuf **resultp); + struct mbuf **datap); static void ng_mppc_getkey(const u_char *h, u_char *h2, int len); static void ng_mppc_updatekey(u_int32_t bits, u_char *key0, u_char *key, struct rc4_state *rc4); @@ -356,7 +356,6 @@ ng_mppc_rcvdata(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); - struct mbuf *out; int error; struct mbuf *m; @@ -368,13 +367,11 @@ ng_mppc_rcvdata(hook_p hook, item_p item) NG_FREE_ITEM(item); return (ENXIO); } - if ((error = ng_mppc_compress(node, m, &out)) != 0) { - NG_FREE_M(m); + if ((error = ng_mppc_compress(node, &m)) != 0) { NG_FREE_ITEM(item); return(error); } - NG_FREE_M(m); - NG_FWD_NEW_DATA(error, item, priv->xmit.hook, out); + NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); return (error); } @@ -385,8 +382,7 @@ ng_mppc_rcvdata(hook_p hook, item_p item) NG_FREE_ITEM(item); return (ENXIO); } - if ((error = ng_mppc_decompress(node, m, &out)) != 0) { - NG_FREE_M(m); + if ((error = ng_mppc_decompress(node, &m)) != 0) { NG_FREE_ITEM(item); if (error == EINVAL && priv->ctrlnode != 0) { struct ng_mesg *msg; @@ -401,8 +397,7 @@ ng_mppc_rcvdata(hook_p hook, item_p item) } return (error); } - NG_FREE_M(m); - NG_FWD_NEW_DATA(error, item, priv->recv.hook, out); + NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); return (error); } @@ -466,16 +461,14 @@ ng_mppc_disconnect(hook_p hook) * The original mbuf is not free'd. */ static int -ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) +ng_mppc_compress(node_p node, struct mbuf **datap) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mppc_dir *const d = &priv->xmit; - u_char *inbuf, *outbuf; - int outlen, inlen; u_int16_t header; + struct mbuf *m = *datap; /* Initialize */ - *resultp = NULL; header = d->cc; /* Always set the flushed bit in stateless mode */ @@ -484,35 +477,38 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) d->flushed = 0; } - /* Work with contiguous regions of memory */ - inlen = m->m_pkthdr.len; - MALLOC(inbuf, u_char *, inlen, M_NETGRAPH_MPPC, M_NOWAIT); - if (inbuf == NULL) - return (ENOMEM); - m_copydata(m, 0, inlen, (caddr_t)inbuf); - if ((d->cfg.bits & MPPC_BIT) != 0) - outlen = MPPC_MAX_BLOWUP(inlen); - else - outlen = MPPC_HDRLEN + inlen; - MALLOC(outbuf, u_char *, outlen, M_NETGRAPH_MPPC, M_NOWAIT); - if (outbuf == NULL) { - FREE(inbuf, M_NETGRAPH_MPPC); - return (ENOMEM); - } - - /* Compress "inbuf" into "outbuf" (if compression enabled) */ + /* Compress packet (if compression enabled) */ #ifdef NETGRAPH_MPPC_COMPRESSION if ((d->cfg.bits & MPPC_BIT) != 0) { u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; + u_char *inbuf, *outbuf; + int outlen, inlen; u_char *source, *dest; u_long sourceCnt, destCnt; int rtn; + /* Work with contiguous regions of memory. */ + inlen = m->m_pkthdr.len; + inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); + if (inbuf == NULL) { + m_freem(m); + return (ENOMEM); + } + m_copydata(m, 0, inlen, (caddr_t)inbuf); + + outlen = MPPC_MAX_BLOWUP(inlen); + outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); + if (outbuf == NULL) { + m_freem(m); + free(inbuf, M_NETGRAPH_MPPC); + return (ENOMEM); + } + /* Prepare to compress */ source = inbuf; sourceCnt = inlen; - dest = outbuf + MPPC_HDRLEN; - destCnt = outlen - MPPC_HDRLEN; + dest = outbuf; + destCnt = outlen; if ((d->cfg.bits & MPPE_STATELESS) == 0) flags |= MPPC_SAVE_HISTORY; @@ -528,22 +524,27 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) header |= MPPC_FLAG_COMPRESSED; if ((rtn & MPPC_RESTART_HISTORY) != 0) header |= MPPC_FLAG_RESTART; + + /* Replace m by the compresed one. */ + m_freem(m); + m = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); } d->flushed = (rtn & MPPC_EXPANDED) != 0 || (flags & MPPC_SAVE_HISTORY) == 0; - } -#endif - /* If we did not compress this packet, copy it to output buffer */ - if ((header & MPPC_FLAG_COMPRESSED) == 0) { - bcopy(inbuf, outbuf + MPPC_HDRLEN, inlen); - outlen = MPPC_HDRLEN + inlen; + free(inbuf, M_NETGRAPH_MPPC); + free(outbuf, M_NETGRAPH_MPPC); + + /* Check m_devget() result. */ + if (m == NULL) + return (ENOMEM); } - FREE(inbuf, M_NETGRAPH_MPPC); +#endif /* Now encrypt packet (if encryption enabled) */ #ifdef NETGRAPH_MPPC_ENCRYPTION if ((d->cfg.bits & MPPE_BITS) != 0) { + struct mbuf *m1; /* Set header bits */ header |= MPPC_FLAG_ENCRYPTED; @@ -559,9 +560,18 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); } + /* We must own the mbuf chain exclusively to modify it. */ + m = m_unshare(m, M_DONTWAIT); + if (m == NULL) + return (ENOMEM); + /* Encrypt packet */ - rc4_crypt(&d->rc4, outbuf + MPPC_HDRLEN, - outbuf + MPPC_HDRLEN, outlen - MPPC_HDRLEN); + m1 = m; + while (m1) { + rc4_crypt(&d->rc4, mtod(m1, u_char *), + mtod(m1, u_char *), m1->m_len); + m1 = m1->m_next; + } } #endif @@ -569,12 +579,12 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) MPPC_CCOUNT_INC(d->cc); /* Install header */ - *((u_int16_t *)outbuf) = htons(header); + M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); + if (m != NULL) + *(mtod(m, uint16_t *)) = htons(header); - /* Return packet in an mbuf */ - *resultp = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); - FREE(outbuf, M_NETGRAPH_MPPC); - return (*resultp == NULL ? ENOBUFS : 0); + *datap = m; + return (*datap == NULL ? ENOBUFS : 0); } /* @@ -582,28 +592,23 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) * The original mbuf is not free'd. */ static int -ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) +ng_mppc_decompress(node_p node, struct mbuf **datap) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mppc_dir *const d = &priv->recv; u_int16_t header, cc; u_int numLost; - u_char *buf; - int len; + struct mbuf *m = *datap; /* Pull off header */ - if (m->m_pkthdr.len < MPPC_HDRLEN) + if (m->m_pkthdr.len < MPPC_HDRLEN) { + m_freem(m); return (EINVAL); + } m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header); header = ntohs(header); cc = (header & MPPC_CCOUNT_MASK); - - /* Copy payload into a contiguous region of memory */ - len = m->m_pkthdr.len - MPPC_HDRLEN; - MALLOC(buf, u_char *, len, M_NETGRAPH_MPPC, M_NOWAIT); - if (buf == NULL) - return (ENOMEM); - m_copydata(m, MPPC_HDRLEN, len, (caddr_t)buf); + m_adj(m, MPPC_HDRLEN); /* Check for an unexpected jump in the sequence number */ numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); @@ -655,6 +660,9 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) /* Decrypt packet */ if ((header & MPPC_FLAG_ENCRYPTED) != 0) { +#ifdef NETGRAPH_MPPC_ENCRYPTION + struct mbuf *m1; +#endif /* Are we not expecting encryption? */ if ((d->cfg.bits & MPPE_BITS) == 0) { @@ -671,8 +679,18 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) d->cfg.startkey, d->key, &d->rc4); } + /* We must own the mbuf chain exclusively to modify it. */ + m = m_unshare(m, M_DONTWAIT); + if (m == NULL) + return (ENOMEM); + /* Decrypt packet */ - rc4_crypt(&d->rc4, buf, buf, len); + m1 = m; + while (m1 != NULL) { + rc4_crypt(&d->rc4, mtod(m1, u_char *), + mtod(m1, u_char *), m1->m_len); + m1 = m1->m_next; + } #endif } else { @@ -693,7 +711,7 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) log(LOG_ERR, "%s: rec'd unexpectedly %s packet", __func__, "compressed"); failed: - FREE(buf, M_NETGRAPH_MPPC); + m_freem(m); return (EINVAL); } @@ -704,12 +722,24 @@ failed: u_char *decompbuf, *source, *dest; u_long sourceCnt, destCnt; int decomplen, rtn; + u_char *buf; + int len; + + /* Copy payload into a contiguous region of memory. */ + len = m->m_pkthdr.len; + buf = malloc(len, M_NETGRAPH_MPPC, M_NOWAIT); + if (buf == NULL) { + m_freem(m); + return (ENOMEM); + } + m_copydata(m, 0, len, (caddr_t)buf); /* Allocate a buffer for decompressed data */ - MALLOC(decompbuf, u_char *, MPPC_DECOMP_BUFSIZE - + MPPC_DECOMP_SAFETY, M_NETGRAPH_MPPC, M_NOWAIT); + decompbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, + M_NETGRAPH_MPPC, M_NOWAIT); if (decompbuf == NULL) { - FREE(buf, M_NETGRAPH_MPPC); + m_freem(m); + free(buf, M_NETGRAPH_MPPC); return (ENOMEM); } decomplen = MPPC_DECOMP_BUFSIZE; @@ -732,21 +762,24 @@ failed: || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { log(LOG_ERR, "%s: decomp returned 0x%x", __func__, rtn); - FREE(decompbuf, M_NETGRAPH_MPPC); + free(buf, M_NETGRAPH_MPPC); + free(decompbuf, M_NETGRAPH_MPPC); goto failed; } /* Replace compressed data with decompressed data */ - FREE(buf, M_NETGRAPH_MPPC); - buf = decompbuf; + free(buf, M_NETGRAPH_MPPC); len = decomplen - destCnt; + + m_freem(m); + m = m_devget((caddr_t)decompbuf, len, 0, NULL, NULL); + free(decompbuf, M_NETGRAPH_MPPC); } #endif /* Return result in an mbuf */ - *resultp = m_devget((caddr_t)buf, len, 0, NULL, NULL); - FREE(buf, M_NETGRAPH_MPPC); - return (*resultp == NULL ? ENOBUFS : 0); + *datap = m; + return (*datap == NULL ? ENOBUFS : 0); } /* |