Skip to content

Commit

Permalink
Added support for the Snappy compression algorithm
Browse files Browse the repository at this point in the history
Added support for the Snappy compression algorithm which has shown to
have considerably better compression speed than LZO at a comparable
compression ratio.

To enable Snappy add:

  compress snappy

to both client and server config files.

Alternatively, enable compression framing on the client:

  compress

and have the server selectively push "compress snappy" to the client.

This change also extends the client capability handshake to include
IV_SNAPPY so the server can be aware that a connecting client supports
Snappy.

Note that the Snappy implementation also includes an improved framing
approach where the first byte of the compressed payload is replaced by
the compression control byte (the first payload byte is moved to the end
of the packet).  This solves off-by-one alignment issues, which improves
performance on ARM.

By default, the configure script will try to build with Snappy support.
To disable, use the --disable-snappy option.

The --enable-lzo-stub configure directive is now --enable-comp-stub
(because it's not actually "lzo" but "compression-enabled packet framing")

Add compression overhead to extra buffer unconditionally, as long
as USE_COMP is defined.

OpenVPN SVN r8206 (2.1.21a) and r8212 (2.1.21b)

Signed-off-by: Gert Doering <gert@greenie.muc.de>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <1366393268-27392-3-git-send-email-gert@greenie.muc.de>
URL: http://article.gmane.org/gmane.network.openvpn.devel/7531
Signed-off-by: Gert Doering <gert@greenie.muc.de>
  • Loading branch information
jamesyonan authored and cron2 committed May 19, 2013
1 parent a19e35a commit 38d96bd
Show file tree
Hide file tree
Showing 19 changed files with 975 additions and 403 deletions.
65 changes: 56 additions & 9 deletions configure.ac
Expand Up @@ -46,11 +46,16 @@ AC_ARG_ENABLE(
[enable_lzo="yes"]
)

AC_ARG_ENABLE(
[lzo-stub],
[AS_HELP_STRING([--enable-lzo-stub], [don't compile LZO compression support but still allow limited interoperability with LZO-enabled peers @<:@default=no@:>@])],
,
[enable_lzo_stub="no"]
AC_ARG_ENABLE(snappy,
[ --disable-snappy Disable Snappy compression support],
[enable_snappy="$enableval"],
[enable_snappy="yes"]
)

AC_ARG_ENABLE(comp-stub,
[ --enable-comp-stub Don't compile compression support but still allow limited interoperability with compression-enabled peers],
[enable_comp_stub="$enableval"],
[enable_comp_stub="no"]
)

AC_ARG_ENABLE(
Expand Down Expand Up @@ -895,6 +900,46 @@ if test "${have_lzo}" = "yes"; then
CFLAGS="${saved_CFLAGS}"
fi

dnl
dnl check for Snappy library
dnl

AC_ARG_VAR([SNAPPY_CFLAGS], [C compiler flags for snappy])
AC_ARG_VAR([SNAPPY_LIBS], [linker flags for snappy])
if test "$enable_snappy" = "yes" && test "$enable_comp_stub" = "no"; then
AC_CHECKING([for Snappy Library and Header files])
havesnappylib=1

# if SNAPPY_LIBS is set, we assume it will work, otherwise test
if test -z "${SNAPPY_LIBS}"; then
AC_CHECK_LIB(snappy, snappy_compress,
[ SNAPPY_LIBS="-lsnappy" ],
[
AC_MSG_RESULT([Snappy library not found.])
havesnappylib=0
])
fi

saved_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} ${SNAPPY_CFLAGS}"
AC_CHECK_HEADER(snappy-c.h,
,
[
AC_MSG_RESULT([Snappy headers not found.])
havesnappylib=0
])

if test $havesnappylib = 0 ; then
AC_MSG_RESULT([Snappy library available from http://code.google.com/p/snappy/])
AC_MSG_ERROR([Or try ./configure --disable-snappy OR ./configure --enable-comp-stub])
fi
OPTIONAL_SNAPPY_CFLAGS="${SNAPPY_CFLAGS}"
OPTIONAL_SNAPPY_LIBS="${SNAPPY_LIBS}"
AC_DEFINE(ENABLE_SNAPPY, 1, [Enable Snappy compression library])
CFLAGS="${saved_CFLAGS}"
fi


AC_MSG_CHECKING([git checkout])
GIT_CHECKOUT="no"
if test -n "${GIT}" -a -d "${srcdir}/.git"; then
Expand Down Expand Up @@ -1003,10 +1048,10 @@ if test "${enable_lzo}" = "yes"; then
OPTIONAL_LZO_LIBS="${LZO_LIBS}"
AC_DEFINE([ENABLE_LZO], [1], [Enable LZO compression library])
fi
if test "${enable_lzo_stub}" = "yes"; then
test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both lzo stub and lzo enabled])
AC_DEFINE([ENABLE_LZO_STUB], [1], [Enable LZO stub capability])
AC_DEFINE([ENABLE_LZO], [1], [Enable LZO compression library])
if test "${enable_comp_stub}" = "yes"; then
test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and lzo enabled (use --disable-lzo)])
test "${enable_snappy}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and snappy enabled (use --disable-snappy)])
AC_DEFINE([ENABLE_COMP_STUB], [1], [Enable compression stub capability])
fi

if test "${enable_pkcs11}" = "yes"; then
Expand Down Expand Up @@ -1060,6 +1105,8 @@ AC_SUBST([OPTIONAL_CRYPTO_CFLAGS])
AC_SUBST([OPTIONAL_CRYPTO_LIBS])
AC_SUBST([OPTIONAL_LZO_CFLAGS])
AC_SUBST([OPTIONAL_LZO_LIBS])
AC_SUBST([OPTIONAL_SNAPPY_CFLAGS])
AC_SUBST([OPTIONAL_SNAPPY_LIBS])
AC_SUBST([OPTIONAL_PKCS11_HELPER_CFLAGS])
AC_SUBST([OPTIONAL_PKCS11_HELPER_LIBS])

Expand Down
22 changes: 21 additions & 1 deletion doc/openvpn.8
Expand Up @@ -2352,12 +2352,32 @@ consecutive messages in the same category. This is useful to
limit repetitive logging of similar message types.
.\"*********************************************************
.TP
.B \-\-compress [algorithm]
Enable a compression algorithm.

The
.B algorithm
parameter may be "snappy", "lzo", or empty. Snappy and LZO
are different compression algorithms, with Snappy generally
offering the best performance.

If the
.B algorithm
parameter is empty, compression will be turned off, but the packet
framing for compression will still be enabled, allowing a different
setting to be pushed later.
.\"*********************************************************
.TP
.B \-\-comp-lzo [mode]
Use fast LZO compression \-\- may add up to 1 byte per
Use LZO compression \-\- may add up to 1 byte per
packet for incompressible data.
.B mode
may be "yes", "no", or "adaptive" (default).

This option is deprecated in favor of the newer
.B --compress
option.

In a server mode setup, it is possible to selectively turn
compression on or off for individual clients.

Expand Down
4 changes: 4 additions & 0 deletions src/openvpn/Makefile.am
Expand Up @@ -26,6 +26,7 @@ AM_CFLAGS = \
$(TAP_CFLAGS) \
$(OPTIONAL_CRYPTO_CFLAGS) \
$(OPTIONAL_LZO_CFLAGS) \
$(OPTIONAL_SNAPPY_CFLAGS) \
$(OPTIONAL_PKCS11_HELPER_CFLAGS)
if WIN32
# we want unicode entry point but not the macro
Expand All @@ -41,6 +42,7 @@ openvpn_SOURCES = \
circ_list.h \
clinat.c clinat.h \
common.h \
comp.c comp.h compstub.c \
crypto.c crypto.h crypto_backend.h \
crypto_openssl.c crypto_openssl.h \
crypto_polarssl.c crypto_polarssl.h \
Expand Down Expand Up @@ -98,6 +100,7 @@ openvpn_SOURCES = \
session_id.c session_id.h \
shaper.c shaper.h \
sig.c sig.h \
snappy.c snappy.h \
socket.c socket.h \
socks.c socks.h \
ssl.c ssl.h ssl_backend.h \
Expand All @@ -116,6 +119,7 @@ openvpn_LDADD = \
$(top_builddir)/src/compat/libcompat.la \
$(SOCKETS_LIBS) \
$(OPTIONAL_LZO_LIBS) \
$(OPTIONAL_SNAPPY_LIBS) \
$(OPTIONAL_PKCS11_HELPER_LIBS) \
$(OPTIONAL_CRYPTO_LIBS) \
$(OPTIONAL_SELINUX_LIBS) \
Expand Down
135 changes: 135 additions & 0 deletions src/openvpn/comp.c
@@ -0,0 +1,135 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif

#include "syshead.h"

#ifdef USE_COMP

#include "comp.h"
#include "error.h"
#include "otime.h"

#include "memdbg.h"

struct compress_context *
comp_init(const struct compress_options *opt)
{
struct compress_context *compctx = NULL;
switch (opt->alg)
{
case COMP_ALG_STUB:
ALLOC_OBJ_CLEAR (compctx, struct compress_context);
compctx->flags = opt->flags;
compctx->alg = comp_stub_alg;
(*compctx->alg.compress_init)(compctx);
break;
#ifdef ENABLE_LZO
case COMP_ALG_LZO:
ALLOC_OBJ_CLEAR (compctx, struct compress_context);
compctx->flags = opt->flags;
compctx->alg = lzo_alg;
(*compctx->alg.compress_init)(compctx);
break;
#endif
#ifdef ENABLE_SNAPPY
case COMP_ALG_SNAPPY:
ALLOC_OBJ_CLEAR (compctx, struct compress_context);
compctx->flags = opt->flags;
compctx->alg = snappy_alg;
(*compctx->alg.compress_init)(compctx);
break;
#endif
}
return compctx;
}

void
comp_uninit(struct compress_context *compctx)
{
if (compctx)
{
(*compctx->alg.compress_uninit)(compctx);
free(compctx);
}
}

void
comp_add_to_extra_frame(struct frame *frame)
{
/* Leave room for our one-byte compressed/didn't-compress prefix byte. */
frame_add_to_extra_frame (frame, COMP_PREFIX_LEN);
}

void
comp_add_to_extra_buffer(struct frame *frame)
{
/* Leave room for compression buffer to expand in worst case scenario
where data is totally uncompressible */
frame_add_to_extra_buffer (frame, COMP_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
}

void
comp_print_stats (const struct compress_context *compctx, struct status_output *so)
{
if (compctx)
{
status_printf (so, "pre-compress bytes," counter_format, compctx->pre_compress);
status_printf (so, "post-compress bytes," counter_format, compctx->post_compress);
status_printf (so, "pre-decompress bytes," counter_format, compctx->pre_decompress);
status_printf (so, "post-decompress bytes," counter_format, compctx->post_decompress);
}
}

/*
* Tell our peer which compression algorithms we support.
*/
void
comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out)
{
if (opt)
{
bool lzo_avail = false;
if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY))
{
#if defined(ENABLE_SNAPPY)
buf_printf (out, "IV_SNAPPY=1\n");
#endif
#if defined(ENABLE_LZO)
buf_printf (out, "IV_LZO=1\n");
lzo_avail = true;
#endif
}
if (!lzo_avail)
buf_printf (out, "IV_LZO_STUB=1\n");
buf_printf (out, "IV_COMP_STUB=1\n");
}
}

#endif /* USE_COMP */

0 comments on commit 38d96bd

Please sign in to comment.