LZ4: try system library first, fallback to builtin
authorKirill Isakov <is-kir@ya.ru>
Tue, 20 Jul 2021 07:29:31 +0000 (13:29 +0600)
committerGuus Sliepen <guus@tinc-vpn.org>
Tue, 20 Jul 2021 17:42:15 +0000 (19:42 +0200)
doc/tinc.texi
m4/lz4.m4
src/net_packet.c

index 9921cda..e3eff86 100644 (file)
@@ -468,13 +468,18 @@ default).
 @cindex LZ4
 Another form of compression is offered using the LZ4 library.
 
-The LZ4 codec is bundled with Tinc and built-in by default as
-compression level 12.  Tinc can be linked to an external liblz4
-library by using the "--disable-lz4-builtin" configure switch.
+Tinc has support for the LZ4 compression algorithm as compression level 12.
 
-If LZ4 support is entirely disabled by passing "--disable-lz4" to the
-configure script, then the resulting binary will not work correctly
-on VPNs where LZ4 compression is used.
+By default, tinc will try to link to an external LZ4 library. If it is not
+found on your system or its version is older than r129, then tinc falls back to
+the built-in copy of the library.
+
+You can force the use of the built-in copy by passing `--enable-lz4-builtin`,
+or disable it completely with `--disable-lz4-builtin`.
+
+LZ4 support can be completely disabled with `--disable-lz4`. Note that the
+resulting binary will not work correctly on VPNs where LZ4 compression is used
+by other peers.
 
 
 @c ==================================================================
index f112885..9d79d2e 100644 (file)
--- a/m4/lz4.m4
+++ b/m4/lz4.m4
@@ -19,87 +19,58 @@ dnl  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 AC_DEFUN([tinc_LZ4], [
 
   AC_ARG_ENABLE([lz4],
-    AS_HELP_STRING([--disable-lz4], [disable all lz4 compression support])
-  )
+    AS_HELP_STRING([--disable-lz4], [disable lz4 compression support]))
 
   AC_ARG_ENABLE([lz4-builtin],
-    AS_HELP_STRING([--disable-lz4-builtin], [required to link an lz4 library])
-  )
+    AS_HELP_STRING([--disable-lz4-builtin], [do not use lz4 builtin]))
 
-  AC_ARG_WITH(lz4,
-    AS_HELP_STRING([--with-lz4=DIR], [lz4 shared library prefix (eg: /usr/local)]),
-    [lz4="$withval" CPPFLAGS="$CPPFLAGS -I$withval/include" LDFLAGS="$LDFLAGS -L$withval/lib"]
-  )
+  AS_IF([test "x$enable_lz4" != "xno"], [
+    AC_DEFINE(HAVE_LZ4, 1, [enable lz4 compression support])
 
-  AC_ARG_WITH(lz4-include,
-    AS_HELP_STRING([--with-lz4-include=DIR], [lz4 shared header directory]),
-    [lz4_include="$withval" CPPFLAGS="$CPPFLAGS -I$withval"]
-  )
-
-  AC_ARG_WITH(lz4-lib,
-    AS_HELP_STRING([--with-lz4-lib=DIR], [lz4 shared object directory]),
-    [lz4_lib="$withval" LDFLAGS="$LDFLAGS -L$withval"]
-  )
-
-  dnl Calling this early prevents autoconf lint.
-  AM_CONDITIONAL([CONFIGURE_LZ4_BUILTIN], [test "$enable_lz4_builtin" != 'no'])
-
-  AS_IF([test "$enable_lz4" != 'no' -a "$enable_lz4_builtin" != 'no' ], [
-    AC_DEFINE(HAVE_LZ4, 1, [Enable lz4 support.])
-    AC_DEFINE(HAVE_LZ4_BUILTIN, 1, [Enable lz4 builtin.])
-    AC_DEFINE(HAVE_LZ4_STATE, 1, [Enable lz4 external state features.])
-    AC_DEFINE(
-      [LZ4_compress_shim(a, b, c, d)],
-      [LZ4_compress_fast_extState(lz4_wrkmem, a, b, c, d, 0)],
-      [This is the best interface for the lz4 builtin.]
+    AC_ARG_WITH(lz4,
+      AS_HELP_STRING([--with-lz4=DIR], [lz4 shared library prefix (eg: /usr/local)]),
+      [lz4="$withval"
+       CPPFLAGS="$CPPFLAGS-I$withval/include"
+       LDFLAGS="$LDFLAGS -L$withval/lib"]
     )
-  ],[
-    AS_IF([test "$enable_lz4" != 'no'], [
-      AC_CHECK_HEADERS(lz4.h, [
-        AC_DEFINE(LZ4_H, [<lz4.h>], [Location of lz4.h])
 
-        AC_CHECK_LIB(lz4, LZ4_compress_fast_extState, [
-          LIBS="$LIBS -llz4"
-          AC_DEFINE(HAVE_LZ4, 1, [Enable lz4 compression support.])
-          AC_DEFINE(HAVE_LZ4_STATE, 1, [Enable lz4 external state features.])
-          AC_DEFINE(
-            [LZ4_compress_shim(a, b, c, d)],
-            [LZ4_compress_fast_extState(lz4_wrkmem, a, b, c, d, 0)],
-            [The lz4-r129 library interface.]
-          )
-          break
-        ])
-
-        AC_CHECK_LIB(lz4, LZ4_compress_default, [
-          LIBS="$LIBS -llz4"
-          AC_DEFINE(HAVE_LZ4, 1, [Enable lz4 compression support.])
-          AC_DEFINE(
-            [LZ4_compress_shim(a, b, c, d)],
-            [LZ4_compress_default(a, b, c, d)],
-            [The lz4-r128 library interface.]
-          )
-          break
-        ])
+    AC_ARG_WITH(lz4-include,
+      AS_HELP_STRING([--with-lz4-include=DIR], [lz4 shared header directory]),
+      [lz4_include="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval"]
+    )
 
-        AC_CHECK_LIB(lz4, LZ4_compress_limitedOutput, [
-          LIBS="$LIBS -llz4"
-          AC_DEFINE(HAVE_LZ4, 1, [Enable lz4 compression support.])
-          AC_DEFINE(
-            [LZ4_compress_shim(a, b, c, d)],
-            [LZ4_compress_limitedOutput(a, b, c, d)],
-            [The lz4-r59 library interface.]
-          )
-          AC_MSG_WARN("Using deprecated lz4-r59 interface.")
-          break
-        ])
+    AC_ARG_WITH(lz4-lib,
+      AS_HELP_STRING([--with-lz4-lib=DIR], [lz4 shared object directory]),
+      [lz4_lib="$withval"
+       LDFLAGS="$LDFLAGS -L$withval"]
+    )
 
-      ],[
-        AC_MSG_ERROR("lz4.h header file not found.")
-        break
+    dnl First we check the system copy of the library
+    AS_IF([test "x$enable_lz4_builtin" != 'xyes'], [
+      AC_CHECK_HEADERS(lz4.h, [
+        AC_CHECK_LIB(lz4, LZ4_compress_fast_extState,
+          [lz4_header='<lz4.h>'
+           LIBS="$LIBS -llz4"])
       ])
+    ])
+
+    dnl If it was not found or is too old, fallback to the built-in copy
+    AS_IF([test "x$enable_lz4_builtin" != 'xno' -a "x$lz4_header" = 'x'], [
+      lz4_header='"lib/lz4/lz4.h"'
+      lz4_builtin=1
+      AC_DEFINE(HAVE_LZ4_BUILTIN, 1, [Enable lz4 builtin.])
+    ])
 
+    dnl If the first one failed and the second one is disabled, there's nothing more we can do
+    AS_IF([test "x$lz4_header" = 'x'], [
+      AC_MSG_ERROR("lz4 library was not found and fallback to builtin is disabled.");
     ])
 
   ])
 
+  AC_DEFINE_UNQUOTED(LZ4_H, [$lz4_header], [Location of lz4.h])
+
+  AM_CONDITIONAL([CONFIGURE_LZ4_BUILTIN], [test "x$lz4_builtin" = 'x1'])
+
 ])
index b8997e5..417c74e 100644 (file)
@@ -25,6 +25,8 @@
 #ifdef HAVE_ZLIB
 #define ZLIB_CONST
 #include <zlib.h>
+#include <assert.h>
+
 #endif
 
 #ifdef HAVE_LZO
 #include LZ4_H
 #endif
 
-#ifdef HAVE_LZ4_BUILTIN
-#include "lib/lz4/lz4.h"
-#endif
-
 #include "address_cache.h"
 #include "cipher.h"
 #include "conf.h"
@@ -75,9 +73,7 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
 #ifdef HAVE_LZ4_BUILTIN
 static LZ4_stream_t lz4_stream;
 #else
-#ifdef HAVE_LZ4_STATE
 static void *lz4_state = NULL;
-#endif /* HAVE_LZ4_STATE   */
 #endif /* HAVE_LZ4_BUILTIN */
 
 static void send_udppacket(node_t *, vpn_packet_t *);
@@ -222,57 +218,61 @@ static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
        }
 }
 
-static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
-       switch(level) {
 #ifdef HAVE_LZ4
-
-       case 12:
+static length_t compress_packet_lz4(uint8_t *dest, const uint8_t *source, length_t len) {
 #ifdef HAVE_LZ4_BUILTIN
-               return LZ4_compress_fast_extState(&lz4_stream, (char *)source, (char *) dest, len, MAXSIZE, 0);
-
+       return LZ4_compress_fast_extState(&lz4_stream, (const char *) source, (char *) dest, len, MAXSIZE, 0);
 #else
-#ifdef HAVE_LZ4_STATE
-
-               /* @FIXME: Put this in a better place, and free() it too. */
-               if(lz4_state == NULL) {
-                       lz4_state = malloc(LZ4_sizeofState());
-               }
 
-               if(lz4_state == NULL) {
-                       logger(DEBUG_ALWAYS, LOG_ERR, "Failed to allocate lz4_state, error: %i", errno);
-                       return 0;
-               }
-
-               return LZ4_compress_fast_extState(lz4_state, source, dest, len, MAXSIZE, 0);
+       /* @FIXME: Put this in a better place, and free() it too. */
+       if(lz4_state == NULL) {
+               lz4_state = malloc(LZ4_sizeofState());
+       }
 
-#else
-               return LZ4_compress_shim(source, dest, len, MAXSIZE);
+       if(lz4_state == NULL) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Failed to allocate lz4_state, error: %i", errno);
+               return 0;
+       }
 
-#endif /* HAVE_LZ4_STATE   */
+       return LZ4_compress_fast_extState(lz4_state, (const char *) source, (char *) dest, len, MAXSIZE, 0);
 #endif /* HAVE_LZ4_BUILTIN */
-#endif /* HAVE_LZ4         */
+}
+#endif /* HAVE_LZ4 */
+
 #ifdef HAVE_LZO
+static length_t compress_packet_lzo(uint8_t *dest, const uint8_t *source, length_t len, int level) {
+       assert(level == 10 || level == 11);
 
-       case 11: {
-               lzo_uint lzolen = MAXSIZE;
+       lzo_uint lzolen = MAXSIZE;
+       int result;
 
-               if(lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem) == LZO_E_OK) {
-                       return lzolen;
-               } else {
-                       return 0;
-               }
+       if(level == 11) {
+               result = lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem);
+       } else { // level == 10
+               result = lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
        }
 
-       case 10: {
-               lzo_uint lzolen = MAXSIZE;
-
-               if(lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem) == LZO_E_OK) {
-                       return lzolen;
-               } else {
-                       return 0;
-               }
+       if(result == LZO_E_OK) {
+               return lzolen;
+       } else {
+               return 0;
        }
+}
+#endif
 
+static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
+       switch(level) {
+#ifdef HAVE_LZ4
+
+       case 12:
+               return compress_packet_lz4(dest, source, len);
+#endif
+
+#ifdef HAVE_LZO
+
+       case 11:
+       case 10:
+               return compress_packet_lzo(dest, source, len, level);
 #endif
 #ifdef HAVE_ZLIB